2121 - key : node-role.kubernetes.io/control-plane
2222 operator : Exists
2323 effect : " NoSchedule"
24+ securityContext :
25+ runAsNonRoot : true
26+ runAsUser : 65534
27+ runAsGroup : 65534
28+ seccompProfile :
29+ type : RuntimeDefault
2430 containers :
2531 - name : kubectl
2632 image : docker.io/clastix/kubectl:v1.32
33+ securityContext :
34+ allowPrivilegeEscalation : false
35+ readOnlyRootFilesystem : true
36+ capabilities :
37+ drop : ["ALL"]
38+ env :
39+ - name : HOME
40+ value : /tmp
41+ resources :
42+ requests :
43+ cpu : 10m
44+ memory : 64Mi
45+ limits :
46+ cpu : 200m
47+ memory : 128Mi
2748 command :
2849 - /bin/sh
2950 - -c
4869 kubectl -n {{ .Release.Namespace }} delete kamajicontrolplanes.controlplane.cluster.x-k8s.io {{ .Release.Name }} \
4970 --ignore-not-found=true
5071
51- echo "Step 4: Deleting TenantControlPlane {{ .Release.Name }}"
72+ echo "Step 4: Deleting TenantControlPlane {{ .Release.Name }} and waiting for it to be removed"
73+ # --wait=true blocks until the TenantControlPlane object is fully
74+ # gone. This is required so that Kamaji's TCP finalizer-cleanup
75+ # chain (which strips finalizer.kamaji.clastix.io/datastore-secret
76+ # off the <release>-datastore-config Secret) has a chance to run
77+ # before we fall through to Step 4b. A short --timeout keeps the
78+ # hook from hanging forever if Kamaji is unreachable; Step 4b is
79+ # the backstop for that case.
5280 kubectl -n {{ .Release.Namespace }} delete tenantcontrolplanes.kamaji.clastix.io {{ .Release.Name }} \
53- --ignore-not-found=true
81+ --ignore-not-found=true --wait=true --timeout=120s \
82+ || echo "WARNING: TenantControlPlane {{ .Release.Name }} did not delete within timeout; relying on the Step 4b finalizer backstop" >&2
83+
84+ echo "Step 4b: Clearing leftover Kamaji datastore-secret finalizer on {{ .Release.Name }}-datastore-config"
85+ # Kamaji creates a per-tenant datastore connection Secret named
86+ # <tcp-name>-datastore-config (tcp-name == .Release.Name) and adds
87+ # the finalizer "finalizer.kamaji.clastix.io/datastore-secret" to
88+ # it. That finalizer is normally removed by Kamaji as part of the
89+ # TenantControlPlane deletion above. If the TCP was force-deleted,
90+ # or Kamaji did not reconcile the removal in time, the finalizer
91+ # stays on the Secret and blocks deletion of the entire namespace
92+ # (the Secret cannot be garbage-collected, see issue #3062).
93+ #
94+ # By this point the TenantControlPlane is gone (Step 4 waited for
95+ # it), so Kamaji no longer has any legitimate use for this Secret:
96+ # the Secret has an ownerReference to the now-deleted TCP and is
97+ # only awaiting garbage collection. Stripping the finalizer here is
98+ # therefore safe and merely lets the GC reap it. We only patch the
99+ # finalizers field of this one named Secret.
100+ # Only clear the finalizer if the TenantControlPlane is actually gone.
101+ # Step 4 may have timed out with the TCP still present; in that case
102+ # Kamaji still legitimately owns the datastore Secret, and stripping
103+ # the finalizer would interfere with its lifecycle management. Gate
104+ # the patch on the TCP being confirmed absent (CodeRabbit #3078).
105+ if kubectl -n {{ .Release.Namespace }} get tenantcontrolplanes.kamaji.clastix.io {{ .Release.Name }} >/dev/null 2>&1; then
106+ echo " TenantControlPlane {{ .Release.Name }} still present (deletion not complete); leaving the datastore-secret finalizer untouched"
107+ elif kubectl -n {{ .Release.Namespace }} get secret {{ .Release.Name }}-datastore-config >/dev/null 2>&1; then
108+ echo " Removing finalizers from secret/{{ .Release.Name }}-datastore-config"
109+ kubectl -n {{ .Release.Namespace }} patch secret {{ .Release.Name }}-datastore-config \
110+ --type=merge -p '{"metadata":{"finalizers":null}}' \
111+ || echo "WARNING: failed to clear datastore-secret finalizer for {{ .Release.Name }}; the namespace may stay in Terminating (issue #3062)" >&2
112+ else
113+ echo " Secret {{ .Release.Name }}-datastore-config not present; nothing to do"
114+ fi
54115
55116 echo "Step 5: Cleaning up DataVolumes"
56117 kubectl -n {{ .Release.Namespace }} delete datavolumes \
@@ -64,7 +125,12 @@ spec:
64125 --ignore-not-found=true
65126
66127 echo "Cleanup completed successfully"
67-
128+ volumeMounts :
129+ - name : tmp
130+ mountPath : /tmp
131+ volumes :
132+ - name : tmp
133+ emptyDir : {}
68134---
69135apiVersion : v1
70136kind : ServiceAccount
@@ -130,6 +196,18 @@ rules:
130196 - list
131197 - watch
132198 - delete
199+ # Scoped to the single Kamaji datastore connection Secret so Step 4b can
200+ # strip the leftover finalizer.kamaji.clastix.io/datastore-secret finalizer
201+ # (issue #3062). resourceNames limits get/patch to exactly this Secret.
202+ - apiGroups :
203+ - " "
204+ resources :
205+ - secrets
206+ resourceNames :
207+ - {{ .Release.Name }}-datastore-config
208+ verbs :
209+ - get
210+ - patch
133211---
134212apiVersion : rbac.authorization.k8s.io/v1
135213kind : RoleBinding
0 commit comments