Skip to content
This repository was archived by the owner on Jun 26, 2023. It is now read-only.

Commit 4b8e7a2

Browse files
authored
Merge pull request #1150 from adrianludwin/subns-conflict
Don't delete subns if anchor has conflict
2 parents 6f44c1c + d6d4a2d commit 4b8e7a2

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

incubator/hnc/internal/reconcilers/anchor.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ package reconcilers
1717

1818
import (
1919
"context"
20+
"errors"
2021

2122
"github.com/go-logr/logr"
2223
corev1 "k8s.io/api/core/v1"
23-
"k8s.io/apimachinery/pkg/api/errors"
24+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2425
"k8s.io/apimachinery/pkg/types"
2526
ctrl "sigs.k8s.io/controller-runtime"
2627
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -65,7 +66,7 @@ func (r *AnchorReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
6566
// purged.
6667
inst, err := r.getInstance(ctx, pnm, nm)
6768
if err != nil {
68-
if errors.IsNotFound(err) {
69+
if apierrors.IsNotFound(err) {
6970
return ctrl.Result{}, nil
7071
}
7172
return ctrl.Result{}, err
@@ -118,13 +119,19 @@ func (r *AnchorReconciler) onDeleting(ctx context.Context, log logr.Logger, inst
118119
return false, err
119120
}
120121

122+
// Update the state of the anchor
123+
//
124+
// TODO: call this in the parent function after v0.5 so there's no special code path for the
125+
// onDeleting case.
126+
r.updateState(log, inst, snsInst)
127+
121128
log.Info("The anchor is being deleted", "deletingCRD", deletingCRD)
122129
switch {
123130
case len(inst.ObjectMeta.Finalizers) == 0:
124131
// We've finished processing this, nothing to do.
125132
log.Info("Do nothing since the finalizers are already gone.")
126133
return true, nil
127-
case r.shouldDeleteSubns(inst, snsInst, deletingCRD):
134+
case r.shouldDeleteSubns(log, inst, snsInst, deletingCRD):
128135
// The subnamespace is not already being deleted but it allows cascadingDelete or it's a leaf.
129136
// Delete the subnamespace, unless the CRD is being deleted, in which case, we want to leave the
130137
// namespaces alone.
@@ -143,7 +150,9 @@ func (r *AnchorReconciler) onDeleting(ctx context.Context, log logr.Logger, inst
143150

144151
// shouldDeleteSubns returns true if the namespace still exists and it is a leaf
145152
// subnamespace or it allows cascading delete unless the CRD is being deleted.
146-
func (r *AnchorReconciler) shouldDeleteSubns(inst *api.SubnamespaceAnchor, nsInst *corev1.Namespace, deletingCRD bool) bool {
153+
//
154+
// TODO: fix comment post-v0.5
155+
func (r *AnchorReconciler) shouldDeleteSubns(log logr.Logger, inst *api.SubnamespaceAnchor, nsInst *corev1.Namespace, deletingCRD bool) bool {
147156
r.forest.Lock()
148157
defer r.forest.Unlock()
149158

@@ -152,6 +161,27 @@ func (r *AnchorReconciler) shouldDeleteSubns(inst *api.SubnamespaceAnchor, nsIns
152161
return false
153162
}
154163

164+
// If the anchor isn't in the "ok" state, don't delete the namespace. If it's "conflict," we
165+
// *definitely* don't want to delete it; if it's missing (and possibly being created), then there
166+
// isn't really a good option but we'll eventually put a condition on the namespace so it's not a
167+
// big deal.
168+
//
169+
// TODO: much of the remaining portion of this function can probably be replaced by this switch
170+
// statement. In v0.5, we're playing it safe so I won't modify the rest of the function, but in
171+
// v0.6 we should restructure.
172+
switch inst.Status.State {
173+
case api.Missing:
174+
return false
175+
case api.Conflict:
176+
return false
177+
case api.Ok:
178+
// keep going...
179+
default:
180+
log.Error(errors.New("Illegal state"), "Unknown state", "state", inst.Status.State)
181+
// Stay on the safe side - don't delete
182+
return false
183+
}
184+
155185
cnm := inst.Name
156186
pnm := inst.Namespace
157187
cns := r.forest.Get(cnm)
@@ -259,7 +289,7 @@ func (r *AnchorReconciler) getNamespace(ctx context.Context, nm string) (*corev1
259289
ns := &corev1.Namespace{}
260290
nnm := types.NamespacedName{Name: nm}
261291
if err := r.Get(ctx, nnm, ns); err != nil {
262-
if !errors.IsNotFound(err) {
292+
if !apierrors.IsNotFound(err) {
263293
return nil, err
264294
}
265295
return &corev1.Namespace{}, nil

incubator/hnc/test/e2e/issues_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ var _ = Describe("Issues", func() {
3131
nsSubSub2, nsSubChild, nsSubSubChild)
3232
})
3333

34+
It("Should not delete full namespace when a faulty anchor is deleted - issue #1149", func() {
35+
// Setup
36+
MustRun("kubectl create ns", nsParent)
37+
MustRun("kubectl hns create", nsChild, "-n", nsParent)
38+
39+
// Wait for subns
40+
MustRun("kubectl describe ns", nsChild)
41+
42+
// Remove annotation
43+
MustRun("kubectl annotate ns", nsChild, "hnc.x-k8s.io/subnamespaceOf-")
44+
RunShouldNotContain("subnamespaceOf", 1, "kubectl get -oyaml ns", nsChild)
45+
46+
// Delete anchor
47+
MustRun("kubectl delete subns", nsChild, "-n", nsParent)
48+
MustNotRun("kubectl get subns", nsChild, "-n", nsParent)
49+
50+
// Verify that namespace still exists
51+
MustRun("kubectl describe ns", nsChild)
52+
})
53+
3454
// Note that this was never actually a problem (only subnamespaces were affected) but it seems
3555
// like a good thing to test anyway.
3656
It("Should delete full namespaces with propagated objects - issue #1130", func() {

0 commit comments

Comments
 (0)