From eedee34c21031d909e19d5c9c545aacab11b9d8a Mon Sep 17 00:00:00 2001 From: Nikhil Thomas Date: Fri, 4 Feb 2022 18:02:19 +0530 Subject: [PATCH] Improve Operator upgrade mechanism Improve ReadyChecks for Pipelines and Triggers Add mechanism to detect upgrade scenario in reconcilers and update status with relevant messages Minor fixes to ensure TektonAddon reconciler acts more predictably Signed-off-by: Nikhil Thomas (cherry picked from commit e8f205b4860bb3368dc59ab49a6811aaef5aee2f) --- Makefile | 2 +- pkg/apis/operator/v1alpha1/const.go | 13 ++ pkg/reconciler/common/common.go | 31 +++++ .../initcontroller.go | 19 ++- .../kubernetes/tektondashboard/controller.go | 10 +- .../tektondashboard/tektondashboard.go | 28 ++--- .../kubernetes/tektoninstallerset/const.go | 26 ---- .../kubernetes/tektoninstallerset/install.go | 16 ++- .../kubernetes/tektoninstallerset/query.go | 4 +- .../tektoninstallerset/query_test.go | 30 ++--- .../kubernetes/tektonpipeline/controller.go | 7 +- .../tektonpipeline/tektonpipeline.go | 52 ++++++-- .../kubernetes/tektontrigger/controller.go | 7 +- .../kubernetes/tektontrigger/tektontrigger.go | 54 ++++++-- .../openshift/tektonaddon/controller.go | 2 +- .../openshift/tektonaddon/extension.go | 9 +- .../openshift/tektonaddon/tektonaddon.go | 117 ++++++++++++------ .../openshift/tektonconfig/common.go | 7 +- .../openshift/tektonconfig/extension/addon.go | 7 ++ pkg/reconciler/openshift/tektonconfig/rbac.go | 3 +- .../openshift/tektonpipeline/extension.go | 9 +- .../openshift/tektonpipeline/installerset.go | 15 ++- .../shared/tektonconfig/controller.go | 9 ++ .../shared/tektonconfig/pipeline/pipeline.go | 7 ++ .../shared/tektonconfig/tektonconfig.go | 60 +++++++-- .../shared/tektonconfig/trigger/trigger.go | 7 ++ test/e2e-common.sh | 18 ++- test/e2e-tests.sh | 3 +- .../e2e/common/tektonconfigdeployment_test.go | 3 +- test/resources/tektonaddons.go | 7 +- 30 files changed, 384 insertions(+), 198 deletions(-) rename pkg/reconciler/{kubernetes/initcontroller => common}/initcontroller.go (85%) delete mode 100644 pkg/reconciler/kubernetes/tektoninstallerset/const.go diff --git a/Makefile b/Makefile index 44bd5b0b0a..682946b7ec 100644 --- a/Makefile +++ b/Makefile @@ -107,7 +107,7 @@ clean-cr: | ; $(info $(M) clean CRs on $(TARGET)) @ ## Clean the CRs to the curr resolve: | $(KO) $(KUSTOMIZE) get-releases ; $(info $(M) ko resolve on $(TARGET)) @ ## Resolve config to the current cluster @ ## --load-restrictor LoadRestrictionsNone is needed in kustomize build as files which not in child tree of kustomize base are pulled @ ## https://github.com/kubernetes-sigs/kustomize/issues/766 - $Q $(KUSTOMIZE) build --load-restrictor LoadRestrictionsNone config/$(TARGET) | $(KO) resolve --push=false --oci-layout-path=$(BIN)/oci -f - + $Q $(KUSTOMIZE) build --load-restrictor LoadRestrictionsNone config/$(TARGET)/overlays/default | $(KO) resolve --push=false --oci-layout-path=$(BIN)/oci -f - .PHONY: generated generated: | vendor ; $(info $(M) update generated files) ## Update generated files diff --git a/pkg/apis/operator/v1alpha1/const.go b/pkg/apis/operator/v1alpha1/const.go index 7b3df7a41f..d8facbd6b3 100644 --- a/pkg/apis/operator/v1alpha1/const.go +++ b/pkg/apis/operator/v1alpha1/const.go @@ -33,6 +33,15 @@ const ( ApiFieldAlpha = "alpha" ApiFieldStable = "stable" + + LastAppliedHashKey = "operator.tekton.dev/last-applied-hash" + CreatedByKey = "operator.tekton.dev/created-by" + ReleaseVersionKey = "operator.tekton.dev/release-version" + ReleaseMinorVersionKey = "operator.tekton.dev/release-minor-version" + TargetNamespaceKey = "operator.tekton.dev/target-namespace" + InstallerSetType = "operator.tekton.dev/type" + + UpgradePending = "upgrade pending" ) var ( @@ -41,6 +50,10 @@ var ( // that we proceed ahead with updated object RECONCILE_AGAIN_ERR = fmt.Errorf("reconcile again and proceed") + // DEPENDENCY_UPGRADE_PENDING_ERR + // When a reconciler cannot proceed due to an upgrade in progress of a dependency + DEPENDENCY_UPGRADE_PENDING_ERR = fmt.Errorf("dependency upgrade pending") + // VERSION_ENV_NOT_SET_ERR Error when VERSION environment variable is not set VERSION_ENV_NOT_SET_ERR = fmt.Errorf("version environment variable %s is not set or empty", VersionEnvKey) ) diff --git a/pkg/reconciler/common/common.go b/pkg/reconciler/common/common.go index 8e9fa9a229..dd8fcb2784 100644 --- a/pkg/reconciler/common/common.go +++ b/pkg/reconciler/common/common.go @@ -17,6 +17,7 @@ limitations under the License. package common import ( + "context" "fmt" "time" @@ -57,6 +58,13 @@ func PipelineReady(informer informer.TektonPipelineInformer) (*v1alpha1.TektonPi } return nil, err } + upgradePending, err := CheckUpgradePending(ppln) + if err != nil { + return nil, err + } + if upgradePending { + return nil, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR + } if !ppln.Status.IsReady() { return nil, fmt.Errorf(PipelineNotReady) } @@ -76,6 +84,13 @@ func TriggerReady(informer informer.TektonTriggerInformer) (*v1alpha1.TektonTrig } return nil, err } + upgradePending, err := CheckUpgradePending(trigger) + if err != nil { + return nil, err + } + if upgradePending { + return nil, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR + } if !trigger.Status.IsReady() { return nil, fmt.Errorf(TriggerNotReady) } @@ -86,3 +101,19 @@ func getTriggerRes(informer informer.TektonTriggerInformer) (*v1alpha1.TektonTri res, err := informer.Lister().Get(TriggerResourceName) return res, err } + +func CheckUpgradePending(tc v1alpha1.TektonComponent) (bool, error) { + labels := tc.GetLabels() + ver, ok := labels[v1alpha1.ReleaseVersionKey] + if !ok { + return true, nil + } + operatorVersion, err := OperatorVersion(context.TODO()) + if err != nil { + return false, err + } + if ver != operatorVersion { + return true, nil + } + return false, nil +} diff --git a/pkg/reconciler/kubernetes/initcontroller/initcontroller.go b/pkg/reconciler/common/initcontroller.go similarity index 85% rename from pkg/reconciler/kubernetes/initcontroller/initcontroller.go rename to pkg/reconciler/common/initcontroller.go index 0994dedddf..7eb8217c8c 100644 --- a/pkg/reconciler/kubernetes/initcontroller/initcontroller.go +++ b/pkg/reconciler/common/initcontroller.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package initcontroller +package common import ( "context" @@ -26,7 +26,6 @@ import ( mfc "github.com/manifestival/client-go-client" mf "github.com/manifestival/manifestival" "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" - "github.com/tektoncd/operator/pkg/reconciler/common" "go.uber.org/zap" "knative.dev/pkg/injection" "knative.dev/pkg/logging" @@ -72,9 +71,9 @@ func (ctrl Controller) InitController(ctx context.Context, opts PayloadOptions) var releaseVersion string // Read the release version of component - releaseVersion, err = common.FetchVersionFromConfigMap(manifest, ctrl.VersionConfigMap) + releaseVersion, err = FetchVersionFromConfigMap(manifest, ctrl.VersionConfigMap) if err != nil { - if common.IsFetchVersionError(err) { + if IsFetchVersionError(err) { ctrl.Logger.Warnf("failed to read version information from ConfigMap %s", ctrl.VersionConfigMap, err) releaseVersion = "Unknown" } else { @@ -91,29 +90,29 @@ func (ctrl Controller) fetchSourceManifests(ctx context.Context, opts PayloadOpt switch { case strings.Contains(ctrl.VersionConfigMap, "pipeline"): var pipeline *v1alpha1.TektonPipeline - if err := common.AppendTarget(ctx, ctrl.Manifest, pipeline); err != nil { + if err := AppendTarget(ctx, ctrl.Manifest, pipeline); err != nil { return err } // add proxy configs to pipeline if any return addProxy(ctrl.Manifest) case strings.Contains(ctrl.VersionConfigMap, "triggers"): var trigger *v1alpha1.TektonTrigger - return common.AppendTarget(ctx, ctrl.Manifest, trigger) + return AppendTarget(ctx, ctrl.Manifest, trigger) case strings.Contains(ctrl.VersionConfigMap, "dashboard") && opts.ReadOnly: var dashboard v1alpha1.TektonDashboard dashboard.Spec.Readonly = true - return common.AppendTarget(ctx, ctrl.Manifest, &dashboard) + return AppendTarget(ctx, ctrl.Manifest, &dashboard) case strings.Contains(ctrl.VersionConfigMap, "dashboard") && !opts.ReadOnly: var dashboard v1alpha1.TektonDashboard dashboard.Spec.Readonly = false - return common.AppendTarget(ctx, ctrl.Manifest, &dashboard) + return AppendTarget(ctx, ctrl.Manifest, &dashboard) } return nil } func addProxy(manifest *mf.Manifest) error { - koDataDir := os.Getenv(common.KoEnvKey) + koDataDir := os.Getenv(KoEnvKey) proxyLocation := filepath.Join(koDataDir, "webhook") - return common.AppendManifest(manifest, proxyLocation) + return AppendManifest(manifest, proxyLocation) } diff --git a/pkg/reconciler/kubernetes/tektondashboard/controller.go b/pkg/reconciler/kubernetes/tektondashboard/controller.go index 0b00cfa2c1..f4c25b86de 100644 --- a/pkg/reconciler/kubernetes/tektondashboard/controller.go +++ b/pkg/reconciler/kubernetes/tektondashboard/controller.go @@ -19,8 +19,6 @@ package tektondashboard import ( "context" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/initcontroller" - "k8s.io/client-go/tools/cache" "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" @@ -53,16 +51,16 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro kubeClient := kubeclient.Get(ctx) logger := logging.FromContext(ctx) - ctrl := initcontroller.Controller{ + ctrl := common.Controller{ Logger: logger, VersionConfigMap: versionConfigMap, } - readonlyManifest, dashboardVer := ctrl.InitController(ctx, initcontroller.PayloadOptions{ReadOnly: true}) + readonlyManifest, dashboardVer := ctrl.InitController(ctx, common.PayloadOptions{ReadOnly: true}) - fullaccessManifest, _ := ctrl.InitController(ctx, initcontroller.PayloadOptions{ReadOnly: false}) + fullaccessManifest, _ := ctrl.InitController(ctx, common.PayloadOptions{ReadOnly: false}) - operatorVer, err := initcontroller.OperatorVersion(ctx) + operatorVer, err := common.OperatorVersion(ctx) if err != nil { logger.Fatal(err) } diff --git a/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go b/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go index 934b2a8b2b..a33dc9fb05 100644 --- a/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go +++ b/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go @@ -21,19 +21,13 @@ import ( "fmt" "time" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" - "github.com/tektoncd/operator/pkg/reconciler/shared/hash" - mf "github.com/manifestival/manifestival" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned" pipelineinformer "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1" tektondashboardreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektondashboard" "github.com/tektoncd/operator/pkg/reconciler/common" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" "github.com/tektoncd/operator/pkg/reconciler/shared/hash" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -95,7 +89,7 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton ls := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, + v1alpha1.CreatedByKey: createdByValue, }, } labelSelector, err := common.LabelSelector(ls) @@ -141,7 +135,9 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashb if err.Error() == common.PipelineNotReady { td.Status.MarkDependencyInstalling("tekton-pipelines is still installing") // wait for pipeline status to change - return fmt.Errorf(common.PipelineNotReady) + r.enqueueAfter(td, 10*time.Second) + return nil + } // (tektonpipeline.opeator.tekton.dev instance not available yet) td.Status.MarkDependencyMissing("tekton-pipelines does not exist") @@ -185,8 +181,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashb return err } - installerSetTargetNamespace := installedTIS.Annotations[tektoninstallerset.TargetNamespaceKey] - installerSetReleaseVersion := installedTIS.Annotations[tektoninstallerset.ReleaseVersionKey] + installerSetTargetNamespace := installedTIS.Annotations[v1alpha1.TargetNamespaceKey] + installerSetReleaseVersion := installedTIS.Annotations[v1alpha1.ReleaseVersionKey] // Check if TargetNamespace of existing TektonInstallerSet is same as expected // Check if Release Version in TektonInstallerSet is same as expected @@ -229,7 +225,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashb } // spec hash stored on installerSet - lastAppliedHash := installedTIS.GetAnnotations()[tektoninstallerset.LastAppliedHashKey] + lastAppliedHash := installedTIS.GetAnnotations()[v1alpha1.LastAppliedHashKey] if lastAppliedHash != expectedSpecHash { @@ -247,7 +243,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashb // Update the spec hash current := installedTIS.GetAnnotations() - current[tektoninstallerset.LastAppliedHashKey] = expectedSpecHash + current[v1alpha1.LastAppliedHashKey] = expectedSpecHash installedTIS.SetAnnotations(current) // Update the manifests @@ -364,12 +360,12 @@ func makeInstallerSet(td *v1alpha1.TektonDashboard, manifest mf.Manifest, tdSpec ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", v1alpha1.DashboardResourceName), Labels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, + v1alpha1.CreatedByKey: createdByValue, }, Annotations: map[string]string{ - tektoninstallerset.ReleaseVersionKey: releaseVersion, - tektoninstallerset.TargetNamespaceKey: td.Spec.TargetNamespace, - tektoninstallerset.LastAppliedHashKey: tdSpecHash, + v1alpha1.ReleaseVersionKey: releaseVersion, + v1alpha1.TargetNamespaceKey: td.Spec.TargetNamespace, + v1alpha1.LastAppliedHashKey: tdSpecHash, }, OwnerReferences: []metav1.OwnerReference{ownerRef}, }, diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/const.go b/pkg/reconciler/kubernetes/tektoninstallerset/const.go deleted file mode 100644 index 2bf1124691..0000000000 --- a/pkg/reconciler/kubernetes/tektoninstallerset/const.go +++ /dev/null @@ -1,26 +0,0 @@ -/* -Copyright 2021 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package tektoninstallerset - -const ( - LastAppliedHashKey = "operator.tekton.dev/last-applied-hash" - CreatedByKey = "operator.tekton.dev/created-by" - ReleaseVersionKey = "operator.tekton.dev/release-version" - ReleaseMinorVersionKey = "operator.tekton.dev/release-minor-version" - TargetNamespaceKey = "operator.tekton.dev/target-namespace" - InstallerSetType = "operator.tekton.dev/type" -) diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/install.go b/pkg/reconciler/kubernetes/tektoninstallerset/install.go index 5e016204f0..fec796a29d 100644 --- a/pkg/reconciler/kubernetes/tektoninstallerset/install.go +++ b/pkg/reconciler/kubernetes/tektoninstallerset/install.go @@ -21,7 +21,8 @@ import ( "strings" mf "github.com/manifestival/manifestival" - "github.com/tektoncd/operator/pkg/reconciler/common" + "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" + "github.com/tektoncd/operator/pkg/reconciler/shared/hash" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" @@ -31,8 +32,7 @@ import ( ) const ( - replicasForHash = 999 - lastAppliedHashKey = "operator.tekton.dev/last-applied-hash" + replicasForHash = 999 ) var ( @@ -46,7 +46,6 @@ var ( roleBindingPred = mf.ByKind("RoleBinding") clusterRolePred = mf.ByKind("ClusterRole") clusterRoleBindingPred = mf.ByKind("ClusterRoleBinding") - podSecurityPolicyPred = mf.ByKind("PodSecurityPolicy") validatingWebhookConfigurationPred = mf.ByKind("ValidatingWebhookConfiguration") mutatingWebhookConfigurationPred = mf.ByKind("MutatingWebhookConfiguration") horizontalPodAutoscalerPred = mf.ByKind("HorizontalPodAutoscaler") @@ -80,7 +79,6 @@ func (i *installer) EnsureClusterScopedResources() error { mf.Any( namespacePred, clusterRolePred, - podSecurityPolicyPred, validatingWebhookConfigurationPred, mutatingWebhookConfigurationPred, clusterInterceptorPred, @@ -140,7 +138,7 @@ func computeDeploymentHash(d appsv1.Deployment) (string, error) { // done to the deployment spec d.Spec.Replicas = ptr.Int32(replicasForHash) - return common.ComputeHashOf(d.Spec) + return hash.Compute(d.Spec) } func (i *installer) createDeployment(expected *unstructured.Unstructured) error { @@ -159,7 +157,7 @@ func (i *installer) createDeployment(expected *unstructured.Unstructured) error if len(dep.Annotations) == 0 { dep.Annotations = map[string]string{} } - dep.Annotations[lastAppliedHashKey] = hash + dep.Annotations[v1alpha1.LastAppliedHashKey] = hash unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(dep) if err != nil { @@ -188,7 +186,7 @@ func (i *installer) updateDeployment(existing *unstructured.Unstructured, existi existingDeployment.Annotations = map[string]string{} } - existingDeployment.Annotations[lastAppliedHashKey] = newHash + existingDeployment.Annotations[v1alpha1.LastAppliedHashKey] = newHash unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(existingDeployment) if err != nil { @@ -231,7 +229,7 @@ func (i *installer) ensureDeployment(expected *unstructured.Unstructured) error return fmt.Errorf("failed to compute hash of existing deployment: %v", err) } - hashFromAnnotation, hashExist := existingDeployment.Annotations[lastAppliedHashKey] + hashFromAnnotation, hashExist := existingDeployment.Annotations[v1alpha1.LastAppliedHashKey] // if hash doesn't exist then update the deployment with hash if !hashExist { diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/query.go b/pkg/reconciler/kubernetes/tektoninstallerset/query.go index 3476d19f34..b3d49b2dc0 100644 --- a/pkg/reconciler/kubernetes/tektoninstallerset/query.go +++ b/pkg/reconciler/kubernetes/tektoninstallerset/query.go @@ -64,7 +64,7 @@ func CurrentInstallerSetName(ctx context.Context, client clientset.Interface, la func CleanUpObsoleteResources(ctx context.Context, client clientset.Interface, createdBy string) error { labelSelector := labels.NewSelector() - createdReq, _ := labels.NewRequirement(CreatedByKey, selection.Equals, []string{createdBy}) + createdReq, _ := labels.NewRequirement(v1alpha1.CreatedByKey, selection.Equals, []string{createdBy}) if createdReq != nil { labelSelector = labelSelector.Add(*createdReq) } @@ -81,7 +81,7 @@ func CleanUpObsoleteResources(ctx context.Context, client clientset.Interface, c for _, i := range list.Items { // check if installerSet has InstallerSetType label // if it doesn't exist then delete it - if _, ok := i.Labels[InstallerSetType]; !ok { + if _, ok := i.Labels[v1alpha1.InstallerSetType]; !ok { err := client.OperatorV1alpha1().TektonInstallerSets().Delete(ctx, i.Name, v1.DeleteOptions{}) if err != nil { return err diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/query_test.go b/pkg/reconciler/kubernetes/tektoninstallerset/query_test.go index c577b90211..00e4d84153 100644 --- a/pkg/reconciler/kubernetes/tektoninstallerset/query_test.go +++ b/pkg/reconciler/kubernetes/tektoninstallerset/query_test.go @@ -30,14 +30,14 @@ import ( var ( pipelineLS = metav1.LabelSelector{ MatchLabels: map[string]string{ - CreatedByKey: "TektonPipeline", - InstallerSetType: "pipeline", + v1alpha1.CreatedByKey: "TektonPipeline", + v1alpha1.InstallerSetType: "pipeline", }, } triggersLS = metav1.LabelSelector{ MatchLabels: map[string]string{ - CreatedByKey: "TektonTriggers", - InstallerSetType: "triggers", + v1alpha1.CreatedByKey: "TektonTriggers", + v1alpha1.InstallerSetType: "triggers", }, } ) @@ -51,8 +51,8 @@ func TestCurrentInstallerSetName(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "pipeline", Labels: map[string]string{ - CreatedByKey: "TektonPipeline", - InstallerSetType: "pipeline", + v1alpha1.CreatedByKey: "TektonPipeline", + v1alpha1.InstallerSetType: "pipeline", }, }, }, @@ -78,8 +78,8 @@ func TestCurrentInstallerSetNameNoMatching(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "pipeline", Labels: map[string]string{ - CreatedByKey: "TektonPipeline", - InstallerSetType: "pipeline", + v1alpha1.CreatedByKey: "TektonPipeline", + v1alpha1.InstallerSetType: "pipeline", }, }, }, @@ -105,8 +105,8 @@ func TestCurrentInstallerSetNameWithDuplicates(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "pipeline-1", Labels: map[string]string{ - CreatedByKey: "TektonPipeline", - InstallerSetType: "pipeline", + v1alpha1.CreatedByKey: "TektonPipeline", + v1alpha1.InstallerSetType: "pipeline", }, }, }, @@ -114,8 +114,8 @@ func TestCurrentInstallerSetNameWithDuplicates(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "pipeline-2", Labels: map[string]string{ - CreatedByKey: "TektonPipeline", - InstallerSetType: "pipeline", + v1alpha1.CreatedByKey: "TektonPipeline", + v1alpha1.InstallerSetType: "pipeline", }, }, }, @@ -140,7 +140,7 @@ func TestCleanUpObsoleteResources(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "pipeline-1", Labels: map[string]string{ - CreatedByKey: "Abc", + v1alpha1.CreatedByKey: "Abc", }, }, }, @@ -148,8 +148,8 @@ func TestCleanUpObsoleteResources(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "pipeline-2", Labels: map[string]string{ - CreatedByKey: "Abc", - InstallerSetType: "pipeline", + v1alpha1.CreatedByKey: "Abc", + v1alpha1.InstallerSetType: "pipeline", }, }, }, diff --git a/pkg/reconciler/kubernetes/tektonpipeline/controller.go b/pkg/reconciler/kubernetes/tektonpipeline/controller.go index 2560434345..954ccf6791 100644 --- a/pkg/reconciler/kubernetes/tektonpipeline/controller.go +++ b/pkg/reconciler/kubernetes/tektonpipeline/controller.go @@ -25,7 +25,6 @@ import ( tektonPipelineInformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektonpipeline" tektonPipelineReconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektonpipeline" "github.com/tektoncd/operator/pkg/reconciler/common" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/initcontroller" "k8s.io/client-go/tools/cache" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/configmap" @@ -47,19 +46,19 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro return func(ctx context.Context, cmw configmap.Watcher) *controller.Impl { logger := logging.FromContext(ctx) - ctrl := initcontroller.Controller{ + ctrl := common.Controller{ Logger: logger, VersionConfigMap: versionConfigMap, } - manifest, pipelineVer := ctrl.InitController(ctx, initcontroller.PayloadOptions{}) + manifest, pipelineVer := ctrl.InitController(ctx, common.PayloadOptions{}) metrics, err := NewRecorder() if err != nil { logger.Errorf("Failed to create pipeline metrics recorder %v", err) } - operatorVer, err := initcontroller.OperatorVersion(ctx) + operatorVer, err := common.OperatorVersion(ctx) if err != nil { logger.Fatal(err) } diff --git a/pkg/reconciler/kubernetes/tektonpipeline/tektonpipeline.go b/pkg/reconciler/kubernetes/tektonpipeline/tektonpipeline.go index accf1c9667..0bb769b5f4 100644 --- a/pkg/reconciler/kubernetes/tektonpipeline/tektonpipeline.go +++ b/pkg/reconciler/kubernetes/tektonpipeline/tektonpipeline.go @@ -71,8 +71,8 @@ type Reconciler struct { var ( ls = metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, - tektoninstallerset.InstallerSetType: v1alpha1.PipelineResourceName, + v1alpha1.CreatedByKey: createdByValue, + v1alpha1.InstallerSetType: v1alpha1.PipelineResourceName, }, } ) @@ -131,6 +131,11 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tp *v1alpha1.TektonPipel // Pass the object through defaulting tp.SetDefaults(ctx) + // Mark TektonPipeline Instance as Not Ready if an upgrade is needed + if err := r.markUpgrade(ctx, tp); err != nil { + return err + } + if err := tektoninstallerset.CleanUpObsoleteResources(ctx, r.operatorClientSet, createdByValue); err != nil { return err } @@ -182,8 +187,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tp *v1alpha1.TektonPipel return err } - installerSetTargetNamespace := installedTIS.Annotations[tektoninstallerset.TargetNamespaceKey] - installerSetReleaseVersion := installedTIS.Labels[tektoninstallerset.ReleaseVersionKey] + installerSetTargetNamespace := installedTIS.Annotations[v1alpha1.TargetNamespaceKey] + installerSetReleaseVersion := installedTIS.Labels[v1alpha1.ReleaseVersionKey] // Check if TargetNamespace of existing TektonInstallerSet is same as expected // Check if Release Version in TektonInstallerSet is same as expected @@ -225,7 +230,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tp *v1alpha1.TektonPipel } // spec hash stored on installerSet - lastAppliedHash := installedTIS.GetAnnotations()[tektoninstallerset.LastAppliedHashKey] + lastAppliedHash := installedTIS.GetAnnotations()[v1alpha1.LastAppliedHashKey] if lastAppliedHash != expectedSpecHash { manifest := r.manifest @@ -236,7 +241,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tp *v1alpha1.TektonPipel // Update the spec hash current := installedTIS.GetAnnotations() - current[tektoninstallerset.LastAppliedHashKey] = expectedSpecHash + current[v1alpha1.LastAppliedHashKey] = expectedSpecHash installedTIS.SetAnnotations(current) // Update the manifests @@ -348,13 +353,13 @@ func (r *Reconciler) makeInstallerSet(tp *v1alpha1.TektonPipeline, manifest mf.M ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", common.PipelineResourceName), Labels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, - tektoninstallerset.InstallerSetType: v1alpha1.PipelineResourceName, - tektoninstallerset.ReleaseVersionKey: r.operatorVersion, + v1alpha1.CreatedByKey: createdByValue, + v1alpha1.InstallerSetType: v1alpha1.PipelineResourceName, + v1alpha1.ReleaseVersionKey: r.operatorVersion, }, Annotations: map[string]string{ - tektoninstallerset.TargetNamespaceKey: tp.Spec.TargetNamespace, - tektoninstallerset.LastAppliedHashKey: tpSpecHash, + v1alpha1.TargetNamespaceKey: tp.Spec.TargetNamespace, + v1alpha1.LastAppliedHashKey: tpSpecHash, }, OwnerReferences: []metav1.OwnerReference{ownerRef}, }, @@ -391,3 +396,28 @@ func (m *Recorder) logMetrics(status, version string, logger *zap.SugaredLogger) logger.Warnf("Failed to log the metrics : %v", err) } } + +func (r *Reconciler) markUpgrade(ctx context.Context, tp *v1alpha1.TektonPipeline) error { + labels := tp.GetLabels() + ver, ok := labels[v1alpha1.ReleaseVersionKey] + if ok && ver == r.operatorVersion { + return nil + } + if ok && ver != r.operatorVersion { + tp.Status.MarkInstallerSetNotReady(v1alpha1.UpgradePending) + tp.Status.MarkPreReconcilerFailed(v1alpha1.UpgradePending) + tp.Status.MarkPostReconcilerFailed(v1alpha1.UpgradePending) + tp.Status.MarkNotReady(v1alpha1.UpgradePending) + } + if labels == nil { + labels = map[string]string{} + } + labels[v1alpha1.ReleaseVersionKey] = r.operatorVersion + tp.SetLabels(labels) + + if _, err := r.operatorClientSet.OperatorV1alpha1().TektonPipelines().Update(ctx, + tp, v1.UpdateOptions{}); err != nil { + return err + } + return v1alpha1.RECONCILE_AGAIN_ERR +} diff --git a/pkg/reconciler/kubernetes/tektontrigger/controller.go b/pkg/reconciler/kubernetes/tektontrigger/controller.go index 71f3845dd5..a8cf3c025d 100644 --- a/pkg/reconciler/kubernetes/tektontrigger/controller.go +++ b/pkg/reconciler/kubernetes/tektontrigger/controller.go @@ -19,7 +19,6 @@ package tektontrigger import ( "context" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/initcontroller" kubeclient "knative.dev/pkg/client/injection/kube/client" tektonInstallerinformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektoninstallerset" @@ -50,19 +49,19 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro return func(ctx context.Context, cmw configmap.Watcher) *controller.Impl { logger := logging.FromContext(ctx) - ctrl := initcontroller.Controller{ + ctrl := common.Controller{ Logger: logger, VersionConfigMap: versionConfigMap, } - manifest, triggersVer := ctrl.InitController(ctx, initcontroller.PayloadOptions{}) + manifest, triggersVer := ctrl.InitController(ctx, common.PayloadOptions{}) metrics, err := NewRecorder() if err != nil { logger.Errorf("Failed to create trigger metrics recorder %v", err) } - operatorVer, err := initcontroller.OperatorVersion(ctx) + operatorVer, err := common.OperatorVersion(ctx) if err != nil { logger.Fatal(err) } diff --git a/pkg/reconciler/kubernetes/tektontrigger/tektontrigger.go b/pkg/reconciler/kubernetes/tektontrigger/tektontrigger.go index 828a150a12..591a565650 100644 --- a/pkg/reconciler/kubernetes/tektontrigger/tektontrigger.go +++ b/pkg/reconciler/kubernetes/tektontrigger/tektontrigger.go @@ -72,8 +72,8 @@ type Reconciler struct { var ( ls = metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, - tektoninstallerset.InstallerSetType: v1alpha1.TriggerResourceName, + v1alpha1.CreatedByKey: createdByValue, + v1alpha1.InstallerSetType: v1alpha1.TriggerResourceName, }, } ) @@ -135,7 +135,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonTrigg if err.Error() == common.PipelineNotReady { tt.Status.MarkDependencyInstalling("tekton-pipelines is still installing") // wait for pipeline status to change - return fmt.Errorf(common.PipelineNotReady) + r.enqueueAfter(tt, 10*time.Second) + return nil } // (tektonpipeline.operator.tekton.dev instance not available yet) tt.Status.MarkDependencyMissing("tekton-pipelines does not exist") @@ -145,6 +146,10 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonTrigg // Pass the object through defaulting tt.SetDefaults(ctx) + // Mark TektonTrigger Instance as Not Ready if an upgrade is needed + if err := r.markUpgrade(ctx, tt); err != nil { + return err + } if err := tektoninstallerset.CleanUpObsoleteResources(ctx, r.operatorClientSet, createdByValue); err != nil { return err @@ -198,8 +203,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonTrigg return err } - installerSetTargetNamespace := installedTIS.Annotations[tektoninstallerset.TargetNamespaceKey] - installerSetReleaseVersion := installedTIS.Labels[tektoninstallerset.ReleaseVersionKey] + installerSetTargetNamespace := installedTIS.Annotations[v1alpha1.TargetNamespaceKey] + installerSetReleaseVersion := installedTIS.Labels[v1alpha1.ReleaseVersionKey] // Check if TargetNamespace of existing TektonInstallerSet is same as expected // Check if Release Version in TektonInstallerSet is same as expected @@ -243,7 +248,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonTrigg } // spec hash stored on installerSet - lastAppliedHash := installedTIS.GetAnnotations()[tektoninstallerset.LastAppliedHashKey] + lastAppliedHash := installedTIS.GetAnnotations()[v1alpha1.LastAppliedHashKey] if lastAppliedHash != expectedSpecHash { @@ -255,7 +260,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonTrigg // Update the spec hash current := installedTIS.GetAnnotations() - current[tektoninstallerset.LastAppliedHashKey] = expectedSpecHash + current[v1alpha1.LastAppliedHashKey] = expectedSpecHash installedTIS.SetAnnotations(current) // Update the manifests @@ -389,13 +394,13 @@ func makeInstallerSet(tt *v1alpha1.TektonTrigger, manifest mf.Manifest, ttSpecHa ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", common.TriggerResourceName), Labels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, - tektoninstallerset.ReleaseVersionKey: releaseVersion, - tektoninstallerset.InstallerSetType: v1alpha1.TriggerResourceName, + v1alpha1.CreatedByKey: createdByValue, + v1alpha1.ReleaseVersionKey: releaseVersion, + v1alpha1.InstallerSetType: v1alpha1.TriggerResourceName, }, Annotations: map[string]string{ - tektoninstallerset.TargetNamespaceKey: tt.Spec.TargetNamespace, - tektoninstallerset.LastAppliedHashKey: ttSpecHash, + v1alpha1.TargetNamespaceKey: tt.Spec.TargetNamespace, + v1alpha1.LastAppliedHashKey: ttSpecHash, }, OwnerReferences: []metav1.OwnerReference{ownerRef}, }, @@ -411,3 +416,28 @@ func (m *Recorder) logMetrics(status, version string, logger *zap.SugaredLogger) logger.Warnf("Failed to log the metrics : %v", err) } } + +func (r *Reconciler) markUpgrade(ctx context.Context, tt *v1alpha1.TektonTrigger) error { + labels := tt.GetLabels() + ver, ok := labels[v1alpha1.ReleaseVersionKey] + if ok && ver == r.operatorVersion { + return nil + } + if ok && ver != r.operatorVersion { + tt.Status.MarkInstallerSetNotReady(v1alpha1.UpgradePending) + tt.Status.MarkPreReconcilerFailed(v1alpha1.UpgradePending) + tt.Status.MarkPostReconcilerFailed(v1alpha1.UpgradePending) + tt.Status.MarkNotReady(v1alpha1.UpgradePending) + } + if labels == nil { + labels = map[string]string{} + } + labels[v1alpha1.ReleaseVersionKey] = r.operatorVersion + tt.SetLabels(labels) + + if _, err := r.operatorClientSet.OperatorV1alpha1().TektonTriggers().Update(ctx, + tt, v1.UpdateOptions{}); err != nil { + return err + } + return v1alpha1.RECONCILE_AGAIN_ERR +} diff --git a/pkg/reconciler/openshift/tektonaddon/controller.go b/pkg/reconciler/openshift/tektonaddon/controller.go index 26794dfc82..8744d4a9a4 100644 --- a/pkg/reconciler/openshift/tektonaddon/controller.go +++ b/pkg/reconciler/openshift/tektonaddon/controller.go @@ -75,7 +75,7 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro pipelineInformer: tektonPipelineinformer.Get(ctx), triggerInformer: tektonTriggerinformer.Get(ctx), manifest: manifest, - version: version, + operatorVersion: version, } impl := tektonAddonreconciler.NewImpl(ctx, c) diff --git a/pkg/reconciler/openshift/tektonaddon/extension.go b/pkg/reconciler/openshift/tektonaddon/extension.go index 7d779780cb..33bb264672 100644 --- a/pkg/reconciler/openshift/tektonaddon/extension.go +++ b/pkg/reconciler/openshift/tektonaddon/extension.go @@ -31,7 +31,6 @@ import ( "github.com/tektoncd/operator/pkg/client/clientset/versioned" operatorclient "github.com/tektoncd/operator/pkg/client/injection/client" "github.com/tektoncd/operator/pkg/reconciler/common" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -88,7 +87,7 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te miscellaneousLS := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.InstallerSetType: MiscellaneousResourcesInstallerSet, + v1alpha1.InstallerSetType: MiscellaneousResourcesInstallerSet, }, } miscellaneousLabelSelector, err := common.LabelSelector(miscellaneousLS) @@ -140,7 +139,7 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te } // spec hash stored on installerSet - lastAppliedHash := installedTIS.Items[0].GetAnnotations()[tektoninstallerset.LastAppliedHashKey] + lastAppliedHash := installedTIS.Items[0].GetAnnotations()[v1alpha1.LastAppliedHashKey] if lastAppliedHash != expectedSpecHash { @@ -151,7 +150,7 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te // Update the spec hash current := installedTIS.Items[0].GetAnnotations() - current[tektoninstallerset.LastAppliedHashKey] = expectedSpecHash + current[v1alpha1.LastAppliedHashKey] = expectedSpecHash installedTIS.Items[0].SetAnnotations(current) // Update the manifests @@ -187,7 +186,7 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te consoleCLILS := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.InstallerSetType: ConsoleCLIInstallerSet, + v1alpha1.InstallerSetType: ConsoleCLIInstallerSet, }, } consoleCLILabelSelector, err := common.LabelSelector(consoleCLILS) diff --git a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go index b324a2c59e..1dd277aa81 100644 --- a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go +++ b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go @@ -53,7 +53,7 @@ type Reconciler struct { pipelineInformer informer.TektonPipelineInformer triggerInformer informer.TektonTriggerInformer - version string + operatorVersion string } const ( @@ -119,6 +119,14 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon return nil } + // Pass the object through defaulting + ta.SetDefaults(ctx) + + // Mark TektonAddon Instance as Not Ready if an upgrade is needed + if err := r.markUpgrade(ctx, ta); err != nil { + return err + } + // Make sure TektonPipeline & TektonTrigger is installed before proceeding with // TektonAddons @@ -126,7 +134,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon if err.Error() == common.PipelineNotReady { ta.Status.MarkDependencyInstalling("tekton-pipelines is still installing") // wait for pipeline status to change - return fmt.Errorf(common.PipelineNotReady) + r.enqueueAfter(ta, 10*time.Second) + return nil } // (tektonpipeline.operator.tekton.dev instance not available yet) ta.Status.MarkDependencyMissing("tekton-pipelines does not exist") @@ -137,7 +146,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon if err.Error() == common.TriggerNotReady { ta.Status.MarkDependencyInstalling("tekton-triggers is still installing") // wait for trigger status to change - return fmt.Errorf(common.TriggerNotReady) + r.enqueueAfter(ta, 10*time.Second) + return nil } // (tektontrigger.operator.tekton.dev instance not available yet) ta.Status.MarkDependencyMissing("tekton-triggers does not exist") @@ -146,9 +156,6 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon ta.Status.MarkDependenciesInstalled() - // Pass the object through defaulting - ta.SetDefaults(ctx) - if err := tektoninstallerset.CleanUpObsoleteResources(ctx, r.operatorClientSet, CreatedByValue); err != nil { return err } @@ -173,7 +180,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon // with their manifest clusterTaskLS := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.InstallerSetType: ClusterTaskInstallerSet, + v1alpha1.InstallerSetType: ClusterTaskInstallerSet, }, } clusterTaskLabelSelector, err := common.LabelSelector(clusterTaskLS) @@ -183,12 +190,14 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon if ctVal == "true" { - exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, clusterTaskLabelSelector) + exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.operatorVersion, clusterTaskLabelSelector) if err != nil { return err } if !exist { + msg := fmt.Sprintf("%s being created/upgraded", ClusterTaskInstallerSet) + ta.Status.MarkInstallerSetNotReady(msg) return r.ensureClusterTasks(ctx, ta) } } else { @@ -207,8 +216,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon // with the versioned clustertask manifest versionedClusterTaskLS := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.InstallerSetType: VersionedClusterTaskInstallerSet, - tektoninstallerset.ReleaseMinorVersionKey: getPatchVersionTrimmed(r.version), + v1alpha1.InstallerSetType: VersionedClusterTaskInstallerSet, + v1alpha1.ReleaseMinorVersionKey: getPatchVersionTrimmed(r.operatorVersion), }, } versionedClusterTaskLabelSelector, err := common.LabelSelector(versionedClusterTaskLS) @@ -218,12 +227,14 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon if ctVal == "true" { // here pass two labels one for type and other for minor release version to remove the previous minor release installerset only not all - exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, versionedClusterTaskLabelSelector) + exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.operatorVersion, versionedClusterTaskLabelSelector) if err != nil { return err } if !exist { + msg := fmt.Sprintf("%s being created/upgraded", VersionedClusterTaskInstallerSet) + ta.Status.MarkInstallerSetNotReady(msg) return r.ensureVersionedClusterTasks(ctx, ta) } } else { @@ -236,8 +247,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon // here pass two labels one for type and other for operator release version to get the latest installerset of current version vClusterTaskLS := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.InstallerSetType: VersionedClusterTaskInstallerSet, - tektoninstallerset.ReleaseVersionKey: r.version, + v1alpha1.InstallerSetType: VersionedClusterTaskInstallerSet, + v1alpha1.ReleaseVersionKey: r.operatorVersion, }, } vClusterTaskLabelSelector, err := common.LabelSelector(vClusterTaskLS) @@ -253,7 +264,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon // with their manifest pipelineTemplateLS := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.InstallerSetType: PipelinesTemplateInstallerSet, + v1alpha1.InstallerSetType: PipelinesTemplateInstallerSet, }, } pipelineTemplateLSLabelSelector, err := common.LabelSelector(pipelineTemplateLS) @@ -262,11 +273,13 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon } if ptVal == "true" { - exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, pipelineTemplateLSLabelSelector) + exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.operatorVersion, pipelineTemplateLSLabelSelector) if err != nil { return err } if !exist { + msg := fmt.Sprintf("%s being created/upgraded", PipelinesTemplateInstallerSet) + ta.Status.MarkInstallerSetNotReady(msg) return r.ensurePipelineTemplates(ctx, ta) } } else { @@ -284,18 +297,20 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon // Ensure Triggers resources triggerResourceLS := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.InstallerSetType: TriggersResourcesInstallerSet, + v1alpha1.InstallerSetType: TriggersResourcesInstallerSet, }, } triggerResourceLabelSelector, err := common.LabelSelector(triggerResourceLS) if err != nil { return err } - exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, triggerResourceLabelSelector) + exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.operatorVersion, triggerResourceLabelSelector) if err != nil { return err } if !exist { + msg := fmt.Sprintf("%s being created/upgraded", TriggersResourcesInstallerSet) + ta.Status.MarkInstallerSetNotReady(msg) return r.ensureTriggerResources(ctx, ta) } @@ -318,7 +333,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon ta.Status.MarkPostReconcilerComplete() - ta.Status.SetVersion(r.version) + ta.Status.SetVersion(r.operatorVersion) return nil } @@ -359,7 +374,7 @@ func (r *Reconciler) ensureTriggerResources(ctx context.Context, ta *v1alpha1.Te return err } - if err := createInstallerSet(ctx, r.operatorClientSet, ta, triggerResourcesManifest, r.version, + if err := createInstallerSet(ctx, r.operatorClientSet, ta, triggerResourcesManifest, r.operatorVersion, TriggersResourcesInstallerSet, "addon-triggers"); err != nil { return err } @@ -385,7 +400,7 @@ func (r *Reconciler) ensurePipelineTemplates(ctx context.Context, ta *v1alpha1.T return err } - if err := createInstallerSet(ctx, r.operatorClientSet, ta, pipelineTemplateManifest, r.version, + if err := createInstallerSet(ctx, r.operatorClientSet, ta, pipelineTemplateManifest, r.operatorVersion, PipelinesTemplateInstallerSet, "addon-pipelines"); err != nil { return err } @@ -406,7 +421,7 @@ func (r *Reconciler) ensureClusterTasks(ctx context.Context, ta *v1alpha1.Tekton } clusterTaskManifest = clusterTaskManifest.Filter( - mf.Not(byContains(getFormattedVersion(r.version))), + mf.Not(byContains(getFormattedVersion(r.operatorVersion))), ) communityClusterTaskManifest := r.manifest @@ -422,7 +437,7 @@ func (r *Reconciler) ensureClusterTasks(ctx context.Context, ta *v1alpha1.Tekton } if err := createInstallerSet(ctx, r.operatorClientSet, ta, clusterTaskManifest, - r.version, ClusterTaskInstallerSet, "addon-clustertasks"); err != nil { + r.operatorVersion, ClusterTaskInstallerSet, "addon-clustertasks"); err != nil { return err } @@ -442,11 +457,11 @@ func (r *Reconciler) ensureVersionedClusterTasks(ctx context.Context, ta *v1alph } clusterTaskManifest = clusterTaskManifest.Filter( - byContains(getFormattedVersion(r.version)), + byContains(getFormattedVersion(r.operatorVersion)), ) if err := createInstallerSet(ctx, r.operatorClientSet, ta, clusterTaskManifest, - r.version, VersionedClusterTaskInstallerSet, "addon-versioned-clustertasks"); err != nil { + r.operatorVersion, VersionedClusterTaskInstallerSet, "addon-versioned-clustertasks"); err != nil { return err } @@ -464,15 +479,16 @@ func checkIfInstallerSetExist(ctx context.Context, oc clientset.Interface, relVe LabelSelector: labelSelector, }) if err != nil { - if errors.IsNotFound(err) { - return false, nil - } return false, err } + if len(installerSets.Items) == 0 { + return false, nil + } + if len(installerSets.Items) == 1 { // if already created then check which version it is - version, ok := installerSets.Items[0].Labels[tektoninstallerset.ReleaseVersionKey] + version, ok := installerSets.Items[0].Labels[v1alpha1.ReleaseVersionKey] if ok && version == relVersion { // if installer set already exist and release version is same // then ignore and move on @@ -490,7 +506,7 @@ func checkIfInstallerSetExist(ctx context.Context, oc clientset.Interface, relVe return false, err } - return false, nil + return false, v1alpha1.RECONCILE_AGAIN_ERR } func createInstallerSet(ctx context.Context, oc clientset.Interface, ta *v1alpha1.TektonAddon, @@ -508,28 +524,30 @@ func createInstallerSet(ctx context.Context, oc clientset.Interface, ta *v1alpha return err } - return nil + return v1alpha1.RECONCILE_AGAIN_ERR } func makeInstallerSet(ta *v1alpha1.TektonAddon, manifest mf.Manifest, prefix, releaseVersion, component, specHash string) *v1alpha1.TektonInstallerSet { ownerRef := *metav1.NewControllerRef(ta, ta.GetGroupVersionKind()) labels := map[string]string{ - tektoninstallerset.CreatedByKey: CreatedByValue, - tektoninstallerset.InstallerSetType: component, - tektoninstallerset.ReleaseVersionKey: releaseVersion, + v1alpha1.CreatedByKey: CreatedByValue, + v1alpha1.InstallerSetType: component, + v1alpha1.ReleaseVersionKey: releaseVersion, } + namePrefix := fmt.Sprintf("%s-", prefix) // special label to make sure no two versioned clustertask installerset exist // for all patch releases if component == VersionedClusterTaskInstallerSet { - labels[tektoninstallerset.ReleaseMinorVersionKey] = getPatchVersionTrimmed(releaseVersion) + labels[v1alpha1.ReleaseMinorVersionKey] = getPatchVersionTrimmed(releaseVersion) + namePrefix = fmt.Sprintf("%s%s-", namePrefix, getFormattedVersion(releaseVersion)) } return &v1alpha1.TektonInstallerSet{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: fmt.Sprintf("%s-", prefix), + GenerateName: namePrefix, Labels: labels, Annotations: map[string]string{ - tektoninstallerset.TargetNamespaceKey: ta.Spec.TargetNamespace, - tektoninstallerset.LastAppliedHashKey: specHash, + v1alpha1.TargetNamespaceKey: ta.Spec.TargetNamespace, + v1alpha1.LastAppliedHashKey: specHash, }, OwnerReferences: []metav1.OwnerReference{ownerRef}, }, @@ -630,3 +648,28 @@ func getPatchVersionTrimmed(version string) string { } return version } + +func (r *Reconciler) markUpgrade(ctx context.Context, ta *v1alpha1.TektonAddon) error { + labels := ta.GetLabels() + ver, ok := labels[v1alpha1.ReleaseVersionKey] + if ok && ver == r.operatorVersion { + return nil + } + if ok && ver != r.operatorVersion { + ta.Status.MarkInstallerSetNotReady(v1alpha1.UpgradePending) + ta.Status.MarkPreReconcilerFailed(v1alpha1.UpgradePending) + ta.Status.MarkPostReconcilerFailed(v1alpha1.UpgradePending) + ta.Status.MarkNotReady(v1alpha1.UpgradePending) + } + if labels == nil { + labels = map[string]string{} + } + labels[v1alpha1.ReleaseVersionKey] = r.operatorVersion + ta.SetLabels(labels) + + if _, err := r.operatorClientSet.OperatorV1alpha1().TektonAddons().Update(ctx, + ta, metav1.UpdateOptions{}); err != nil { + return err + } + return v1alpha1.RECONCILE_AGAIN_ERR +} diff --git a/pkg/reconciler/openshift/tektonconfig/common.go b/pkg/reconciler/openshift/tektonconfig/common.go index 13a7a097a4..eb02f686e7 100644 --- a/pkg/reconciler/openshift/tektonconfig/common.go +++ b/pkg/reconciler/openshift/tektonconfig/common.go @@ -21,7 +21,6 @@ import ( "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" "github.com/tektoncd/operator/pkg/client/clientset/versioned" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -68,8 +67,8 @@ func makeInstallerSet(tc *v1alpha1.TektonConfig, name, releaseVersion string, la Name: name, Labels: labels, Annotations: map[string]string{ - tektoninstallerset.ReleaseVersionKey: releaseVersion, - tektoninstallerset.TargetNamespaceKey: tc.Spec.TargetNamespace, + v1alpha1.ReleaseVersionKey: releaseVersion, + v1alpha1.TargetNamespaceKey: tc.Spec.TargetNamespace, }, OwnerReferences: []metav1.OwnerReference{ownerRef}, }, @@ -123,7 +122,7 @@ func checkIfInstallerSetExist(ctx context.Context, oc versioned.Interface, relVe return false, err } - if version, ok := ctIs.Annotations[tektoninstallerset.ReleaseVersionKey]; ok && version == relVersion { + if version, ok := ctIs.Annotations[v1alpha1.ReleaseVersionKey]; ok && version == relVersion { // if installer set already exist and release version is same // then ignore and move on return true, nil diff --git a/pkg/reconciler/openshift/tektonconfig/extension/addon.go b/pkg/reconciler/openshift/tektonconfig/extension/addon.go index f516909978..67d6f6c92b 100644 --- a/pkg/reconciler/openshift/tektonconfig/extension/addon.go +++ b/pkg/reconciler/openshift/tektonconfig/extension/addon.go @@ -127,6 +127,13 @@ func waitForTektonAddonState(clients op.TektonAddonInterface, name string, // isTektonAddonReady will check the status conditions of the TektonAddon and return true if the TektonAddon is ready. func isTektonAddonReady(s *v1alpha1.TektonAddon, err error) (bool, error) { + upgradePending, errInternal := common.CheckUpgradePending(s) + if err != nil { + return false, errInternal + } + if upgradePending { + return false, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR + } return s.Status.IsReady(), err } diff --git a/pkg/reconciler/openshift/tektonconfig/rbac.go b/pkg/reconciler/openshift/tektonconfig/rbac.go index fbbafe1a1d..2b6771f904 100644 --- a/pkg/reconciler/openshift/tektonconfig/rbac.go +++ b/pkg/reconciler/openshift/tektonconfig/rbac.go @@ -24,7 +24,6 @@ import ( "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned" "github.com/tektoncd/operator/pkg/reconciler/common" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -139,7 +138,7 @@ func (r *rbac) createResources(ctx context.Context) error { } if !exist { if err := createInstallerSet(ctx, r.operatorClientSet, r.tektonConfig, map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, + v1alpha1.CreatedByKey: createdByValue, }, r.version, componentName, "rbac-resources"); err != nil { return err } diff --git a/pkg/reconciler/openshift/tektonpipeline/extension.go b/pkg/reconciler/openshift/tektonpipeline/extension.go index 74d16486a7..b69063403d 100644 --- a/pkg/reconciler/openshift/tektonpipeline/extension.go +++ b/pkg/reconciler/openshift/tektonpipeline/extension.go @@ -28,7 +28,6 @@ import ( "github.com/tektoncd/operator/pkg/client/clientset/versioned" operatorclient "github.com/tektoncd/operator/pkg/client/injection/client" "github.com/tektoncd/operator/pkg/reconciler/common" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common" "go.uber.org/zap" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -54,14 +53,14 @@ const ( var ( preReconcileSelector = metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, - tektoninstallerset.InstallerSetType: prePipelineInstallerSet, + v1alpha1.CreatedByKey: createdByValue, + v1alpha1.InstallerSetType: prePipelineInstallerSet, }, } postReconcileSelector = metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, - tektoninstallerset.InstallerSetType: postPipelineInstallerSet, + v1alpha1.CreatedByKey: createdByValue, + v1alpha1.InstallerSetType: postPipelineInstallerSet, }, } ) diff --git a/pkg/reconciler/openshift/tektonpipeline/installerset.go b/pkg/reconciler/openshift/tektonpipeline/installerset.go index 22c497fd55..23b8dacb01 100644 --- a/pkg/reconciler/openshift/tektonpipeline/installerset.go +++ b/pkg/reconciler/openshift/tektonpipeline/installerset.go @@ -25,7 +25,6 @@ import ( mf "github.com/manifestival/manifestival" "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -76,8 +75,8 @@ func checkIfInstallerSetExist(ctx context.Context, oc clientset.Interface, relVe // If anyone of this is not as expected then delete existing // InstallerSet and return false - version, vOk := installerSets.Items[0].Labels[tektoninstallerset.ReleaseVersionKey] - namespace, nOk := installerSets.Items[0].Annotations[tektoninstallerset.TargetNamespaceKey] + version, vOk := installerSets.Items[0].Labels[v1alpha1.ReleaseVersionKey] + namespace, nOk := installerSets.Items[0].Annotations[v1alpha1.TargetNamespaceKey] if vOk && nOk { if version == relVersion && namespace == tp.Spec.TargetNamespace { @@ -133,13 +132,13 @@ func makeInstallerSet(tp *v1alpha1.TektonPipeline, manifest mf.Manifest, install ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", strings.ToLower(installerSetType)), Labels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, - tektoninstallerset.ReleaseVersionKey: releaseVersion, - tektoninstallerset.InstallerSetType: installerSetType, + v1alpha1.CreatedByKey: createdByValue, + v1alpha1.ReleaseVersionKey: releaseVersion, + v1alpha1.InstallerSetType: installerSetType, }, Annotations: map[string]string{ - tektoninstallerset.ReleaseVersionKey: releaseVersion, - tektoninstallerset.TargetNamespaceKey: tp.Spec.TargetNamespace, + v1alpha1.ReleaseVersionKey: releaseVersion, + v1alpha1.TargetNamespaceKey: tp.Spec.TargetNamespace, }, OwnerReferences: []metav1.OwnerReference{ownerRef}, }, diff --git a/pkg/reconciler/shared/tektonconfig/controller.go b/pkg/reconciler/shared/tektonconfig/controller.go index c1587d8fd3..dafed46ce0 100644 --- a/pkg/reconciler/shared/tektonconfig/controller.go +++ b/pkg/reconciler/shared/tektonconfig/controller.go @@ -46,13 +46,22 @@ func NewExtensibleController(generator common.ExtensionGenerator) injection.Cont return func(ctx context.Context, cmw configmap.Watcher) *controller.Impl { logger := logging.FromContext(ctx) + operatorVer, err := common.OperatorVersion(ctx) + if err != nil { + logger.Fatal(err) + } + c := &Reconciler{ kubeClientSet: kubeclient.Get(ctx), operatorClientSet: operatorclient.Get(ctx), extension: generator(ctx), + operatorVersion: operatorVer, } impl := tektonConfigreconciler.NewImpl(ctx, c) + // Add enqueue func in reconciler + c.enqueueAfter = impl.EnqueueAfter + logger.Info("Setting up event handlers for TektonConfig") tektonConfiginformer.Get(ctx).Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) diff --git a/pkg/reconciler/shared/tektonconfig/pipeline/pipeline.go b/pkg/reconciler/shared/tektonconfig/pipeline/pipeline.go index ed82c891b7..d3da8737ed 100644 --- a/pkg/reconciler/shared/tektonconfig/pipeline/pipeline.go +++ b/pkg/reconciler/shared/tektonconfig/pipeline/pipeline.go @@ -126,6 +126,13 @@ func waitForTektonPipelineState(clients op.TektonPipelineInterface, name string, // IsTektonPipelineReady will check the status conditions of the TektonPipeline and return true if the TektonPipeline is ready. func isTektonPipelineReady(s *v1alpha1.TektonPipeline, err error) (bool, error) { + upgradePending, errInternal := common.CheckUpgradePending(s) + if err != nil { + return false, errInternal + } + if upgradePending { + return false, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR + } return s.Status.IsReady(), err } diff --git a/pkg/reconciler/shared/tektonconfig/tektonconfig.go b/pkg/reconciler/shared/tektonconfig/tektonconfig.go index 7a6bb8c49c..03f6795a5b 100644 --- a/pkg/reconciler/shared/tektonconfig/tektonconfig.go +++ b/pkg/reconciler/shared/tektonconfig/tektonconfig.go @@ -19,7 +19,9 @@ package tektonconfig import ( "context" "fmt" + "time" + mf "github.com/manifestival/manifestival" "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned" tektonConfigreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektonconfig" @@ -40,6 +42,10 @@ type Reconciler struct { operatorClientSet clientset.Interface // Platform-specific behavior to affect the transform extension common.Extension + // enqueueAfter enqueues a obj after a duration + enqueueAfter func(obj interface{}, after time.Duration) + manifest mf.Manifest + operatorVersion string } // Check that our Reconciler implements controller.Reconciler @@ -55,10 +61,10 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton } if original.Spec.Profile == v1alpha1.ProfileLite { - return pipeline.TektonPipelineCRDelete(r.operatorClientSet.OperatorV1alpha1().TektonPipelines(), common.PipelineResourceName) + return pipeline.TektonPipelineCRDelete(r.operatorClientSet.OperatorV1alpha1().TektonPipelines(), v1alpha1.PipelineResourceName) } else { // TektonPipeline and TektonTrigger is common for profile type basic and all - if err := trigger.TektonTriggerCRDelete(r.operatorClientSet.OperatorV1alpha1().TektonTriggers(), common.TriggerResourceName); err != nil { + if err := trigger.TektonTriggerCRDelete(r.operatorClientSet.OperatorV1alpha1().TektonTriggers(), v1alpha1.TriggerResourceName); err != nil { return err } if err := pipeline.TektonPipelineCRDelete(r.operatorClientSet.OperatorV1alpha1().TektonPipelines(), v1alpha1.PipelineResourceName); err != nil { @@ -76,9 +82,9 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tc *v1alpha1.TektonConfi tc.Status.InitializeConditions() logger.Infow("Reconciling TektonConfig", "status", tc.Status) - if tc.GetName() != common.ConfigResourceName { + if tc.GetName() != v1alpha1.ConfigResourceName { msg := fmt.Sprintf("Resource ignored, Expected Name: %s, Got Name: %s", - common.ConfigResourceName, + v1alpha1.ConfigResourceName, tc.GetName(), ) logger.Error(msg) @@ -87,10 +93,15 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tc *v1alpha1.TektonConfi } tc.SetDefaults(ctx) + // Mark TektonConfig Instance as Not Ready if an upgrade is needed + if err := r.markUpgrade(ctx, tc); err != nil { + return err + } if err := r.extension.PreReconcile(ctx, tc); err != nil { if err == v1alpha1.RECONCILE_AGAIN_ERR { - return err + r.enqueueAfter(tc, 10*time.Second) + return nil } tc.Status.MarkPreInstallFailed(err.Error()) return err @@ -101,19 +112,22 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tc *v1alpha1.TektonConfi // Create TektonPipeline CR if err := pipeline.CreatePipelineCR(tc, r.operatorClientSet.OperatorV1alpha1()); err != nil { tc.Status.MarkComponentNotReady(fmt.Sprintf("TektonPipeline: %s", err.Error())) - return err + r.enqueueAfter(tc, 10*time.Second) + return nil } // Create TektonTrigger CR if the profile is all or basic if tc.Spec.Profile == v1alpha1.ProfileAll || tc.Spec.Profile == v1alpha1.ProfileBasic { if err := trigger.CreateTriggerCR(tc, r.operatorClientSet.OperatorV1alpha1()); err != nil { tc.Status.MarkComponentNotReady(fmt.Sprintf("TektonTrigger: %s", err.Error())) - return err + r.enqueueAfter(tc, 10*time.Second) + return nil } } else { - if err := trigger.TektonTriggerCRDelete(r.operatorClientSet.OperatorV1alpha1().TektonTriggers(), common.TriggerResourceName); err != nil { + if err := trigger.TektonTriggerCRDelete(r.operatorClientSet.OperatorV1alpha1().TektonTriggers(), v1alpha1.TriggerResourceName); err != nil { tc.Status.MarkComponentNotReady(fmt.Sprintf("TektonTrigger: %s", err.Error())) - return err + r.enqueueAfter(tc, 10*time.Second) + return nil } } @@ -126,7 +140,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tc *v1alpha1.TektonConfi if err := r.extension.PostReconcile(ctx, tc); err != nil { tc.Status.MarkPostInstallFailed(err.Error()) - return err + r.enqueueAfter(tc, 10*time.Second) + return nil } tc.Status.MarkPostInstallComplete() @@ -138,3 +153,28 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tc *v1alpha1.TektonConfi return nil } + +func (r *Reconciler) markUpgrade(ctx context.Context, tc *v1alpha1.TektonConfig) error { + labels := tc.GetLabels() + ver, ok := labels[v1alpha1.ReleaseVersionKey] + if ok && ver == r.operatorVersion { + return nil + } + if ok && ver != r.operatorVersion { + tc.Status.MarkComponentNotReady("Upgrade Pending") + tc.Status.MarkPreInstallFailed(v1alpha1.UpgradePending) + tc.Status.MarkPostInstallFailed(v1alpha1.UpgradePending) + tc.Status.MarkNotReady("Upgrade Pending") + } + if labels == nil { + labels = map[string]string{} + } + labels[v1alpha1.ReleaseVersionKey] = r.operatorVersion + tc.SetLabels(labels) + // Update the object for any spec changes + if _, err := r.operatorClientSet.OperatorV1alpha1().TektonConfigs().Update(ctx, + tc, v1.UpdateOptions{}); err != nil { + return err + } + return v1alpha1.RECONCILE_AGAIN_ERR +} diff --git a/pkg/reconciler/shared/tektonconfig/trigger/trigger.go b/pkg/reconciler/shared/tektonconfig/trigger/trigger.go index ee7041e75e..a113fc8490 100644 --- a/pkg/reconciler/shared/tektonconfig/trigger/trigger.go +++ b/pkg/reconciler/shared/tektonconfig/trigger/trigger.go @@ -126,6 +126,13 @@ func waitForTektonTriggerState(clients op.TektonTriggerInterface, name string, // isTektonTriggerReady will check the status conditions of the TektonTrigger and return true if the TektonTrigger is ready. func isTektonTriggerReady(s *v1alpha1.TektonTrigger, err error) (bool, error) { + upgradePending, errInternal := common.CheckUpgradePending(s) + if err != nil { + return false, errInternal + } + if upgradePending { + return false, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR + } return s.Status.IsReady(), err } diff --git a/test/e2e-common.sh b/test/e2e-common.sh index 7d0deafacb..9110aebfdb 100755 --- a/test/e2e-common.sh +++ b/test/e2e-common.sh @@ -47,9 +47,21 @@ function install_operator_resources() { # Wait for pods to be running in the namespaces we are deploying to # TODO: parameterize namespace, operator can run in a namespace different from the namespace where tektonpipelines is installed wait_until_pods_running ${OPERATOR_NAMESPACE} || fail_test "Tekton Operator controller did not come up" +} + +function tektonconfig_ready_wait() { + echo "Wait for controller to start and create TektonConfig" + TEKTONCONFIG_READY=False + until [[ "${TEKTONCONFIG_READY}" = "True" ]]; do + echo waiting for TektonConfig config Ready status + sleep 5 + kubectl get TektonConfig config > /dev/null 2>&1 + if [[ $? -ne 0 ]]; then + echo TektonConfig config not yet created + continue + fi + TEKTONCONFIG_READY=$(kubectl get tektonconfig config -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}') - # Make sure that everything is cleaned up in the current namespace. - for res in tektonpipelines tektontriggers tektondashboards; do - kubectl delete --ignore-not-found=true ${res}.operator.tekton.dev --all done + echo "TektonConfig config Ready: True" } diff --git a/test/e2e-tests.sh b/test/e2e-tests.sh index 7058249be8..73fca69134 100755 --- a/test/e2e-tests.sh +++ b/test/e2e-tests.sh @@ -32,8 +32,7 @@ failed=0 header "Setting up environment" install_operator_resources -echo "Wait for TektonConfig creation" -sleep 30 +tektonconfig_ready_wait header "Running Go e2e tests" go_test_e2e -timeout=20m ./test/e2e/common ${KUBECONFIG_PARAM} || failed=1 diff --git a/test/e2e/common/tektonconfigdeployment_test.go b/test/e2e/common/tektonconfigdeployment_test.go index 4e09e46ebf..00fcae9ddd 100644 --- a/test/e2e/common/tektonconfigdeployment_test.go +++ b/test/e2e/common/tektonconfigdeployment_test.go @@ -27,7 +27,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" "github.com/tektoncd/operator/pkg/reconciler/common" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektonpipeline" "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektontrigger" "github.com/tektoncd/operator/test/client" @@ -298,7 +297,7 @@ func runAddonTest(t *testing.T, clients *utils.Clients, tc *v1alpha1.TektonConfi ls := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.CreatedByKey: "TektonAddon", + v1alpha1.CreatedByKey: "TektonAddon", }, } labelSelector, err := common.LabelSelector(ls) diff --git a/test/resources/tektonaddons.go b/test/resources/tektonaddons.go index 7f0f0d971e..a522e82861 100644 --- a/test/resources/tektonaddons.go +++ b/test/resources/tektonaddons.go @@ -20,11 +20,12 @@ import ( "context" "errors" "fmt" - "github.com/tektoncd/operator/pkg/reconciler/common" "path/filepath" "runtime" "testing" + "github.com/tektoncd/operator/pkg/reconciler/common" + mfc "github.com/manifestival/client-go-client" mf "github.com/manifestival/manifestival" @@ -35,7 +36,6 @@ import ( "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1" addonv1alpha1 "github.com/tektoncd/operator/pkg/client/clientset/versioned/typed/operator/v1alpha1" - "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset" "github.com/tektoncd/operator/pkg/reconciler/openshift/tektonaddon" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -97,6 +97,7 @@ func AssertTektonAddonCRReadyStatus(t *testing.T, clients *utils.Clients, names // AssertTektonInstallerSets verifies if the TektonInstallerSets are created. func AssertTektonInstallerSets(t *testing.T, clients *utils.Clients) { assertInstallerSetsForAddon(t, clients, tektonaddon.ClusterTaskInstallerSet) + assertInstallerSetsForAddon(t, clients, tektonaddon.VersionedClusterTaskInstallerSet) assertInstallerSetsForAddon(t, clients, tektonaddon.PipelinesTemplateInstallerSet) assertInstallerSetsForAddon(t, clients, tektonaddon.TriggersResourcesInstallerSet) assertInstallerSetsForAddon(t, clients, tektonaddon.ConsoleCLIInstallerSet) @@ -106,7 +107,7 @@ func AssertTektonInstallerSets(t *testing.T, clients *utils.Clients) { func assertInstallerSetsForAddon(t *testing.T, clients *utils.Clients, component string) { ls := metav1.LabelSelector{ MatchLabels: map[string]string{ - tektoninstallerset.InstallerSetType: component, + v1alpha1.InstallerSetType: component, }, } labelSelector, err := common.LabelSelector(ls)