Skip to content

Commit 747f2fe

Browse files
pkg/helm/controller/reconcile.go: finalizer fix (#3046)
This PR fixes a bug in the helm operator that caused the CR to be unable to be deleted without manually intervening to delete a prematurely added finalizer. Helm operator now applies its uninstall finalizer only when a release is deployed. Co-authored-by: Joe Lanford <[email protected]>
1 parent ce634ef commit 747f2fe

File tree

3 files changed

+54
-45
lines changed

3 files changed

+54
-45
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
entries:
2+
- description: >
3+
Helm operator now applies its uninstall finalizer only when
4+
a release is deployed. This fixes a bug that caused the
5+
CR to be unable to be deleted without manually intervening
6+
to delete a prematurely added finalizer.
7+
kind: bugfix

pkg/helm/controller/controller.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import (
3636

3737
"github.com/operator-framework/operator-sdk/pkg/helm/release"
3838
"github.com/operator-framework/operator-sdk/pkg/internal/predicates"
39-
"github.com/operator-framework/operator-sdk/pkg/predicate"
4039
)
4140

4241
var log = logf.Log.WithName("helm.controller")
@@ -80,8 +79,7 @@ func Add(mgr manager.Manager, options WatchOptions) error {
8079

8180
o := &unstructured.Unstructured{}
8281
o.SetGroupVersionKind(options.GVK)
83-
if err := c.Watch(&source.Kind{Type: o}, &crthandler.EnqueueRequestForObject{},
84-
predicate.GenerationChangedPredicate{}); err != nil {
82+
if err := c.Watch(&source.Kind{Type: o}, &crthandler.EnqueueRequestForObject{}); err != nil {
8583
return err
8684
}
8785

pkg/helm/controller/reconcile.go

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ import (
2929
"k8s.io/apimachinery/pkg/runtime/schema"
3030
"k8s.io/apimachinery/pkg/util/wait"
3131
"k8s.io/client-go/tools/record"
32+
"k8s.io/client-go/util/retry"
3233
"sigs.k8s.io/controller-runtime/pkg/client"
34+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3335
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3436

3537
"github.com/operator-framework/operator-sdk/internal/util/diffutil"
@@ -94,38 +96,8 @@ func (r HelmOperatorReconciler) Reconcile(request reconcile.Request) (reconcile.
9496
status := types.StatusFor(o)
9597
log = log.WithValues("release", manager.ReleaseName())
9698

97-
deleted := o.GetDeletionTimestamp() != nil
98-
pendingFinalizers := o.GetFinalizers()
99-
if !deleted && !contains(pendingFinalizers, finalizer) {
100-
log.V(1).Info("Adding finalizer", "finalizer", finalizer)
101-
finalizers := append(pendingFinalizers, finalizer)
102-
o.SetFinalizers(finalizers)
103-
err = r.updateResource(o)
104-
105-
// Need to requeue because finalizer update does not change metadata.generation
106-
return reconcile.Result{Requeue: true}, err
107-
}
108-
109-
status.SetCondition(types.HelmAppCondition{
110-
Type: types.ConditionInitialized,
111-
Status: types.StatusTrue,
112-
})
113-
114-
if err := manager.Sync(context.TODO()); err != nil {
115-
log.Error(err, "Failed to sync release")
116-
status.SetCondition(types.HelmAppCondition{
117-
Type: types.ConditionIrreconcilable,
118-
Status: types.StatusTrue,
119-
Reason: types.ReasonReconcileError,
120-
Message: err.Error(),
121-
})
122-
_ = r.updateResourceStatus(o, status)
123-
return reconcile.Result{}, err
124-
}
125-
status.RemoveCondition(types.ConditionIrreconcilable)
126-
127-
if deleted {
128-
if !contains(pendingFinalizers, finalizer) {
99+
if o.GetDeletionTimestamp() != nil {
100+
if !contains(o.GetFinalizers(), finalizer) {
129101
log.Info("Resource is terminated, skipping reconciliation")
130102
return reconcile.Result{}, nil
131103
}
@@ -163,13 +135,7 @@ func (r HelmOperatorReconciler) Reconcile(request reconcile.Request) (reconcile.
163135
return reconcile.Result{}, err
164136
}
165137

166-
finalizers := []string{}
167-
for _, pendingFinalizer := range pendingFinalizers {
168-
if pendingFinalizer != finalizer {
169-
finalizers = append(finalizers, pendingFinalizer)
170-
}
171-
}
172-
o.SetFinalizers(finalizers)
138+
controllerutil.RemoveFinalizer(o, finalizer)
173139
if err := r.updateResource(o); err != nil {
174140
log.Info("Failed to remove CR uninstall finalizer")
175141
return reconcile.Result{}, err
@@ -187,6 +153,24 @@ func (r HelmOperatorReconciler) Reconcile(request reconcile.Request) (reconcile.
187153
return reconcile.Result{}, nil
188154
}
189155

156+
status.SetCondition(types.HelmAppCondition{
157+
Type: types.ConditionInitialized,
158+
Status: types.StatusTrue,
159+
})
160+
161+
if err := manager.Sync(context.TODO()); err != nil {
162+
log.Error(err, "Failed to sync release")
163+
status.SetCondition(types.HelmAppCondition{
164+
Type: types.ConditionIrreconcilable,
165+
Status: types.StatusTrue,
166+
Reason: types.ReasonReconcileError,
167+
Message: err.Error(),
168+
})
169+
_ = r.updateResourceStatus(o, status)
170+
return reconcile.Result{}, err
171+
}
172+
status.RemoveCondition(types.ConditionIrreconcilable)
173+
190174
if !manager.IsInstalled() {
191175
for k, v := range r.OverrideValues {
192176
r.EventRecorder.Eventf(o, "Warning", "OverrideValuesInUse",
@@ -206,6 +190,13 @@ func (r HelmOperatorReconciler) Reconcile(request reconcile.Request) (reconcile.
206190
}
207191
status.RemoveCondition(types.ConditionReleaseFailed)
208192

193+
log.V(1).Info("Adding finalizer", "finalizer", finalizer)
194+
controllerutil.AddFinalizer(o, finalizer)
195+
if err := r.updateResource(o); err != nil {
196+
log.Info("Failed to add CR uninstall finalizer")
197+
return reconcile.Result{}, err
198+
}
199+
209200
if r.releaseHook != nil {
210201
if err := r.releaseHook(installedRelease); err != nil {
211202
log.Error(err, "Failed to run release hook")
@@ -236,6 +227,15 @@ func (r HelmOperatorReconciler) Reconcile(request reconcile.Request) (reconcile.
236227
return reconcile.Result{RequeueAfter: r.ReconcilePeriod}, err
237228
}
238229

230+
if !contains(o.GetFinalizers(), finalizer) {
231+
log.V(1).Info("Adding finalizer", "finalizer", finalizer)
232+
controllerutil.AddFinalizer(o, finalizer)
233+
if err := r.updateResource(o); err != nil {
234+
log.Info("Failed to add CR uninstall finalizer")
235+
return reconcile.Result{}, err
236+
}
237+
}
238+
239239
if manager.IsUpdateRequired() {
240240
for k, v := range r.OverrideValues {
241241
r.EventRecorder.Eventf(o, "Warning", "OverrideValuesInUse",
@@ -343,12 +343,16 @@ func hasHelmUpgradeForceAnnotation(o *unstructured.Unstructured) bool {
343343
}
344344

345345
func (r HelmOperatorReconciler) updateResource(o runtime.Object) error {
346-
return r.Client.Update(context.TODO(), o)
346+
return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
347+
return r.Client.Update(context.TODO(), o)
348+
})
347349
}
348350

349351
func (r HelmOperatorReconciler) updateResourceStatus(o *unstructured.Unstructured, status *types.HelmAppStatus) error {
350-
o.Object["status"] = status
351-
return r.Client.Status().Update(context.TODO(), o)
352+
return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
353+
o.Object["status"] = status
354+
return r.Client.Status().Update(context.TODO(), o)
355+
})
352356
}
353357

354358
func (r HelmOperatorReconciler) waitForDeletion(o runtime.Object) error {

0 commit comments

Comments
 (0)