diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 2af1f715..2804d1ca 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -376,6 +376,10 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { return false }, UpdateFunc: func(e event.UpdateEvent) bool { + // If the object is not updated except the ODLMWatchedLabel label or ODLMReferenceAnnotation annotation, return false + if !r.ObjectIsUpdatedWithException(&e.ObjectOld, &e.ObjectNew) { + return false + } labels := e.ObjectNew.GetLabels() if labels != nil { if labelValue, ok := labels[constant.ODLMWatchedLabel]; ok && labelValue == "true" { diff --git a/controllers/operandrequest/operandrequest_controller_test.go b/controllers/operandrequest/operandrequest_controller_test.go index a63ad87d..71c15273 100644 --- a/controllers/operandrequest/operandrequest_controller_test.go +++ b/controllers/operandrequest/operandrequest_controller_test.go @@ -325,6 +325,13 @@ var _ = Describe("OperandRequest controller", func() { return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) + By("Checking the status of first OperandRequest") + Eventually(func() operatorv1alpha1.ClusterPhase { + requestInstance1 := &operatorv1alpha1.OperandRequest{} + Expect(k8sClient.Get(ctx, requestKey1, requestInstance1)).Should(Succeed()) + return requestInstance1.Status.Phase + }, testutil.Timeout, testutil.Interval).Should(Equal(operatorv1alpha1.ClusterPhaseRunning)) + By("Disabling the jaeger operator from first OperandRequest") requestInstance1 := &operatorv1alpha1.OperandRequest{} Expect(k8sClient.Get(ctx, requestKey1, requestInstance1)).Should(Succeed()) @@ -338,6 +345,13 @@ var _ = Describe("OperandRequest controller", func() { return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) + By("Checking the status of first OperandRequest after updating the Operand") + Eventually(func() operatorv1alpha1.ClusterPhase { + requestInstance1 := &operatorv1alpha1.OperandRequest{} + Expect(k8sClient.Get(ctx, requestKey1, requestInstance1)).Should(Succeed()) + return requestInstance1.Status.Phase + }, testutil.Timeout, testutil.Interval).Should(Equal(operatorv1alpha1.ClusterPhaseRunning)) + By("Disabling the jaeger operator from second OperandRequest") requestInstance2 := &operatorv1alpha1.OperandRequest{} Expect(k8sClient.Get(ctx, requestKey2, requestInstance2)).Should(Succeed()) @@ -351,20 +365,7 @@ var _ = Describe("OperandRequest controller", func() { return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) - By("Deleting the first OperandRequest") - Expect(k8sClient.Delete(ctx, request1)).Should(Succeed()) - - By("Checking mongodb operator has not been deleted") - Eventually(func() error { - mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) - return err - }, testutil.Timeout, testutil.Interval).Should(Succeed()) - - By("Deleting the second OperandRequest") - Expect(k8sClient.Delete(ctx, request2)).Should(Succeed()) - - By("Checking the k8s resource has been deleted") + By("Checking jaeger k8s resource has been deleted") Eventually(func() bool { jaegerConfigMap := &corev1.ConfigMap{} err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jaeger-configmap", Namespace: registryNamespaceName}, jaegerConfigMap) @@ -376,13 +377,34 @@ var _ = Describe("OperandRequest controller", func() { return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) - By("Checking operators have been deleted") + By("Checking jaeger operators have been deleted") Eventually(func() bool { jaegerCSV := &olmv1alpha1.ClusterServiceVersion{} err := k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) + By("Checking the status of second OperandRequest after updating the Operand") + Eventually(func() operatorv1alpha1.ClusterPhase { + requestInstance2 := &operatorv1alpha1.OperandRequest{} + Expect(k8sClient.Get(ctx, requestKey2, requestInstance2)).Should(Succeed()) + return requestInstance2.Status.Phase + }, testutil.Timeout, testutil.Interval).Should(Equal(operatorv1alpha1.ClusterPhaseRunning)) + + By("Deleting the first OperandRequest") + Expect(k8sClient.Delete(ctx, request1)).Should(Succeed()) + + By("Checking mongodb operator has not been deleted") + Eventually(func() error { + mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) + return err + }, testutil.Timeout, testutil.Interval).Should(Succeed()) + + By("Deleting the second OperandRequest") + Expect(k8sClient.Delete(ctx, request2)).Should(Succeed()) + + By("Checking the mongodb-atlas operator has been deleted") Eventually(func() bool { mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index ed081821..128b856e 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -576,7 +576,7 @@ func (r *Reconciler) reconcileK8sResource(ctx context.Context, res operatorv1alp return err } } else { - klog.V(2).Infof("Skip the k8s resource %s/%s which is not created by ODLM", res.Kind, res.Name) + klog.V(2).Infof("Skip the k8s resource %s %s/%s whose force field is false", res.Kind, k8sResNs, res.Name) } } } else { diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 855542aa..a99b554c 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "fmt" + "reflect" "sort" "strings" @@ -859,7 +860,7 @@ func (m *ODLMOperator) ParseObjectRef(ctx context.Context, obj *util.ObjectRef, func (m *ODLMOperator) GetValueRefFromConfigMap(ctx context.Context, instanceType, instanceName, instanceNs, cmName, cmNs, configMapKey string) (string, error) { cm := &corev1.ConfigMap{} - if err := m.Client.Get(ctx, types.NamespacedName{Name: cmName, Namespace: cmNs}, cm); err != nil { + if err := m.Reader.Get(ctx, types.NamespacedName{Name: cmName, Namespace: cmNs}, cm); err != nil { if apierrors.IsNotFound(err) { klog.V(2).Infof("Configmap %s/%s is not found", cmNs, cmName) return "", nil @@ -891,7 +892,7 @@ func (m *ODLMOperator) GetValueRefFromConfigMap(ctx context.Context, instanceTyp func (m *ODLMOperator) GetValueRefFromSecret(ctx context.Context, instanceType, instanceName, instanceNs, secretName, secretNs, secretKey string) (string, error) { secret := &corev1.Secret{} - if err := m.Client.Get(ctx, types.NamespacedName{Name: secretName, Namespace: secretNs}, secret); err != nil { + if err := m.Reader.Get(ctx, types.NamespacedName{Name: secretName, Namespace: secretNs}, secret); err != nil { if apierrors.IsNotFound(err) { klog.V(3).Infof("Secret %s/%s is not found", secretNs, secretName) return "", nil @@ -959,3 +960,38 @@ func (m *ODLMOperator) GetValueRefFromObject(ctx context.Context, instanceType, klog.V(2).Infof("Get value %s from %s %s/%s", sanitizedString, objKind, obj.GetNamespace(), obj.GetName()) return sanitizedString, nil } + +// ObjectIsUpdatedWithException checks if the object is updated except for the ODLMWatchedLabel and ODLMReferenceAnnotation +func (m *ODLMOperator) ObjectIsUpdatedWithException(oldObj, newObj *client.Object) bool { + oldObject := *oldObj + newObject := *newObj + + // Check if labels are the same except for ODLMWatchedLabel + oldLabels := oldObject.GetLabels() + newLabels := newObject.GetLabels() + if oldLabels != nil && newLabels != nil { + delete(oldLabels, constant.ODLMWatchedLabel) + delete(newLabels, constant.ODLMWatchedLabel) + } + if !reflect.DeepEqual(oldLabels, newLabels) { + return true + } + + // Check if annotations are the same except for ODLMReferenceAnnotation + oldAnnotations := oldObject.GetAnnotations() + newAnnotations := newObject.GetAnnotations() + if oldAnnotations != nil && newAnnotations != nil { + delete(oldAnnotations, constant.ODLMReferenceAnnotation) + delete(newAnnotations, constant.ODLMReferenceAnnotation) + } + if !reflect.DeepEqual(oldAnnotations, newAnnotations) { + return true + } + + // Check if other parts of the object are unchanged + oldObject.SetLabels(nil) + oldObject.SetAnnotations(nil) + newObject.SetLabels(nil) + newObject.SetAnnotations(nil) + return !reflect.DeepEqual(oldObject, newObject) +} diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index 4eddc18e..c79c6e2a 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -200,7 +200,7 @@ func OperandConfigObj(name, namespace string) *apiv1alpha1.OperandConfig { } }`), }, - Force: false, + Force: true, }, }, },