From 9aab6c0c97369724d860858f0efbca134669d2d0 Mon Sep 17 00:00:00 2001 From: Drew Minnear Date: Wed, 5 Nov 2025 13:46:07 -0500 Subject: [PATCH] update pattern deletion logic this commit includes two key changes: 1. A sync with prune is triggered to remove all applications part of the pattern BEFORE the subscriptions and other resources are deleted to prevent applications from becoming undeleteable if CRs, webhooks, etc disappear. 2. Subscription for openshift-gitops is no longer owned by pattern instances. Previously, deleting a pattern would delete this subscription and a new subscription would not be able to be created on the reinstall of a pattern since the CSV still existed. The subscription is necessary since it sets the env var ARGOCD_CLUSTER_CONFIG_NAMESPACES to '*'. Without the subscription the ArgoCD instance created by the new pattern would be created in namespaced mode and many charts like vault will not install since they try to create clusterwide resources like clusterrolebindings --- internal/controller/argo.go | 15 +++++++++++++++ internal/controller/pattern_controller.go | 11 +++++++---- internal/controller/subscription.go | 1 + 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/internal/controller/argo.go b/internal/controller/argo.go index a25fa0e20..2caa8264e 100644 --- a/internal/controller/argo.go +++ b/internal/controller/argo.go @@ -961,3 +961,18 @@ func updateHelmParameter(goal api.PatternParameter, actual []argoapi.HelmParamet } return false } + +func syncApplicationWithPrune(client argoclient.Interface, app *argoapi.Application, namespace string) error { + app.Operation = &argoapi.Operation{ + Sync: &argoapi.SyncOperation{ + Prune: true, + }, + } + + _, err := client.ArgoprojV1alpha1().Applications(namespace).Update(context.Background(), app, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("failed to sync application %q with prune: %w", app.Name, err) + } + + return nil +} diff --git a/internal/controller/pattern_controller.go b/internal/controller/pattern_controller.go index a7230d8b8..625492d04 100644 --- a/internal/controller/pattern_controller.go +++ b/internal/controller/pattern_controller.go @@ -162,13 +162,11 @@ func (r *PatternReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct // -- GitOps Subscription targetSub, _ := newSubscriptionFromConfigMap(r.fullClient) - _ = controllerutil.SetOwnerReference(qualifiedInstance, targetSub, r.Scheme) - sub, _ := getSubscription(r.olmClient, targetSub.Name) if sub == nil { err = createSubscription(r.olmClient, targetSub) return r.actionPerformed(qualifiedInstance, "create gitops subscription", err) - } else if ownedBySame(targetSub, sub) { + } else if owner, ok := sub.Labels["app.kubernetes.io/managed-by"]; ok && owner == "patterns-operator" { // Check version/channel etc // Dangerous if multiple patterns do not agree, or automatic upgrades are in place... changed, errSub := updateSubscription(r.olmClient, targetSub, sub) @@ -528,6 +526,10 @@ func (r *PatternReconciler) finalizeObject(instance *api.Pattern) error { return fmt.Errorf("updated application %q for removal", app.Name) } + if err := syncApplicationWithPrune(r.argoClient, app, ns); err != nil { + return err + } + if haveACMHub(r) { return fmt.Errorf("waiting for removal of that acm hub") } @@ -604,7 +606,8 @@ func (r *PatternReconciler) onReconcileErrorWithRequeue(p *api.Pattern, reason s } if duration != nil { log.Printf("Requeueing\n") - return reconcile.Result{RequeueAfter: *duration}, err + // Return nil error when we have a duration to avoid exponential backoff + return reconcile.Result{RequeueAfter: *duration}, nil } return reconcile.Result{}, err } diff --git a/internal/controller/subscription.go b/internal/controller/subscription.go index c099d48c9..32ba0083d 100644 --- a/internal/controller/subscription.go +++ b/internal/controller/subscription.go @@ -73,6 +73,7 @@ func newSubscriptionFromConfigMap(r kubernetes.Interface) (*operatorv1alpha1.Sub ObjectMeta: metav1.ObjectMeta{ Name: GitOpsDefaultPackageName, Namespace: SubscriptionNamespace, + Labels: map[string]string{"app.kubernetes.io/managed-by": "patterns-operator"}, }, Spec: spec, }