Skip to content

Commit 940c4c6

Browse files
adwk67claude
andcommitted
fix: Add orderly shutdown steps to all kuttl tests to prevent namespace deletion timeouts
During namespace deletion, ZooKeeper and Kafka are terminated simultaneously. Kafka's controlled-shutdown retries ZK connections indefinitely, keeping the process alive for the full grace period and blocking namespace deletion past kuttl's 300s timeout. For ZK-mode tests: scale brokers to 0 via the CRD so the operator performs an orderly shutdown before ZK is removed. For KRaft-mode tests: scale brokers to 0, delete the KafkaCluster CR to stop reconciliation, then force-delete controller pods. Controllers cannot be scaled via the CRD due to a "no Kraft controllers found to build ConfigMap" error. All tests also set gracefulShutdownTimeout: 60s to bound the worst-case wait. Validated with a full nightly suite run (26/26 PASS). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0d1c8bb commit 940c4c6

19 files changed

Lines changed: 239 additions & 0 deletions

tests/templates/kuttl/cluster-operation/20-install-kafka.yaml.j2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ spec:
2323
zookeeperConfigMapName: test-zk
2424
brokers:
2525
config:
26+
gracefulShutdownTimeout: 60s
2627
logging:
2728
enableVectorAgent: {{ lookup('env', 'VECTOR_AGGREGATOR') | length > 0 }}
2829
roleGroups:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
# Scale Kafka down before kuttl deletes the namespace.
3+
# Without this, ZooKeeper and Kafka are terminated simultaneously during
4+
# namespace deletion. Kafka's controlled-shutdown retries ZK connections
5+
# indefinitely, keeping the process alive for the full grace period
6+
# and blocking namespace deletion well past kuttl's 300s timeout.
7+
apiVersion: kuttl.dev/v1beta1
8+
kind: TestStep
9+
timeout: 600
10+
commands:
11+
- script: |
12+
kubectl patch kafkacluster test-kafka -n $NAMESPACE --type merge -p '{"spec":{"brokers":{"roleGroups":{"default":{"replicas":0}}}}}'
13+
- script: |
14+
if kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=120s 2>/dev/null; then
15+
exit 0
16+
fi
17+
kubectl delete pods -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --grace-period=0 --force 2>/dev/null || true
18+
kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=300s

tests/templates/kuttl/configuration/10-install-kafka.yaml.j2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ spec:
2323
{% endif %}
2424
controllers:
2525
config:
26+
gracefulShutdownTimeout: 60s
2627
logging:
2728
enableVectorAgent: {{ lookup('env', 'VECTOR_AGGREGATOR') | length > 0 }}
2829
resources:
@@ -57,6 +58,7 @@ spec:
5758
replicas: 1
5859
brokers:
5960
config:
61+
gracefulShutdownTimeout: 60s
6062
logging:
6163
enableVectorAgent: {{ lookup('env', 'VECTOR_AGGREGATOR') | length > 0 }}
6264
resources:
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
# Scale Kafka down before kuttl deletes the namespace.
3+
# Brokers are scaled via the CRD so the operator performs an orderly shutdown.
4+
# Once brokers are gone, we delete the KafkaCluster CR to stop the operator
5+
# reconciling, then force-delete any remaining controller pods. We cannot scale
6+
# controllers via the CRD because the operator errors with "no Kraft controllers
7+
# found to build ConfigMap", and scaling the StatefulSet directly is immediately
8+
# reversed by the operator's reconciliation loop.
9+
apiVersion: kuttl.dev/v1beta1
10+
kind: TestStep
11+
timeout: 600
12+
commands:
13+
- script: |
14+
kubectl patch kafkacluster test-kafka -n $NAMESPACE --type merge -p '{"spec":{"brokers":{"roleGroups":{"default":{"replicas":0}}}}}'
15+
- script: |
16+
if kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka,app.kubernetes.io/component=broker -n $NAMESPACE --timeout=120s 2>/dev/null; then
17+
exit 0
18+
fi
19+
kubectl delete pods -l app.kubernetes.io/instance=test-kafka,app.kubernetes.io/component=broker -n $NAMESPACE --grace-period=0 --force 2>/dev/null || true
20+
kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka,app.kubernetes.io/component=broker -n $NAMESPACE --timeout=300s
21+
- script: |
22+
kubectl delete kafkacluster test-kafka -n $NAMESPACE --wait=false 2>/dev/null || true
23+
- script: |
24+
kubectl delete pods -l app.kubernetes.io/instance=test-kafka,app.kubernetes.io/component=controller -n $NAMESPACE --grace-period=0 --force 2>/dev/null || true
25+
kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka,app.kubernetes.io/component=controller -n $NAMESPACE --timeout=120s 2>/dev/null || true
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
# Scale Kafka down before kuttl deletes the namespace.
3+
# Without this, ZooKeeper and Kafka are terminated simultaneously during
4+
# namespace deletion. Kafka's controlled-shutdown retries ZK connections
5+
# indefinitely, keeping the process alive for the full grace period
6+
# and blocking namespace deletion well past kuttl's 300s timeout.
7+
apiVersion: kuttl.dev/v1beta1
8+
kind: TestStep
9+
timeout: 600
10+
commands:
11+
- script: |
12+
kubectl patch kafkacluster test-kafka -n $NAMESPACE --type merge -p '{"spec":{"brokers":{"roleGroups":{"default":{"replicas":0},"secondary":{"replicas":0}}}}}'
13+
- script: |
14+
if kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=120s 2>/dev/null; then
15+
exit 0
16+
fi
17+
kubectl delete pods -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --grace-period=0 --force 2>/dev/null || true
18+
kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=300s
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
# Scale Kafka down before kuttl deletes the namespace.
3+
# Without this, ZooKeeper and Kafka are terminated simultaneously during
4+
# namespace deletion. Kafka's controlled-shutdown retries ZK connections
5+
# indefinitely, keeping the process alive for the full grace period
6+
# and blocking namespace deletion well past kuttl's 300s timeout.
7+
apiVersion: kuttl.dev/v1beta1
8+
kind: TestStep
9+
timeout: 600
10+
commands:
11+
- script: |
12+
kubectl patch kafkacluster test-kafka -n $NAMESPACE --type merge -p '{"spec":{"brokers":{"roleGroups":{"default":{"replicas":0}}}}}'
13+
- script: |
14+
if kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=120s 2>/dev/null; then
15+
exit 0
16+
fi
17+
kubectl delete pods -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --grace-period=0 --force 2>/dev/null || true
18+
kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=300s

