diff --git a/bundle/manifests/runtime-component.clusterserviceversion.yaml b/bundle/manifests/runtime-component.clusterserviceversion.yaml index 019e03f9..b91f1a69 100644 --- a/bundle/manifests/runtime-component.clusterserviceversion.yaml +++ b/bundle/manifests/runtime-component.clusterserviceversion.yaml @@ -71,7 +71,7 @@ metadata: categories: Application Runtime certified: "true" containerImage: icr.io/appcafe/runtime-component-operator:daily - createdAt: "2025-06-23T19:46:14Z" + createdAt: "2025-07-15T04:30:14Z" description: Deploys any runtime component with dynamic and auto-tuning configuration features.operators.openshift.io/disconnected: "true" features.operators.openshift.io/fips-compliant: "true" diff --git a/common/config.go b/common/config.go index 5d0d413e..c40f94e8 100644 --- a/common/config.go +++ b/common/config.go @@ -3,6 +3,7 @@ package common import ( "errors" "strconv" + "strings" "sync" uberzap "go.uber.org/zap" @@ -59,6 +60,9 @@ const ( // OpConfigShowReconcileInterval default whether reconcile interval will be visible in the instance's status field OpConfigShowReconcileInterval = "showReconcileInterval" + + // OpConfigDelayReconcile list of instances/namespaces with delayed reconciliation + OpConfigDelayReconcile = "delayReconcile" ) // Config stores operator configuration @@ -108,6 +112,34 @@ func LoadFromConfig(oc *sync.Map, key string) string { return value.(string) } +// Checks if the instance / namespace exists in delay reconcile list +func CheckDelayReconcile(oc *sync.Map, key string, name string, namespace string, OperatorName string) (bool, error) { + value := LoadFromConfig(oc, key) + lines := strings.Split(value, "\n") + + nsFound := false + + for _, line := range lines { + if strings.Contains(line, ":") { + ns := strings.TrimRight(line, ":") + if namespace == ns { + nsFound = true + } else { + nsFound = false + } + } else if nsFound && strings.Contains(line, "- ") { + instance := strings.TrimLeft(line, "- ") + if instance == "*" || instance == name { + return true, nil + } + } else if !strings.Contains(line, ":") && !strings.Contains(line, "- ") { + return false, errors.New("delayReconcile syntax error in ConfigMap: " + OperatorName + ".") + } + } + + return false, nil +} + func CheckValidValue(oc *sync.Map, key string, OperatorName string) error { value := LoadFromConfig(oc, key) diff --git a/internal/controller/runtimecomponent_controller.go b/internal/controller/runtimecomponent_controller.go index 59c0546a..81feee97 100644 --- a/internal/controller/runtimecomponent_controller.go +++ b/internal/controller/runtimecomponent_controller.go @@ -124,6 +124,17 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req return reconcile.Result{}, err } + // If the instance was already reconciled and is waiting for operator version upgrade + if instance.Status.Versions.Reconciled != "" && instance.Status.Versions.Reconciled != appstacksutils.RCOOperandVersion { + // If the instance / namespace is listed under delayReconcile in ConfigMap, skip and delay reconciliation + delay, err := common.CheckDelayReconcile(common.Config, common.OpConfigDelayReconcile, req.Name, req.Namespace, OperatorName) + if err != nil { + return r.ManageError(err, common.StatusConditionTypeReconciled, instance) + } else if delay { + return r.ManageSuccess(common.StatusConditionTypeReconciled, instance) + } + } + if err = common.CheckValidValue(common.Config, common.OpConfigReconcileIntervalMinimum, OperatorName); err != nil { return r.ManageError(err, common.StatusConditionTypeReconciled, instance) }