diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/predicate_func.go b/operators/multiclusterobservability/controllers/multiclusterobservability/predicate_func.go index af7f25c13..00c1f44b0 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/predicate_func.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/predicate_func.go @@ -5,6 +5,8 @@ package multiclusterobservability import ( + "reflect" + mcov1beta2 "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/v1beta2" "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" mchv1 "github.com/stolostron/multiclusterhub-operator/api/v1" @@ -138,7 +140,7 @@ func GetMCHPredicateFunc(c client.Client) predicate.Funcs { e.Object.(*mchv1.MultiClusterHub).Status.DesiredVersion == e.Object.(*mchv1.MultiClusterHub).Status.CurrentVersion { // only read the image manifests configmap and enqueue the request when the MCH is // installed/upgraded successfully - ok, err := config.ReadImageManifestConfigMap( + _, ok, err := config.ReadImageManifestConfigMap( c, e.Object.(*mchv1.MultiClusterHub).Status.CurrentVersion, ) @@ -150,20 +152,32 @@ func GetMCHPredicateFunc(c client.Client) predicate.Funcs { return false }, UpdateFunc: func(e event.UpdateEvent) bool { + // Ensure the event pertains to the target namespace and object type if e.ObjectNew.GetNamespace() == config.GetMCONamespace() && + e.ObjectNew.GetResourceVersion() != e.ObjectOld.GetResourceVersion() && e.ObjectNew.(*mchv1.MultiClusterHub).Status.CurrentVersion != "" && e.ObjectNew.(*mchv1.MultiClusterHub).Status.DesiredVersion == e.ObjectNew.(*mchv1.MultiClusterHub).Status.CurrentVersion { - // only read the image manifests configmap and enqueue the request when the MCH is - // installed/upgraded successfully - ok, err := config.ReadImageManifestConfigMap( + + currentData, _, err := config.ReadImageManifestConfigMap( c, e.ObjectNew.(*mchv1.MultiClusterHub).Status.CurrentVersion, ) if err != nil { + log.Error(err, "Failed to read image manifest ConfigMap") return false } - return ok + + previousData, exists := config.GetCachedImageManifestData() + if !exists { + config.SetCachedImageManifestData(currentData) + return true + } + if !reflect.DeepEqual(currentData, previousData) { + config.SetCachedImageManifestData(currentData) + return true + } + return false } return false }, diff --git a/operators/multiclusterobservability/controllers/placementrule/placementrule_controller_test.go b/operators/multiclusterobservability/controllers/placementrule/placementrule_controller_test.go index 0215c3e2f..2683f25d6 100644 --- a/operators/multiclusterobservability/controllers/placementrule/placementrule_controller_test.go +++ b/operators/multiclusterobservability/controllers/placementrule/placementrule_controller_test.go @@ -510,7 +510,7 @@ func TestObservabilityAddonController(t *testing.T) { }, } - ok, err := config.ReadImageManifestConfigMap(c, testMCHInstance.Status.CurrentVersion) + _, ok, err := config.ReadImageManifestConfigMap(c, testMCHInstance.Status.CurrentVersion) if err != nil || !ok { t.Fatalf("Failed to read image manifest configmap: (%T,%v)", ok, err) } diff --git a/operators/multiclusterobservability/controllers/placementrule/predict_func.go b/operators/multiclusterobservability/controllers/placementrule/predict_func.go index 13d0a0a6a..2e3e934ce 100644 --- a/operators/multiclusterobservability/controllers/placementrule/predict_func.go +++ b/operators/multiclusterobservability/controllers/placementrule/predict_func.go @@ -109,7 +109,7 @@ func getMchPred(c client.Client) predicate.Funcs { e.Object.(*mchv1.MultiClusterHub).Status.DesiredVersion == e.Object.(*mchv1.MultiClusterHub).Status.CurrentVersion { // only read the image manifests configmap and enqueue the request when the MCH is // installed/upgraded successfully - ok, err := config.ReadImageManifestConfigMap( + _, ok, err := config.ReadImageManifestConfigMap( c, e.Object.(*mchv1.MultiClusterHub).Status.CurrentVersion, ) @@ -121,21 +121,32 @@ func getMchPred(c client.Client) predicate.Funcs { return false }, UpdateFunc: func(e event.UpdateEvent) bool { + // Ensure the event pertains to the target namespace and object type if e.ObjectNew.GetNamespace() == config.GetMCONamespace() && e.ObjectNew.GetResourceVersion() != e.ObjectOld.GetResourceVersion() && e.ObjectNew.(*mchv1.MultiClusterHub).Status.CurrentVersion != "" && e.ObjectNew.(*mchv1.MultiClusterHub).Status.DesiredVersion == e.ObjectNew.(*mchv1.MultiClusterHub).Status.CurrentVersion { - // / only read the image manifests configmap and enqueue the request when the MCH is - // installed/upgraded successfully - ok, err := config.ReadImageManifestConfigMap( + + currentData, _, err := config.ReadImageManifestConfigMap( c, e.ObjectNew.(*mchv1.MultiClusterHub).Status.CurrentVersion, ) if err != nil { + log.Error(err, "Failed to read image manifest ConfigMap") return false } - return ok + + previousData, exists := config.GetCachedImageManifestData() + if !exists { + config.SetCachedImageManifestData(currentData) + return true + } + if !reflect.DeepEqual(currentData, previousData) { + config.SetCachedImageManifestData(currentData) + return true + } + return false } return false }, diff --git a/operators/multiclusterobservability/pkg/config/config.go b/operators/multiclusterobservability/pkg/config/config.go index 71e6c665d..c68e525f4 100644 --- a/operators/multiclusterobservability/pkg/config/config.go +++ b/operators/multiclusterobservability/pkg/config/config.go @@ -9,6 +9,7 @@ import ( "fmt" "os" "strings" + "sync" "time" ocinfrav1 "github.com/openshift/api/config/v1" @@ -322,6 +323,7 @@ var ( } multicloudConsoleRouteHost = "" + imageManifestCache sync.Map ) func GetReplicas(component string, advanced *observabilityv1beta2.AdvancedConfig) *int32 { @@ -396,7 +398,7 @@ func GetImageManifestConfigMapName() string { } // ReadImageManifestConfigMap reads configmap with the label ocm-configmap-type=image-manifest. -func ReadImageManifestConfigMap(c client.Client, version string) (bool, error) { +func ReadImageManifestConfigMap(c client.Client, version string) (map[string]string, bool, error) { mcoNamespace := GetMCONamespace() // List image manifest configmap with label ocm-configmap-type=image-manifest and ocm-release-version matchLabels := map[string]string{ @@ -411,17 +413,17 @@ func ReadImageManifestConfigMap(c client.Client, version string) (bool, error) { imageCMList := &corev1.ConfigMapList{} err := c.List(context.TODO(), imageCMList, listOpts...) if err != nil { - return false, fmt.Errorf("failed to list mch-image-manifest configmaps: %w", err) + return nil, false, fmt.Errorf("failed to list mch-image-manifest configmaps: %w", err) } if len(imageCMList.Items) != 1 { // there should be only one matched image manifest configmap found - return false, nil + return nil, false, nil } imageManifests = imageCMList.Items[0].Data log.V(1).Info("the length of mch-image-manifest configmap", "imageManifests", len(imageManifests)) - return true, nil + return imageManifests, true, nil } // GetImageManifests... @@ -1211,3 +1213,16 @@ func IsAlertingDisabledInSpec(mco *observabilityv1beta2.MultiClusterObservabilit annotations := mco.GetAnnotations() return annotations != nil && annotations[AnnotationDisableMCOAlerting] == "true" } + +func SetCachedImageManifestData(data map[string]string) { + imageManifestCache.Store("mch-image-manifest", data) +} + +func GetCachedImageManifestData() (map[string]string, bool) { + if value, ok := imageManifestCache.Load("mch-image-manifest"); ok { + if cachedData, valid := value.(map[string]string); valid { + return cachedData, true + } + } + return nil, false +} diff --git a/operators/multiclusterobservability/pkg/config/config_test.go b/operators/multiclusterobservability/pkg/config/config_test.go index cf4318652..3099f0f87 100644 --- a/operators/multiclusterobservability/pkg/config/config_test.go +++ b/operators/multiclusterobservability/pkg/config/config_test.go @@ -431,7 +431,7 @@ func TestReadImageManifestConfigMap(t *testing.T) { } client := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjs...).Build() - gotRet, err := ReadImageManifestConfigMap(client, c.version) + _, gotRet, err := ReadImageManifestConfigMap(client, c.version) if err != nil { t.Errorf("Failed read image manifest configmap due to %v", err) }