diff --git a/controllers/operandconfig/operandconfig_controller_test.go b/controllers/operandconfig/operandconfig_controller_test.go index 21b113f4..168d58c1 100644 --- a/controllers/operandconfig/operandconfig_controller_test.go +++ b/controllers/operandconfig/operandconfig_controller_test.go @@ -121,7 +121,7 @@ var _ = Describe("OperandConfig controller", func() { }, timeout, interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -129,7 +129,7 @@ var _ = Describe("OperandConfig controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, timeout, interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) diff --git a/controllers/operandregistry/operandregistry_controller_test.go b/controllers/operandregistry/operandregistry_controller_test.go index 3a075e91..525f822e 100644 --- a/controllers/operandregistry/operandregistry_controller_test.go +++ b/controllers/operandregistry/operandregistry_controller_test.go @@ -120,7 +120,7 @@ var _ = Describe("OperandRegistry controller", func() { }, timeout, interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -128,7 +128,7 @@ var _ = Describe("OperandRegistry controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, timeout, interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) diff --git a/controllers/operandrequest/operandrequest_controller_test.go b/controllers/operandrequest/operandrequest_controller_test.go index 5b36c35a..a63ad87d 100644 --- a/controllers/operandrequest/operandrequest_controller_test.go +++ b/controllers/operandrequest/operandrequest_controller_test.go @@ -140,7 +140,7 @@ var _ = Describe("OperandRequest controller", func() { }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -148,7 +148,7 @@ var _ = Describe("OperandRequest controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) @@ -272,7 +272,7 @@ var _ = Describe("OperandRequest controller", func() { }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -280,7 +280,7 @@ var _ = Describe("OperandRequest controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) @@ -433,7 +433,7 @@ var _ = Describe("OperandRequest controller", func() { }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -441,7 +441,7 @@ var _ = Describe("OperandRequest controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 5c323c86..adb88acf 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -351,20 +351,23 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, cr *operatorv1alpha klog.V(2).Infof("Deleting Subscription %s/%s ...", sub.Namespace, sub.Name) - csv, err := r.GetClusterServiceVersion(ctx, sub) + csvList, err := r.GetClusterServiceVersionList(ctx, sub) // If can't get CSV, requeue the request if err != nil { return err } - if csv != nil { - klog.V(3).Info("Set Deleting Condition in the operandRequest") - cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) + if csvList != nil { + klog.Infof("Found %d ClusterServiceVersions for Subscription %s/%s", len(csvList), sub.Namespace, sub.Name) + for _, csv := range csvList { + klog.V(3).Info("Set Deleting Condition in the operandRequest") + cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) - klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.Delete(ctx, csv); err != nil { - cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) - return err + klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.Delete(ctx, csv); err != nil { + cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) + return err + } } } @@ -426,16 +429,17 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN return nil } - if csv, err := r.GetClusterServiceVersion(ctx, sub); err != nil { + if csvList, err := r.GetClusterServiceVersionList(ctx, sub); err != nil { // If can't get CSV, requeue the request return err - } else if csv != nil { + } else if csvList != nil { + klog.Infof("Found %d ClusterServiceVersions for Subscription %s/%s", len(csvList), sub.Namespace, sub.Name) if uninstallOperand { - klog.V(2).Infof("Deleting all the Custom Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.deleteAllCustomResource(ctx, csv, requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + klog.V(2).Infof("Deleting all the Custom Resources for CSV, Namespace: %s, Name: %s", csvList[0].Namespace, csvList[0].Name) + if err := r.deleteAllCustomResource(ctx, csvList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { return err } - klog.V(2).Infof("Deleting all the k8s Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + klog.V(2).Infof("Deleting all the k8s Resources for CSV, Namespace: %s, Name: %s", csvList[0].Namespace, csvList[0].Name) if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { return err } @@ -447,12 +451,14 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN } klog.V(3).Info("Set Deleting Condition in the operandRequest") - requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetDeletingCondition(csvList[0].Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) - klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.Delete(ctx, csv); err != nil { - requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) - return errors.Wrap(err, "failed to delete the ClusterServiceVersion") + for _, csv := range csvList { + klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.Delete(ctx, csv); err != nil { + requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) + return errors.Wrapf(err, "failed to delete the ClusterServiceVersion %s/%s", csv.Namespace, csv.Name) + } } } } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 3a4bf4fd..b43c98da 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -391,6 +391,44 @@ func (m *ODLMOperator) GetClusterServiceVersion(ctx context.Context, sub *olmv1a return csv, nil } +// GetClusterServiceVersionList gets a list of ClusterServiceVersions from the subscription +func (m *ODLMOperator) GetClusterServiceVersionList(ctx context.Context, sub *olmv1alpha1.Subscription) ([]*olmv1alpha1.ClusterServiceVersion, error) { + // Check if subscription is nil + if sub == nil { + klog.Error("The subscription is nil") + return nil, fmt.Errorf("the subscription is nil") + } + + packageName := sub.Spec.Package + csvNamespace := sub.Namespace + + // Get the ClusterServiceVersion list with label operators.coreos.com/packageName.csvNamespace='' + csvList := &olmv1alpha1.ClusterServiceVersionList{} + opts := []client.ListOption{ + client.MatchingLabels{fmt.Sprintf("operators.coreos.com/%s.%s", packageName, csvNamespace): ""}, + client.InNamespace(csvNamespace), + } + + if err := m.Reader.List(ctx, csvList, opts...); err != nil { + if apierrors.IsNotFound(err) || len(csvList.Items) == 0 { + klog.V(3).Infof("No ClusterServiceVersion found with label operators.coreos.com/%s.%s", packageName, csvNamespace) + return nil, nil + } + return nil, errors.Wrapf(err, "failed to list ClusterServiceVersions with label operators.coreos.com/%s.%s", packageName, csvNamespace) + } else if len(csvList.Items) > 1 { + klog.Warningf("Multiple ClusterServiceVersions found with label operators.coreos.com/%s.%s", packageName, csvNamespace) + } + + var csvs []*olmv1alpha1.ClusterServiceVersion + for i := range csvList.Items { + klog.V(3).Infof("Get ClusterServiceVersion %s in the namespace %s", csvList.Items[i].Name, csvNamespace) + csvs = append(csvs, &csvList.Items[i]) + } + + klog.V(3).Infof("Get %v ClusterServiceVersions in the namespace %s", len(csvs), csvNamespace) + return csvs, nil +} + // GetOperatorNamespace returns the operator namespace based on the install mode func (m *ODLMOperator) GetOperatorNamespace(installMode, namespace string) string { if installMode == apiv1alpha1.InstallModeCluster { diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index 9308e5f5..4eddc18e 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -495,7 +495,7 @@ func SubscriptionStatus(name, namespace, csvVersion string) olmv1alpha1.Subscrip } } -func ClusterServiceVersion(name, namespace, example string) *olmv1alpha1.ClusterServiceVersion { +func ClusterServiceVersion(name, packageName, namespace, example string) *olmv1alpha1.ClusterServiceVersion { return &olmv1alpha1.ClusterServiceVersion{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -503,6 +503,9 @@ func ClusterServiceVersion(name, namespace, example string) *olmv1alpha1.Cluster Annotations: map[string]string{ "alm-examples": example, }, + Labels: map[string]string{ + "operators.coreos.com/" + packageName + "." + namespace: "", + }, }, Spec: olmv1alpha1.ClusterServiceVersionSpec{ InstallStrategy: olmv1alpha1.NamedInstallStrategy{