diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/const.go b/pkg/reconciler/kubernetes/tektoninstallerset/const.go index 3efaf627d1..6eee854cfd 100644 --- a/pkg/reconciler/kubernetes/tektoninstallerset/const.go +++ b/pkg/reconciler/kubernetes/tektoninstallerset/const.go @@ -21,4 +21,12 @@ const ( CreatedByKey = "operator.tekton.dev/created-by" ReleaseVersionKey = "operator.tekton.dev/release-version" TargetNamespaceKey = "operator.tekton.dev/target-namespace" + InstallerSetType = "operator.tekton.dev/type" + + ClusterTaskInstallerSet = "ClusterTask" + PipelinesTemplateInstallerSet = "PipelinesTemplate" + TriggersResourcesInstallerSet = "TriggersResources" + ConsoleCLIInstallerSet = "ConsoleCLI" + MiscellaneousResourcesInstallerSet = "MiscellaneousResources" + CreatedByValue = "TektonAddon" ) diff --git a/pkg/reconciler/openshift/tektonaddon/extension.go b/pkg/reconciler/openshift/tektonaddon/extension.go index 93ad925fe9..541e42f7bc 100644 --- a/pkg/reconciler/openshift/tektonaddon/extension.go +++ b/pkg/reconciler/openshift/tektonaddon/extension.go @@ -87,31 +87,27 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te logger := logging.FromContext(ctx) addon := comp.(*v1alpha1.TektonAddon) - exist, err := checkIfInstallerSetExist(ctx, oe.operatorClientSet, oe.version, addon, miscellaneousResourcesInstallerSet) + exist, err := checkIfInstallerSetExist(ctx, oe.operatorClientSet, oe.version, tektoninstallerset.MiscellaneousResourcesInstallerSet) if err != nil { return err } if !exist { - manifest, err := getMiscellaneousManifest(ctx, addon, oe.manifest, comp) if err != nil { return err } if err := createInstallerSet(ctx, oe.operatorClientSet, addon, manifest, oe.version, - miscellaneousResourcesInstallerSet, "addon-openshift"); err != nil { + tektoninstallerset.MiscellaneousResourcesInstallerSet, "addon-openshift"); err != nil { return err } } // Check if installer set is already created - compInstallerSet, ok := addon.Status.AddonsInstallerSet[miscellaneousResourcesInstallerSet] - if !ok { - return v1alpha1.RECONCILE_AGAIN_ERR - } - installedTIS, err := oe.operatorClientSet.OperatorV1alpha1().TektonInstallerSets(). - Get(ctx, compInstallerSet, metav1.GetOptions{}) + List(ctx, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", tektoninstallerset.InstallerSetType, tektoninstallerset.MiscellaneousResourcesInstallerSet), + }) if err != nil { if apierrors.IsNotFound(err) { manifest, err := getMiscellaneousManifest(ctx, addon, oe.manifest, comp) @@ -120,7 +116,7 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te } if err := createInstallerSet(ctx, oe.operatorClientSet, addon, manifest, oe.version, - miscellaneousResourcesInstallerSet, "addon-openshift"); err != nil { + tektoninstallerset.MiscellaneousResourcesInstallerSet, "addon-openshift"); err != nil { return err } } @@ -134,7 +130,7 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te } // spec hash stored on installerSet - lastAppliedHash := installedTIS.GetAnnotations()[tektoninstallerset.LastAppliedHashKey] + lastAppliedHash := installedTIS.Items[0].GetAnnotations()[tektoninstallerset.LastAppliedHashKey] if lastAppliedHash != expectedSpecHash { @@ -144,33 +140,31 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te } // Update the spec hash - current := installedTIS.GetAnnotations() + current := installedTIS.Items[0].GetAnnotations() current[tektoninstallerset.LastAppliedHashKey] = expectedSpecHash - installedTIS.SetAnnotations(current) + installedTIS.Items[0].SetAnnotations(current) // Update the manifests - installedTIS.Spec.Manifests = manifest.Resources() + installedTIS.Items[0].Spec.Manifests = manifest.Resources() if _, err = oe.operatorClientSet.OperatorV1alpha1().TektonInstallerSets(). - Update(ctx, installedTIS, metav1.UpdateOptions{}); err != nil { + Update(ctx, &installedTIS.Items[0], metav1.UpdateOptions{}); err != nil { return err } return v1alpha1.RECONCILE_AGAIN_ERR } - existingInstallerSet, ok := addon.Status.AddonsInstallerSet[miscellaneousResourcesInstallerSet] - if !ok { - return v1alpha1.RECONCILE_AGAIN_ERR - } installedAddonIS, err := oe.operatorClientSet.OperatorV1alpha1().TektonInstallerSets(). - Get(ctx, existingInstallerSet, metav1.GetOptions{}) + List(ctx, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", tektoninstallerset.InstallerSetType, tektoninstallerset.MiscellaneousResourcesInstallerSet), + }) if err != nil { logger.Error("failed to get InstallerSet: %s", err) return err } - ready := installedAddonIS.Status.GetCondition(apis.ConditionReady) + ready := installedAddonIS.Items[0].Status.GetCondition(apis.ConditionReady) if ready == nil { return v1alpha1.RECONCILE_AGAIN_ERR } @@ -180,7 +174,7 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te } consolecliManifest := oe.manifest - exist, err = checkIfInstallerSetExist(ctx, oe.operatorClientSet, oe.version, addon, consoleCLIInstallerSet) + exist, err = checkIfInstallerSetExist(ctx, oe.operatorClientSet, oe.version, tektoninstallerset.ConsoleCLIInstallerSet) if err != nil { return err } @@ -203,7 +197,7 @@ func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.Te } if err := createInstallerSet(ctx, oe.operatorClientSet, addon, consolecliManifest, oe.version, - consoleCLIInstallerSet, "addon-consolecli"); err != nil { + tektoninstallerset.ConsoleCLIInstallerSet, "addon-consolecli"); err != nil { return err } } diff --git a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go index 48d3cba2fc..10b80786c4 100644 --- a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go +++ b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go @@ -65,16 +65,6 @@ const ( providerTypeRedHat = "redhat" ) -const ( - clusterTaskInstallerSet = "ClusterTaskInstallerSet" - pipelinesTemplateInstallerSet = "PipelinesTemplateInstallerSet" - triggersResourcesInstallerSet = "TriggersResourcesInstallerSet" - consoleCLIInstallerSet = "ConsoleCLIInstallerSet" - miscellaneousResourcesInstallerSet = "MiscellaneousResourcesInstallerSet" - - createdByValue = "TektonAddon" -) - // Check that our Reconciler implements controller.Reconciler var _ tektonaddonreconciler.Interface = (*Reconciler)(nil) var _ tektonaddonreconciler.Finalizer = (*Reconciler)(nil) @@ -180,7 +170,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon // with their manifest if ctVal == "true" { - exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, ta, clusterTaskInstallerSet) + exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, tektoninstallerset.ClusterTaskInstallerSet) if err != nil { return err } @@ -190,13 +180,12 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon } } else { // if disabled then delete the installer Set if exist - if err := r.deleteInstallerSet(ctx, ta, clusterTaskInstallerSet); err != nil { + if err := r.deleteInstallerSet(ctx, tektoninstallerset.ClusterTaskInstallerSet); err != nil { return err } } - err := r.checkComponentStatus(ctx, ta, clusterTaskInstallerSet) - if err != nil { + if err := r.checkComponentStatus(ctx, tektoninstallerset.ClusterTaskInstallerSet); err != nil { ta.Status.MarkInstallerSetNotReady(err.Error()) return nil } @@ -205,7 +194,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon // with their manifest if ptVal == "true" { - exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, ta, pipelinesTemplateInstallerSet) + exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, tektoninstallerset.PipelinesTemplateInstallerSet) if err != nil { return err } @@ -214,20 +203,19 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon } } else { // if disabled then delete the installer Set if exist - if err := r.deleteInstallerSet(ctx, ta, pipelinesTemplateInstallerSet); err != nil { + if err := r.deleteInstallerSet(ctx, tektoninstallerset.PipelinesTemplateInstallerSet); err != nil { return err } } - err = r.checkComponentStatus(ctx, ta, pipelinesTemplateInstallerSet) - if err != nil { + if err := r.checkComponentStatus(ctx, tektoninstallerset.PipelinesTemplateInstallerSet); err != nil { ta.Status.MarkInstallerSetNotReady(err.Error()) return nil } // Ensure Triggers resources - exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, ta, triggersResourcesInstallerSet) + exist, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.version, tektoninstallerset.TriggersResourcesInstallerSet) if err != nil { return err } @@ -235,7 +223,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon return r.ensureTriggerResources(ctx, ta) } - err = r.checkComponentStatus(ctx, ta, triggersResourcesInstallerSet) + err = r.checkComponentStatus(ctx, tektoninstallerset.TriggersResourcesInstallerSet) if err != nil { ta.Status.MarkInstallerSetNotReady(err.Error()) return nil @@ -254,34 +242,31 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon ta.Status.MarkPostReconcilerComplete() + ta.Status.SetVersion(r.version) + return nil } -func (r *Reconciler) checkComponentStatus(ctx context.Context, ta *v1alpha1.TektonAddon, component string) error { +func (r *Reconciler) checkComponentStatus(ctx context.Context, component string) error { // Check if installer set is already created - compInstallerSet, ok := ta.Status.AddonsInstallerSet[component] - if !ok { - return nil - } + installerSets, err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets(). + List(ctx, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", tektoninstallerset.InstallerSetType, component), + }) - if compInstallerSet != "" { - - ctIs, err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets(). - Get(ctx, compInstallerSet, metav1.GetOptions{}) - if err != nil { - if errors.IsNotFound(err) { - return nil - } - return err + if err != nil { + if errors.IsNotFound(err) { + return nil } + return err + } - ready := ctIs.Status.GetCondition(apis.ConditionReady) - if ready == nil || ready.Status == corev1.ConditionUnknown { - return fmt.Errorf("InstallerSet %s: waiting for installation", ctIs.Name) - } else if ready.Status == corev1.ConditionFalse { - return fmt.Errorf("InstallerSet %s: ", ready.Message) - } + ready := installerSets.Items[0].Status.GetCondition(apis.ConditionReady) + if ready == nil || ready.Status == corev1.ConditionUnknown { + return fmt.Errorf("InstallerSet %s: waiting for installation", installerSets.Items[0].Name) + } else if ready.Status == corev1.ConditionFalse { + return fmt.Errorf("InstallerSet %s: ", ready.Message) } return nil @@ -299,7 +284,7 @@ func (r *Reconciler) ensureTriggerResources(ctx context.Context, ta *v1alpha1.Te } if err := createInstallerSet(ctx, r.operatorClientSet, ta, triggerResourcesManifest, r.version, - triggersResourcesInstallerSet, "addon-triggers"); err != nil { + tektoninstallerset.TriggersResourcesInstallerSet, "addon-triggers"); err != nil { return err } @@ -325,7 +310,7 @@ func (r *Reconciler) ensurePipelineTemplates(ctx context.Context, ta *v1alpha1.T } if err := createInstallerSet(ctx, r.operatorClientSet, ta, pipelineTemplateManifest, r.version, - pipelinesTemplateInstallerSet, "addon-pipelines"); err != nil { + tektoninstallerset.PipelinesTemplateInstallerSet, "addon-pipelines"); err != nil { return err } @@ -358,7 +343,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.version, tektoninstallerset.ClusterTaskInstallerSet, "addon-clustertasks"); err != nil { return err } @@ -369,26 +354,34 @@ func (r *Reconciler) ensureClusterTasks(ctx context.Context, ta *v1alpha1.Tekton // and if installer set which already exist is of older version then it deletes and return false to create a new // installer set func checkIfInstallerSetExist(ctx context.Context, oc clientset.Interface, relVersion string, - ta *v1alpha1.TektonAddon, component string) (bool, error) { + component string) (bool, error) { - // Check if installer set is already created - compInstallerSet, ok := ta.Status.AddonsInstallerSet[component] - if !ok { - return false, nil + installerSets, err := oc.OperatorV1alpha1().TektonInstallerSets(). + List(ctx, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", tektoninstallerset.InstallerSetType, component), + }) + if err != nil { + if errors.IsNotFound(err) { + return false, nil + } + return false, err } - if compInstallerSet != "" { - // if already created then check which version it is - ctIs, err := oc.OperatorV1alpha1().TektonInstallerSets(). - Get(ctx, compInstallerSet, metav1.GetOptions{}) + // Delete installer sets if exist more than one + if len(installerSets.Items) > 1 { + err = oc.OperatorV1alpha1().TektonInstallerSets(). + DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", tektoninstallerset.InstallerSetType, component), + }) if err != nil { - if errors.IsNotFound(err) { - return false, nil - } return false, err } + } - version, ok := ctIs.Annotations[tektoninstallerset.ReleaseVersionKey] + // Check if installer set is already created + for i := range installerSets.Items { + // if already created then check which version it is + version, ok := installerSets.Items[i].Labels[tektoninstallerset.ReleaseVersionKey] if ok && version == relVersion { // if installer set already exist and release version is same // then ignore and move on @@ -398,9 +391,10 @@ func checkIfInstallerSetExist(ctx context.Context, oc clientset.Interface, relVe // release version doesn't exist or is different from expected // deleted existing InstallerSet and create a new one - err = oc.OperatorV1alpha1().TektonInstallerSets(). - Delete(ctx, compInstallerSet, metav1.DeleteOptions{}) - if err != nil { + if err = oc.OperatorV1alpha1().TektonInstallerSets(). + DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", tektoninstallerset.InstallerSetType, component), + }); err != nil { return false, err } } @@ -416,41 +410,27 @@ func createInstallerSet(ctx context.Context, oc clientset.Interface, ta *v1alpha return err } - is := makeInstallerSet(ta, manifest, installerSetPrefix, releaseVersion, specHash) - - createdIs, err := oc.OperatorV1alpha1().TektonInstallerSets(). - Create(ctx, is, metav1.CreateOptions{}) - if err != nil { - return err - } - - if len(ta.Status.AddonsInstallerSet) == 0 { - ta.Status.AddonsInstallerSet = map[string]string{} - } - - // Update the status of addon with created installerSet name - ta.Status.AddonsInstallerSet[component] = createdIs.Name - ta.Status.SetVersion(releaseVersion) + is := makeInstallerSet(ta, manifest, installerSetPrefix, releaseVersion, component, specHash) - _, err = oc.OperatorV1alpha1().TektonAddons(). - UpdateStatus(ctx, ta, metav1.UpdateOptions{}) - if err != nil { + if _, err := oc.OperatorV1alpha1().TektonInstallerSets(). + Create(ctx, is, metav1.CreateOptions{}); err != nil { return err } return nil } -func makeInstallerSet(ta *v1alpha1.TektonAddon, manifest mf.Manifest, prefix, releaseVersion, specHash string) *v1alpha1.TektonInstallerSet { +func makeInstallerSet(ta *v1alpha1.TektonAddon, manifest mf.Manifest, prefix, releaseVersion, component, specHash string) *v1alpha1.TektonInstallerSet { ownerRef := *metav1.NewControllerRef(ta, ta.GetGroupVersionKind()) return &v1alpha1.TektonInstallerSet{ ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", prefix), Labels: map[string]string{ - tektoninstallerset.CreatedByKey: createdByValue, + tektoninstallerset.CreatedByKey: tektoninstallerset.CreatedByValue, + tektoninstallerset.InstallerSetType: component, + tektoninstallerset.ReleaseVersionKey: releaseVersion, }, Annotations: map[string]string{ - tektoninstallerset.ReleaseVersionKey: releaseVersion, tektoninstallerset.TargetNamespaceKey: ta.Spec.TargetNamespace, tektoninstallerset.LastAppliedHashKey: specHash, }, @@ -462,28 +442,14 @@ func makeInstallerSet(ta *v1alpha1.TektonAddon, manifest mf.Manifest, prefix, re } } -func (r *Reconciler) deleteInstallerSet(ctx context.Context, ta *v1alpha1.TektonAddon, component string) error { +func (r *Reconciler) deleteInstallerSet(ctx context.Context, component string) error { - compInstallerSet, ok := ta.Status.AddonsInstallerSet[component] - if !ok { - return nil - } - - if compInstallerSet != "" { - // delete the installer set - err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets(). - Delete(ctx, ta.Status.AddonsInstallerSet[component], metav1.DeleteOptions{}) - if err != nil && !errors.IsNotFound(err) { - return err - } - - // clear the name of installer set from TektonAddon status - delete(ta.Status.AddonsInstallerSet, component) - _, err = r.operatorClientSet.OperatorV1alpha1().TektonAddons(). - UpdateStatus(ctx, ta, metav1.UpdateOptions{}) - if err != nil && !errors.IsNotFound(err) { - return err - } + err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets(). + DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", tektoninstallerset.InstallerSetType, component), + }) + if err != nil && !errors.IsNotFound(err) { + return err } return nil diff --git a/test/e2e/openshift/tektonaddondeployment_test.go b/test/e2e/openshift/tektonaddondeployment_test.go index a6701974b4..3a01c2cb1d 100644 --- a/test/e2e/openshift/tektonaddondeployment_test.go +++ b/test/e2e/openshift/tektonaddondeployment_test.go @@ -19,6 +19,7 @@ limitations under the License. package openshift import ( + "fmt" "os" "testing" @@ -87,6 +88,11 @@ func TestTektonAddonsDeployment(t *testing.T) { resources.AssertTektonAddonCRReadyStatus(t, clients, crNames) }) + // Test if TektonInstallerSets are created. + t.Run("verify-tektoninstallersets", func(t *testing.T) { + resources.AssertTektonInstallerSets(t, clients) + }) + // Delete the TektonAddon CR instance to see if all resources will be removed t.Run("delete-addon", func(t *testing.T) { resources.AssertTektonAddonCRReadyStatus(t, clients, crNames) diff --git a/test/resources/tektonaddons.go b/test/resources/tektonaddons.go index f275651582..4e8e1e8d72 100644 --- a/test/resources/tektonaddons.go +++ b/test/resources/tektonaddons.go @@ -34,6 +34,7 @@ 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" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -91,6 +92,27 @@ 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, tektoninstallerset.ClusterTaskInstallerSet) + assertInstallerSetsForAddon(t, clients, tektoninstallerset.PipelinesTemplateInstallerSet) + assertInstallerSetsForAddon(t, clients, tektoninstallerset.TriggersResourcesInstallerSet) + assertInstallerSetsForAddon(t, clients, tektoninstallerset.ConsoleCLIInstallerSet) + assertInstallerSetsForAddon(t, clients, tektoninstallerset.MiscellaneousResourcesInstallerSet) +} + +func assertInstallerSetsForAddon(t *testing.T, clients *utils.Clients, component string) { + clusterTaskIS, err := clients.TektonInstallerSet().List(context.TODO(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", tektoninstallerset.InstallerSetType, component), + }) + if err != nil { + t.Fatalf("failed to get TektonInstallerSet for %s : %v", component, err) + } + if len(clusterTaskIS.Items) > 1 { + t.Fatalf("multiple installer sets for %s TektonInstallerSet", component) + } +} + // TektonAddonCRDelete deletes tha TektonAddon to see if all resources will be deleted func TektonAddonCRDelete(t *testing.T, clients *utils.Clients, crNames utils.ResourceNames) { if err := clients.TektonAddon().Delete(context.TODO(), crNames.TektonAddon, metav1.DeleteOptions{}); err != nil { diff --git a/test/utils/clients.go b/test/utils/clients.go index 7a2df9840e..ff5d082c25 100644 --- a/test/utils/clients.go +++ b/test/utils/clients.go @@ -139,3 +139,11 @@ func (c *Clients) TektonResult() operatorv1alpha1.TektonResultInterface { func (c *Clients) TektonResultAll() operatorv1alpha1.TektonResultInterface { return c.Operator.TektonResults() } + +func (c *Clients) TektonInstallerSet() operatorv1alpha1.TektonInstallerSetInterface { + return c.Operator.TektonInstallerSets() +} + +func (c *Clients) TektonInstallerSetAll() operatorv1alpha1.TektonInstallerSetInterface { + return c.Operator.TektonInstallerSets() +}