From 81f685b6f16c3bb621a6608437744def4a89d090 Mon Sep 17 00:00:00 2001 From: Mario Manno Date: Wed, 24 Sep 2025 15:17:49 +0200 Subject: [PATCH] Explicitly delete bundle secrets on bundle deletion (#4146) * Explicitly delete bundle secrets on bundle deletion * Update owner reference when updating values/options secret --- internal/cmd/cli/apply/apply.go | 1 + .../reconciler/bundle_controller.go | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/internal/cmd/cli/apply/apply.go b/internal/cmd/cli/apply/apply.go index cac28199a1..ca978b0864 100644 --- a/internal/cmd/cli/apply/apply.go +++ b/internal/cmd/cli/apply/apply.go @@ -420,6 +420,7 @@ func writeBundle(ctx context.Context, c client.Client, r record.EventRecorder, b valuesSecret := newValuesSecret(bundle, data) updated := valuesSecret.DeepCopy() _, err = controllerutil.CreateOrUpdate(ctx, c, valuesSecret, func() error { + valuesSecret.OwnerReferences = updated.OwnerReferences valuesSecret.Labels = updated.Labels valuesSecret.Data = updated.Data valuesSecret.Type = updated.Type diff --git a/internal/cmd/controller/reconciler/bundle_controller.go b/internal/cmd/controller/reconciler/bundle_controller.go index 068c933060..909098af0a 100644 --- a/internal/cmd/controller/reconciler/bundle_controller.go +++ b/internal/cmd/controller/reconciler/bundle_controller.go @@ -37,6 +37,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/record" + "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -447,6 +448,11 @@ func (r *BundleReconciler) handleDelete(ctx context.Context, logger logr.Logger, return ctrl.Result{}, err } + // pro-actively delete the bundle's secret. k8s owner garbage collection will handle remaining orphans. + if err := r.Delete(ctx, &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: bundle.Name, Namespace: bundle.Namespace}}); err != nil && !apierrors.IsNotFound(err) { + logger.V(1).Info("Cannot delete bundle's values secret, owner garbage collection will remove it") + } + return ctrl.Result{}, r.maybeDeleteOCIArtifact(ctx, bundle) } @@ -552,12 +558,19 @@ func (r *BundleReconciler) createOptionsSecret(ctx context.Context, bd *fleet.Bu Namespace: bd.Namespace, }, } - - if err := controllerutil.SetControllerReference(bd, secret, r.Scheme); err != nil { - return err + owners := []metav1.OwnerReference{ + { + APIVersion: fleet.SchemeGroupVersion.String(), + Kind: "BundleDeployment", + Name: bd.GetName(), + UID: bd.GetUID(), + BlockOwnerDeletion: ptr.To(true), + Controller: ptr.To(true), + }, } if _, err := controllerutil.CreateOrUpdate(ctx, r.Client, secret, func() error { + secret.OwnerReferences = owners secret.Data = map[string][]byte{ helmvalues.ValuesKey: options, helmvalues.StagedValuesKey: stagedOptions, @@ -743,6 +756,10 @@ func batchDeleteBundleDeployments(ctx context.Context, c client.Client, list []f if err := c.Delete(ctx, &bd); client.IgnoreNotFound(err) != nil { errs = append(errs, err) } + + // k8s ownership garbage collection can take a long time, so we explicitly delete the secrets here. + // GC will delete any remaining orphaned secrets, no need to add an error. + _ = c.Delete(ctx, &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: bd.Name, Namespace: bd.Namespace}}) } return errors.Join(errs...)