Skip to content

Commit 3d9d5e0

Browse files
committed
Add generic teardown script in shared folder. Will require additional changes to be pulled in by beku that depend on stackabletech/beku.py#40 to be merged first.
1 parent 1cc39b7 commit 3d9d5e0

1 file changed

Lines changed: 75 additions & 0 deletions

File tree

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
# Generic, product-agnostic teardown step for Stackable kuttl tests.
3+
#
4+
# Runs BEFORE kuttl deletes the test namespace. It removes every Stackable workload so the built-in
5+
# StatefulSet controller can no longer recreate Pods during namespace deletion (the recreation race
6+
# that wedges Pods on ephemeral-PVC ownership / listener-secret CSI mount and blocks teardown).
7+
#
8+
# It hardcodes nothing about the product under test:
9+
# 1. discovers and deletes ALL `*.stackable.tech` custom resources in the namespace (Stackable
10+
# StatefulSets are managed by their CR, so they must be removed this way),
11+
# 2. deletes the NON-Stackable Pod-owning workload controllers directly — StatefulSets, Deployments,
12+
# ReplicaSets, DaemonSets, Jobs NOT labelled stackable.tech/vendor=Stackable (unmanaged
13+
# test-helper / infra deps such as MinIO/Keycloak/LDAP/KDC; disposable, and removing them stops
14+
# Pod recreation). Stackable-managed workloads are excluded on purpose — they are removed via
15+
# their CR (step 1) + GC, so deleting them here would race the operator into recreating them,
16+
# 3. waits for the Stackable-managed StatefulSets to be gone (selected by the
17+
# `stackable.tech/vendor=Stackable` label, so a StatefulSet the step can't remove — owned by
18+
# another controller — doesn't make it wait out its timeout), so nothing recreates Pods,
19+
# 4. force-deletes any remaining Pods (safe now) instead of waiting out product shutdown grace.
20+
#
21+
# Drop this file in as the highest-numbered step of a test (e.g. 99-teardown.yaml), or — better —
22+
# have it injected into every test from a single source (see teardown-step-placement.md).
23+
apiVersion: kuttl.dev/v1beta1
24+
kind: TestStep
25+
timeout: 600
26+
commands:
27+
- timeout: 600
28+
script: |
29+
set -u
30+
NS="$NAMESPACE"
31+
32+
# 1. Delete ALL Stackable CRs in the namespace (dynamic kind discovery — no per-product names).
33+
# Stackable StatefulSets are MANAGED: the operator recreates them from the CR, so they must be
34+
# removed via the CR, not by deleting the StatefulSet directly.
35+
kinds="$(kubectl api-resources --verbs=delete --namespaced -o name 2>/dev/null \
36+
| grep '\.stackable\.tech$' | paste -sd, -)"
37+
[ -n "$kinds" ] && kubectl -n "$NS" delete "$kinds" --all --ignore-not-found --wait=false || true
38+
39+
# 2. Best-effort: delete the NON-Stackable Pod-owning workload controllers directly (test helpers
40+
# like *-test-helper / checks, and infra deps — MinIO/Keycloak are Deployments and use PVCs;
41+
# OpenLDAP/KDC may be bare StatefulSets). These are disposable and, crucially, unmanaged: no
42+
# operator watches them, so deleting the top-level object sticks and nothing recreates it.
43+
# Removing them stops them recreating Pods, so the force-delete/wait below can't churn and
44+
# nothing re-adds pvc-protection during namespace deletion.
45+
#
46+
# We deliberately EXCLUDE Stackable-managed workloads (stackable.tech/vendor=Stackable). Those
47+
# are removed by deleting their CR (step 1) + owner-reference GC, and waited on in step 3.
48+
# Deleting them directly here would RACE the operator: our delete fires the operator's
49+
# owned-object watch, and if its informer cache hasn't yet seen the CR deletion (no
50+
# deletionTimestamp cached), the reconcile re-applies the StatefulSet — recreation overtaking
51+
# our delete. `notin (Stackable)` also matches objects with no vendor label, i.e. exactly the
52+
# unmanaged ones.
53+
kubectl -n "$NS" delete statefulsets,deployments,replicasets,daemonsets,jobs \
54+
-l 'stackable.tech/vendor notin (Stackable)' \
55+
--ignore-not-found --wait=false >/dev/null 2>&1 || true
56+
57+
# 3. Wait for the STACKABLE StatefulSets to be gone (their controller then can't recreate Pods).
58+
# Scoped to the Stackable vendor label so a foreign StatefulSet the step can't remove (owned by
59+
# another controller) can't make this loop burn its full 300s timeout. We only need to
60+
# guarantee the operator-managed STSs — the wedge-prone ones — are cleared here.
61+
sel="stackable.tech/vendor=Stackable"
62+
for _ in $(seq 1 150); do
63+
[ -z "$(kubectl -n "$NS" get statefulsets -l "$sel" -o name 2>/dev/null)" ] && break
64+
sleep 2
65+
done
66+
67+
# 4. Force-delete any lingering Pods (nothing recreates them now); skips product grace periods.
68+
kubectl -n "$NS" delete pods --all --grace-period=0 --force --ignore-not-found >/dev/null 2>&1 || true
69+
70+
# 5. Best-effort: let Pods clear so the namespace delete has no work left.
71+
for _ in $(seq 1 60); do
72+
[ -z "$(kubectl -n "$NS" get pods -o name 2>/dev/null)" ] && break
73+
sleep 2
74+
done
75+
echo "teardown: stackable CRs deleted; pods remaining in $NS: $(kubectl -n "$NS" get pods --no-headers 2>/dev/null | wc -l)"

0 commit comments

Comments
 (0)