Skip to content

Commit 185c46b

Browse files
authored
Merge pull request kubernetes-retired#203 from erikgb/improve/finalizers
Refactor adding/removing/contains finalizers
2 parents ae70162 + 811b9aa commit 185c46b

File tree

2 files changed

+31
-33
lines changed

2 files changed

+31
-33
lines changed

internal/anchor/reconciler.go

+20-23
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"k8s.io/apimachinery/pkg/types"
2727
ctrl "sigs.k8s.io/controller-runtime"
2828
"sigs.k8s.io/controller-runtime/pkg/client"
29+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2930
"sigs.k8s.io/controller-runtime/pkg/event"
3031
"sigs.k8s.io/controller-runtime/pkg/handler"
3132
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -81,9 +82,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
8182
// Anchors in unmanaged namespace should be ignored. Make sure it
8283
// doesn't have any finalizers, otherwise, leave it alone.
8384
if why := config.WhyUnmanaged(pnm); why != "" {
84-
if len(inst.ObjectMeta.Finalizers) > 0 {
85+
if controllerutil.ContainsFinalizer(inst, api.MetaGroup) {
8586
log.Info("Removing finalizers from anchor in unmanaged namespace", "reason", why)
86-
inst.ObjectMeta.Finalizers = nil
87+
controllerutil.RemoveFinalizer(inst, api.MetaGroup)
8788
return ctrl.Result{}, r.writeInstance(ctx, log, inst)
8889
}
8990
return ctrl.Result{}, nil
@@ -94,10 +95,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
9495
// been bypassed and the anchor has been successfully created. Forbidden
9596
// anchors won't have finalizers.
9697
if why := config.WhyUnmanaged(nm); why != "" {
97-
if inst.Status.State != api.Forbidden || len(inst.ObjectMeta.Finalizers) > 0 {
98+
if inst.Status.State != api.Forbidden || controllerutil.ContainsFinalizer(inst, api.MetaGroup) {
9899
log.Info("Setting forbidden state on anchor with unmanaged name", "reason", why)
99100
inst.Status.State = api.Forbidden
100-
inst.ObjectMeta.Finalizers = nil
101+
controllerutil.RemoveFinalizer(inst, api.MetaGroup)
101102
return ctrl.Result{}, r.writeInstance(ctx, log, inst)
102103
}
103104
return ctrl.Result{}, nil
@@ -113,9 +114,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
113114
r.updateState(log, inst, snsInst)
114115

115116
// Handle the case where the anchor is being deleted.
116-
if deleting, err := r.onDeleting(ctx, log, inst, snsInst); deleting {
117-
return ctrl.Result{}, err
117+
if !inst.DeletionTimestamp.IsZero() {
118+
// Stop reconciliation as anchor is being deleted
119+
return ctrl.Result{}, r.onDeleting(ctx, log, inst, snsInst)
118120
}
121+
// Add finalizers on all non-forbidden anchors to ensure it's not deleted until
122+
// after the subnamespace is deleted.
123+
controllerutil.AddFinalizer(inst, api.MetaGroup)
119124

120125
// If the subnamespace doesn't exist, create it.
121126
if inst.Status.State == api.Missing {
@@ -130,9 +135,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
130135
}
131136
}
132137

133-
// Add finalizers on all non-forbidden anchors to ensure it's not deleted until
134-
// after the subnamespace is deleted.
135-
inst.ObjectMeta.Finalizers = []string{api.MetaGroup}
136138
return ctrl.Result{}, r.writeInstance(ctx, log, inst)
137139
}
138140

@@ -145,19 +147,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
145147
// There are several conditions where we skip step 1 - for example, if we're uninstalling HNC, or
146148
// if allowCascadingDeletion is disabled but the subnamespace has descendants (see
147149
// shouldDeleteSubns for details). In such cases, we move straight to step 2.
148-
func (r *Reconciler) onDeleting(ctx context.Context, log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) (bool, error) {
149-
// Early exit and continue reconciliation if the instance is not being deleted.
150-
if inst.DeletionTimestamp.IsZero() {
151-
return false, nil
152-
}
153-
150+
func (r *Reconciler) onDeleting(ctx context.Context, log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) error {
154151
// We handle deletions differently depending on whether _one_ anchor is being deleted (i.e., the
155152
// user wants to delete the namespace) or whether the Anchor CRD is being deleted, which usually
156153
// means HNC is being uninstalled and we shouldn't delete _any_ namespaces.
157154
deletingCRD, err := crd.IsDeletingCRD(ctx, api.Anchors)
158155
if err != nil {
159156
log.Error(err, "Couldn't determine if CRD is being deleted")
160-
return false, err
157+
return err
161158
}
162159
log.V(1).Info("Anchor is being deleted", "deletingCRD", deletingCRD)
163160

@@ -166,21 +163,21 @@ func (r *Reconciler) onDeleting(ctx context.Context, log logr.Logger, inst *api.
166163
switch {
167164
case r.shouldDeleteSubns(log, inst, snsInst, deletingCRD):
168165
log.Info("Deleting subnamespace due to anchor being deleted")
169-
return true, r.deleteNamespace(ctx, log, snsInst)
166+
return r.deleteNamespace(ctx, log, snsInst)
170167
case r.shouldFinalizeAnchor(log, inst, snsInst):
171168
log.V(1).Info("Unblocking deletion") // V(1) since we'll very shortly show an "anchor deleted" message
172-
inst.ObjectMeta.Finalizers = nil
173-
return true, r.writeInstance(ctx, log, inst)
169+
controllerutil.RemoveFinalizer(inst, api.MetaGroup)
170+
return r.writeInstance(ctx, log, inst)
174171
default:
175172
// There's nothing to do; we're just waiting for something to happen. Print out a log message
176173
// indicating what we're waiting for.
177-
if len(inst.ObjectMeta.Finalizers) > 0 {
174+
if controllerutil.ContainsFinalizer(inst, api.MetaGroup) {
178175
log.Info("Waiting for subnamespace to be fully purged before letting the anchor be deleted")
179176
} else {
180177
// I doubt we'll ever get here but I suppose it's possible
181178
log.Info("Waiting for K8s to delete this anchor (all finalizers are removed)")
182179
}
183-
return true, nil
180+
return nil
184181
}
185182
}
186183

@@ -213,7 +210,7 @@ func (r *Reconciler) shouldDeleteSubns(log logr.Logger, inst *api.SubnamespaceAn
213210
log.V(1).Info("The subnamespace is already being deleted; no need to delete again")
214211
return false
215212
}
216-
if len(inst.ObjectMeta.Finalizers) == 0 {
213+
if !controllerutil.ContainsFinalizer(inst, api.MetaGroup) {
217214
log.V(1).Info("The anchor has already been finalized; do not reconsider deleting the namespace")
218215
return false
219216
}
@@ -257,7 +254,7 @@ func (r *Reconciler) shouldDeleteSubns(log logr.Logger, inst *api.SubnamespaceAn
257254
// deleted, it's in the process of being deleted, etc).
258255
func (r *Reconciler) shouldFinalizeAnchor(log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) bool {
259256
// If the anchor is already finalized, there's no need to do it again.
260-
if len(inst.ObjectMeta.Finalizers) == 0 {
257+
if !controllerutil.ContainsFinalizer(inst, api.MetaGroup) {
261258
return false
262259
}
263260

internal/hierarchyconfig/reconciler.go

+11-10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
ctrl "sigs.k8s.io/controller-runtime"
3131
"sigs.k8s.io/controller-runtime/pkg/client"
3232
"sigs.k8s.io/controller-runtime/pkg/controller"
33+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3334
"sigs.k8s.io/controller-runtime/pkg/event"
3435
"sigs.k8s.io/controller-runtime/pkg/handler"
3536
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -133,9 +134,9 @@ func (r *Reconciler) handleUnmanaged(ctx context.Context, log logr.Logger, nm st
133134
// Remove the finalizers if there are any. Note that while getSingleton can return an invalid
134135
// object (i.e. one without a name or namespace, if there's no singleton on the server), it can
135136
// never do that if there are finalizers or children so this is safe to write back.
136-
if len(inst.ObjectMeta.Finalizers) > 0 || len(inst.Status.Children) > 0 {
137+
if controllerutil.ContainsFinalizer(inst, api.FinalizerHasSubnamespace) || len(inst.Status.Children) > 0 {
137138
log.Info("Removing finalizers and children on unmanaged singleton")
138-
inst.ObjectMeta.Finalizers = nil
139+
controllerutil.RemoveFinalizer(inst, api.FinalizerHasSubnamespace)
139140
inst.Status.Children = nil
140141
stats.WriteHierConfig()
141142
if err := r.Update(ctx, inst); err != nil {
@@ -241,27 +242,27 @@ func (r *Reconciler) addIncludedNamespaceLabel(log logr.Logger, nsInst *corev1.N
241242
// .spec.allowCascadingDeletion field, so if we allowed this object to be deleted before all
242243
// descendants have been deleted, we would lose the knowledge that cascading deletion is enabled.
243244
func (r *Reconciler) updateFinalizers(log logr.Logger, inst *api.HierarchyConfiguration, nsInst *corev1.Namespace, anms []string) {
244-
// No-one should put a finalizer on a hierarchy config except us. See
245-
// https://github.com/kubernetes-sigs/hierarchical-namespaces/issues/623 as we try to enforce that.
246245
switch {
247246
case len(anms) == 0:
248247
// There are no subnamespaces in this namespace. The HC instance can be safely deleted anytime.
249-
if len(inst.ObjectMeta.Finalizers) > 0 {
248+
if controllerutil.ContainsFinalizer(inst, api.FinalizerHasSubnamespace) {
250249
log.V(1).Info("Removing finalizers since there are no longer any anchors in the namespace.")
250+
controllerutil.RemoveFinalizer(inst, api.FinalizerHasSubnamespace)
251251
}
252-
inst.ObjectMeta.Finalizers = nil
253252
case !inst.DeletionTimestamp.IsZero() && nsInst.DeletionTimestamp.IsZero():
254253
// If the HC instance is being deleted but not the namespace (which means
255254
// it's not a cascading delete), remove the finalizers to let it go through.
256255
// This is the only case the finalizers can be removed even when the
257256
// namespace has subnamespaces. (A default HC will be recreated later.)
258-
log.Info("Removing finalizers to allow a single deletion of the singleton (not involved in a cascading deletion).")
259-
inst.ObjectMeta.Finalizers = nil
257+
if controllerutil.ContainsFinalizer(inst, api.FinalizerHasSubnamespace) {
258+
log.Info("Removing finalizers to allow a single deletion of the singleton (not involved in a cascading deletion).")
259+
controllerutil.RemoveFinalizer(inst, api.FinalizerHasSubnamespace)
260+
}
260261
default:
261-
if len(inst.ObjectMeta.Finalizers) == 0 {
262+
if !controllerutil.ContainsFinalizer(inst, api.FinalizerHasSubnamespace) {
262263
log.Info("Adding finalizers since there's at least one anchor in the namespace.")
264+
controllerutil.AddFinalizer(inst, api.FinalizerHasSubnamespace)
263265
}
264-
inst.ObjectMeta.Finalizers = []string{api.FinalizerHasSubnamespace}
265266
}
266267
}
267268

0 commit comments

Comments
 (0)