Commit 05fb765
fix(kafka): resolve disk-removal deadlock during rolling upgrade (#254)
* Fix disk removal deadlock during rolling upgrade
When a broker pod is deleted during rolling upgrade and a disk removal is
pending (GracefulDiskRemovalScheduled), the operator enters a deadlock:
reconcileKafkaPvc blocks the entire reconcile with "Disk removal pending",
preventing reconcileKafkaPod from recreating the missing pod. Meanwhile,
Cruise Control cannot complete the disk removal because the broker isn't
running.
Fix: move runningBrokers map building before reconcileKafkaPvc and pass it
in. Before returning the blocking error, check if any broker with pending
disk removal has a missing pod. If so, allow the reconcile to proceed so
the pod can be recreated. The disk removal check is re-evaluated on the
next cycle once the broker is back up.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review findings: cover IsDiskRebalance, add mountPath to log, add tests
- Fix #1 (HIGH): Override now checks IsDiskRebalance() in addition to
IsDiskRemoval(), closing the same deadlock vector for rebalance states
- Fix #2 (LOW): Include mountPath in the bypass log message for
consistency with other disk-removal log messages
- Fix #3 (LOW): Add tests for rebalance-state deadlock bypass and for
newly-marked-for-removal with missing pod
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add OpenSpec artifacts for disk removal deadlock fix
Proposal, design, and task tracking for the fix.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(kafka): don't block reconcile on stalled disk removal/rebalance
A terminally-failed or paused Cruise Control disk operation
(GracefulDisk{Removal,Rebalance}CompletedWithError / Paused) was treated
as "in progress" via IsDiskRemovalRunning(), so reconcileKafkaPvc returned
CruiseControlTaskRunning indefinitely. With all broker pods present this
froze the whole reconcile — including config rollout / rolling upgrade to
healthy brokers — since reconcileKafkaPod runs downstream of the PVC block.
Observed on a live 3-broker cluster stuck in ClusterRollingUpgrading with
every removed disk in GracefulDiskRemovalCompletedWithError.
Relaxing the block is data-safe: log.dirs retention
(shouldKeepRemovedLogDirInConfig) and PVC mount retention both keep the
removed disk in place until removal is confirmed *succeeded*, independent
of this block. Cruise Control also does not hang on a dead broker — it
marks the intra-broker task DEAD and completes with error — so a stalled
state is genuinely terminal, not in-flight work a restart could disrupt.
- add CruiseControlVolumeState.IsDiskOperationStalled() (CompletedWithError
/Paused), mirroring IsDownscaleStalled
- in handleDiskRemoval, set waitForDiskRemovalToFinish only for non-stalled
IsDiskRemoval()/IsDiskRebalance() states; branch selection (PVC deletion,
state marking) is unchanged
- tests: removal CompletedWithError / Paused and rebalance CompletedWithError
with pod present now proceed; Running + pod present still blocks
Complements the existing missing-pod bypass: narrowing handles a stalled
task with pods up; the bypass handles a genuinely-running task whose broker
pod is missing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(e2e): verify config change + disk removal reconcile together
Add an e2e spec that applies a single manifest carrying both a read-only
broker config change (log.retention.hours, forces a rolling restart) and a
disk removal, then asserts the cluster reconciles correctly: the config
change propagates to broker ConfigMaps, the removed disk drops out of
log.dirs, Cruise Control goes quiescent, and the cluster returns to
ClusterRunning (a deadlock would time out this wait).
- config/samples/simplekafkacluster_1disk_configchange.yaml: 2disk sample
reduced to one disk (removes /kafka-logs3) plus a changed readOnlyConfig
- tests/e2e/test_config_change_with_disk_removal.go: testConfigChangeWithDiskRemoval
and brokerConfigMapsContainProperty helper
- wire the spec into the suite after testMultiDiskRemoval (chains 2->1 disk)
Covers the combined-operation happy path end to end; the stalled-removal and
missing-pod deadlocks the fix targets remain covered by the unit tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(kafka): silence funlen for TestReconcileKafkaPvcDiskRemoval
The added stalled-state cases pushed the table-driven test past the funlen
limit (355 > 323). Annotate with //nolint:funlen, matching the existing
convention for long table tests in this file.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent fb6d1c1 commit 05fb765
9 files changed
Lines changed: 930 additions & 14 deletions
File tree
- api/v1beta1
- config/samples
- openspec/changes/fix-disk-removal-deadlock
- pkg/resources/kafka
- tests/e2e
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
105 | 117 | | |
106 | 118 | | |
107 | 119 | | |
| |||
Lines changed: 300 additions & 0 deletions
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
327 | 327 | | |
328 | 328 | | |
329 | 329 | | |
330 | | - | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
336 | | - | |
337 | 330 | | |
338 | 331 | | |
339 | 332 | | |
| |||
347 | 340 | | |
348 | 341 | | |
349 | 342 | | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
350 | 350 | | |
351 | 351 | | |
352 | 352 | | |
| |||
1189 | 1189 | | |
1190 | 1190 | | |
1191 | 1191 | | |
1192 | | - | |
| 1192 | + | |
1193 | 1193 | | |
1194 | 1194 | | |
1195 | 1195 | | |
| |||
1328 | 1328 | | |
1329 | 1329 | | |
1330 | 1330 | | |
| 1331 | + | |
| 1332 | + | |
| 1333 | + | |
| 1334 | + | |
| 1335 | + | |
| 1336 | + | |
| 1337 | + | |
| 1338 | + | |
| 1339 | + | |
| 1340 | + | |
| 1341 | + | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
| 1345 | + | |
| 1346 | + | |
| 1347 | + | |
1331 | 1348 | | |
1332 | 1349 | | |
1333 | 1350 | | |
| |||
1376 | 1393 | | |
1377 | 1394 | | |
1378 | 1395 | | |
1379 | | - | |
1380 | | - | |
| 1396 | + | |
| 1397 | + | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
| 1401 | + | |
| 1402 | + | |
| 1403 | + | |
| 1404 | + | |
| 1405 | + | |
| 1406 | + | |
| 1407 | + | |
1381 | 1408 | | |
1382 | | - | |
1383 | | - | |
| 1409 | + | |
| 1410 | + | |
| 1411 | + | |
| 1412 | + | |
| 1413 | + | |
| 1414 | + | |
| 1415 | + | |
1384 | 1416 | | |
1385 | 1417 | | |
1386 | 1418 | | |
| |||
0 commit comments