Skip to content

Commit 8ca015a

Browse files
AlexsJonesclaude
andcommitted
fix: strip finalizers before controller deletion to prevent stuck resources
Move finalizer stripping before controller/manager deletion in CLI uninstall, and add a Helm pre-delete hook Job that strips finalizers from all Sympozium CRDs before the release is torn down. This prevents skillpacks, personapacks, and other resources from hanging in Terminating state during uninstall. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fbb2cac commit 8ca015a

File tree

2 files changed

+118
-16
lines changed

2 files changed

+118
-16
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
{{- if .Values.rbac.create }}
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: sympozium-pre-delete
6+
namespace: {{ include "sympozium.namespace" . }}
7+
labels:
8+
{{- include "sympozium.labels" . | nindent 4 }}
9+
annotations:
10+
"helm.sh/hook": pre-delete
11+
"helm.sh/hook-weight": "-10"
12+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed
13+
---
14+
apiVersion: rbac.authorization.k8s.io/v1
15+
kind: ClusterRole
16+
metadata:
17+
name: {{ include "sympozium.fullname" . }}-pre-delete
18+
labels:
19+
{{- include "sympozium.labels" . | nindent 4 }}
20+
annotations:
21+
"helm.sh/hook": pre-delete
22+
"helm.sh/hook-weight": "-10"
23+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed
24+
rules:
25+
- apiGroups: ["sympozium.ai"]
26+
resources:
27+
- skillpacks
28+
- personapacks
29+
- sympoziuminstances
30+
- agentruns
31+
- sympoziumpolicies
32+
- sympoziumschedules
33+
- sympoziumconfigs
34+
verbs: ["get", "list", "patch"]
35+
- apiGroups: ["sympozium.ai"]
36+
resources:
37+
- skillpacks/finalizers
38+
- personapacks/finalizers
39+
- sympoziuminstances/finalizers
40+
- agentruns/finalizers
41+
- sympoziumpolicies/finalizers
42+
- sympoziumschedules/finalizers
43+
- sympoziumconfigs/finalizers
44+
verbs: ["update"]
45+
---
46+
apiVersion: rbac.authorization.k8s.io/v1
47+
kind: ClusterRoleBinding
48+
metadata:
49+
name: {{ include "sympozium.fullname" . }}-pre-delete
50+
labels:
51+
{{- include "sympozium.labels" . | nindent 4 }}
52+
annotations:
53+
"helm.sh/hook": pre-delete
54+
"helm.sh/hook-weight": "-10"
55+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed
56+
roleRef:
57+
apiGroup: rbac.authorization.k8s.io
58+
kind: ClusterRole
59+
name: {{ include "sympozium.fullname" . }}-pre-delete
60+
subjects:
61+
- kind: ServiceAccount
62+
name: sympozium-pre-delete
63+
namespace: {{ include "sympozium.namespace" . }}
64+
---
65+
apiVersion: batch/v1
66+
kind: Job
67+
metadata:
68+
name: sympozium-pre-delete-finalizers
69+
namespace: {{ include "sympozium.namespace" . }}
70+
labels:
71+
{{- include "sympozium.labels" . | nindent 4 }}
72+
annotations:
73+
"helm.sh/hook": pre-delete
74+
"helm.sh/hook-weight": "-5"
75+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed
76+
spec:
77+
backoffLimit: 1
78+
ttlSecondsAfterFinished: 60
79+
template:
80+
metadata:
81+
labels:
82+
app.kubernetes.io/name: sympozium-pre-delete
83+
spec:
84+
serviceAccountName: sympozium-pre-delete
85+
restartPolicy: Never
86+
containers:
87+
- name: strip-finalizers
88+
image: bitnami/kubectl:latest
89+
command:
90+
- /bin/sh
91+
- -c
92+
- |
93+
set -e
94+
RESOURCES="skillpacks.sympozium.ai personapacks.sympozium.ai sympoziuminstances.sympozium.ai agentruns.sympozium.ai sympoziumpolicies.sympozium.ai sympoziumschedules.sympozium.ai sympoziumconfigs.sympozium.ai"
95+
for res in $RESOURCES; do
96+
echo "Stripping finalizers from $res..."
97+
items=$(kubectl get "$res" --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' 2>/dev/null || true)
98+
for item in $items; do
99+
[ -z "$item" ] && continue
100+
ns="${item%%/*}"
101+
name="${item#*/}"
102+
echo " Patching $res $ns/$name"
103+
kubectl patch "$res" "$name" -n "$ns" --type=merge -p '{"metadata":{"finalizers":[]}}' 2>/dev/null || true
104+
done
105+
done
106+
echo "Done stripping finalizers."
107+
{{- end }}

cmd/sympozium/main.go

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,10 +1246,17 @@ func runInstall(ver, imageTag string) error {
12461246
func runUninstall() error {
12471247
fmt.Println(" Removing Sympozium...")
12481248

1249-
// Delete default SkillPacks from sympozium-system first (before CRDs go away).
1250-
fmt.Println(" Removing default SkillPacks...")
1251-
_ = kubectl("delete", "skillpacks.sympozium.ai", "--ignore-not-found",
1252-
"-n", "sympozium-system", "-l", "sympozium.ai/builtin=true")
1249+
// Strip finalizers from all Sympozium CRD instances BEFORE deleting the
1250+
// controller, so resources don't get stuck in Terminating state.
1251+
fmt.Println(" Removing finalizers from Sympozium resources...")
1252+
resources := []string{"agentruns", "sympoziuminstances", "sympoziumpolicies", "skillpacks", "sympoziumschedules", "personapacks"}
1253+
for _, res := range resources {
1254+
stripFinalizers(res)
1255+
}
1256+
fmt.Println(" Deleting Sympozium custom resources...")
1257+
for _, res := range resources {
1258+
_ = kubectl("delete", res+".sympozium.ai", "--all", "--all-namespaces", "--ignore-not-found", "--timeout=60s")
1259+
}
12531260

12541261
// Delete in reverse order.
12551262
manifests := []string{
@@ -1267,18 +1274,6 @@ func runUninstall() error {
12671274
_ = kubectl("delete", "--ignore-not-found", "-f", m)
12681275
}
12691276

1270-
// Strip finalizers from all Sympozium CRD instances so CRD deletion doesn't
1271-
// hang waiting for the (now-deleted) controller to reconcile them.
1272-
fmt.Println(" Removing finalizers from Sympozium resources...")
1273-
resources := []string{"agentruns", "sympoziuminstances", "sympoziumpolicies", "skillpacks", "sympoziumschedules", "personapacks"}
1274-
for _, res := range resources {
1275-
stripFinalizers(res)
1276-
}
1277-
fmt.Println(" Deleting Sympozium custom resources...")
1278-
for _, res := range resources {
1279-
_ = kubectl("delete", res+".sympozium.ai", "--all", "--all-namespaces", "--ignore-not-found", "--timeout=60s")
1280-
}
1281-
12821277
// CRDs last.
12831278
crdBase := "https://raw.githubusercontent.com/" + ghRepo + "/main/config/crd/bases/"
12841279
crds := []string{

0 commit comments

Comments
 (0)