tests/templates/kuttl/logging/04-install-kafka.yaml.j2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ spec:
5252
vectorAggregatorConfigMapName: kafka-vector-aggregator-discovery
5353
zookeeperConfigMapName: test-kafka-znode
5454
brokers:
55+
config:
56+
gracefulShutdownTimeout: 60s
5557
roleGroups:
5658
automatic-log-config:
5759
replicas: 1
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
# Scale Kafka down before kuttl deletes the namespace.
3+
# Without this, ZooKeeper and Kafka are terminated simultaneously during
4+
# namespace deletion. Kafka's controlled-shutdown retries ZK connections
5+
# indefinitely, keeping the process alive for the full grace period
6+
# and blocking namespace deletion well past kuttl's 300s timeout.
7+
apiVersion: kuttl.dev/v1beta1
8+
kind: TestStep
9+
timeout: 600
10+
commands:
11+
- script: |
12+
kubectl patch kafkacluster test-kafka -n $NAMESPACE --type merge -p '{"spec":{"brokers":{"roleGroups":{"automatic-log-config":{"replicas":0},"custom-log-config":{"replicas":0}}}}}'
13+
- script: |
14+
if kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=120s 2>/dev/null; then
15+
exit 0
16+
fi
17+
kubectl delete pods -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --grace-period=0 --force 2>/dev/null || true
18+
kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=300s

tests/templates/kuttl/opa/30-install-kafka.yaml.j2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ commands:
4242
config:
4343
logging:
4444
enableVectorAgent: true
45+
gracefulShutdownTimeout: 60s
4546
roleGroups:
4647
default:
4748
replicas: 3
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
# Scale Kafka down before kuttl deletes the namespace.
3+
# Without this, ZooKeeper and Kafka are terminated simultaneously during
4+
# namespace deletion. Kafka's controlled-shutdown retries ZK connections
5+
# indefinitely, keeping the process alive for the full grace period
6+
# and blocking namespace deletion well past kuttl's 300s timeout.
7+
apiVersion: kuttl.dev/v1beta1
8+
kind: TestStep
9+
timeout: 600
10+
commands:
11+
- script: |
12+
kubectl patch kafkacluster test-kafka -n $NAMESPACE --type merge -p '{"spec":{"brokers":{"roleGroups":{"default":{"replicas":0}}}}}'
13+
- script: |
14+
if kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=120s 2>/dev/null; then
15+
exit 0
16+
fi
17+
kubectl delete pods -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --grace-period=0 --force 2>/dev/null || true
18+
kubectl wait --for=delete pod -l app.kubernetes.io/instance=test-kafka -n $NAMESPACE --timeout=300s

0 commit comments

Comments
 (0)