Skip to content

cinder chaos: volume/snapshot churn with extend mutations#37

Merged
berendt merged 7 commits into
mainfrom
implement/issue-32-cinder-chaos
Jul 3, 2026
Merged

cinder chaos: volume/snapshot churn with extend mutations#37
berendt merged 7 commits into
mainfrom
implement/issue-32-cinder-chaos

Conversation

@berendt

@berendt berendt commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Closes #32

Summary

Adds a cinder chaos churn/soak mode: it drives volume and snapshot lifecycle churn within a scenario envelope while treating volume extend as a mutation. Rather than fork the Neutron churn engine, this branch first generalizes the shared chaos engine so it names no service, then teaches it a third action class (mutate), and finally maps a Cinder plan onto it and wires up the command.

Change set (in commit order)

  1. 3a02cc8 Pin the Neutron churn decision schedule with a golden test
    Captures the exact create/delete/no-op schedule the chaos engine draws for churnPlan() at seed 7 under a virtual clock, generated once with -update. The unchanged bytes become the proof that the subsequent refactor and the new mutate action do not perturb the Neutron decision schedule for a given seed.

  2. 3be9c47 Generalize the chaos engine seam and relocate the Neutron builder
    Drops the Neutron interface from the engine's node closures — a Node's Create/Delete now capture their cloud client at graph-build time and operate on the shared resource.Resource, so the engine names no service. Per-operation retry and 404 delete-tolerance move into the builder closures; Config sheds ExternalNetworkID/OpTimeout and gains an optional Classify hook; a create now publishes whatever it returned (with a failed flag) so a created-but-not-ready resource stays deletable and recorded while a doomed child is skipped. The Neutron graph builder, interface, retry wrappers, and error classifier move to a new internal/chaos/neutrongraph subpackage. The golden schedule moves with the tests and stays byte-identical, proving the refactor is invisible for Neutron.

  3. 8be83a8 Add a mutate action with a resize_ratio draw to the chaos engine
    Adds a third action class alongside create and delete: a mutation of a live instance (a Cinder volume extend). Each step draws, with probability ResizeRatio, a mutation of a present, not-yet-mutated node carrying a Mutate closure; a node is mutated at most once per lifetime and re-armed when re-created. The draw is double-gated on the graph having mutable nodes and a positive ratio, so a Neutron graph never touches the RNG here and its golden decision schedule stays byte-for-byte identical. Result/ChaosStats gain a Mutates counter (omitempty).

  4. 2117368 Add a chaos block with resize_ratio to the Cinder scenario schema
    Gives the Cinder scenario its own chaos block mirroring the Neutron one (duration, interval, parallel, churn_ratio, target_fill) plus the block-storage-specific resize_ratio — the per-tick probability of extending a live, not-yet-resized volume to its planned target. The block is validated (nil-safe, ratios in [0,1], interval min <= max) and duplicated by design so a typo in either service's scenario fails loudly under strict unmarshal. Every shipped profile (5m/30m/1h) gains a chaos block, so cinder chaos --scenario … runs without --duration.

  5. be61aaa Add the Cinder churn graph builder
    Maps a Cinder plan onto the chaos engine: one parentless volume node per volume (mutable to its planned resizeToGiB when it has a target) and one snapshot node parented on its source volume, so the engine never snapshots an absent volume nor deletes a volume with live snapshots. Readiness is folded into each operation (create/extend complete only at available, delete only once the resource is gone), and each volume's snapshot/extend/delete operations are serialized behind a per-volume mutex. Drives every call through the cinder executor's retry policy, now exported as WithRetry. Adds one engine guard the cinder graph is first to need: skip a mutation when the create failed (a Cinder create can succeed yet fail readiness — a volume stuck at error — and must stay deletable/recorded but never extended).

  6. c6f1de2 Add the cinder chaos command
    Wires the cinder churn graph into a cinder chaos subcommand mirroring neutron chaos: same flag surface and three-layer config merge (defaults < scenario chaos block < flags), plus --volume-type and the block-storage-specific --resize-ratio. It authenticates, resolves the volume type, pre-checks quota against the full plan envelope, builds the cindergraph, runs the churn, records the run with ChaosStats and the volume type, and — unless interrupted or --no-cleanup — tears volumes and snapshots down by metadata (snapshots before volumes, each bounded by --timeout) and runs a leak check. An interrupted or --no-cleanup run prints the cinder cleanup --run-id reclaim hint. buildCinderPlanFromFlags now also returns the scenario so the command can read its chaos block.

  7. 839fe45 Document cinder chaos in the README
    Documents the new mode in §15: adds it to the commands block and phase/roadmap status, adds a "Chaos duration" column to the profile table, and adds a "Churn / soak mode (cinder chaos)" subsection covering engine reuse, the volume/snapshot lifecycle, the readiness rule, extend-as-mutation with the new resize_ratio knob (default 0.3, --resize-ratio overrides, 0 disables), the ChaosStats/OTEL outputs, and metadata-based reclamation of an interrupted run.

Divergences from the issue

None visible from the commits: the change implements volume/snapshot churn with extend mutations inside the scenario chaos envelope as issue #32 requested. Note that the branch does more than the literal ask — it first generalizes the shared chaos engine and extracts the Neutron builder into internal/chaos/neutrongraph — but this is enabling refactor, pinned byte-for-byte against a golden decision schedule so Neutron behavior is provably unchanged.

Testing

The diff carries the tests with the code: a golden Neutron decision schedule, generalized engine tests, the new internal/chaos/cindergraph engine/graph tests (lifecycle, envelope, extend-once-per-lifetime, gigabytes bound, per-volume serialization, not-ready and terminal-error paths, schedule determinism), scenario schema validation tests, and command tests mirroring the neutron chaos suite.


Implemented by planwerk-agent 6b3f3ea with Claude:claude-opus-4-8

berendt added 7 commits July 3, 2026 08:35
Capture the exact create/delete/no-op schedule the chaos engine draws
for churnPlan() at seed 7 under testConfig() and a virtual clock, so the
upcoming engine seam refactor is provably byte-for-byte for Neutron.

The golden file is generated once with -update against the current
engine and must never be regenerated afterwards: its unchanged bytes are
the proof that generalizing the node seam and adding the mutate action do
not perturb the Neutron decision schedule for a given seed.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@b42labs.com>
Drop the Neutron interface from the engine's node closures: a Node's
Create/Delete now capture their cloud client at graph-build time and
operate on the shared resource.Resource, so the engine names no service.
Per-operation retry and 404 delete-tolerance move into the builder
closures, Config sheds ExternalNetworkID/OpTimeout and gains an optional
Classify hook, and a create now publishes whatever it returned (with a
failed flag) so a created-but-not-ready resource stays deletable and
recorded while a doomed child is still skipped.

The Neutron graph builder, its interface, retry wrappers, and error
classifier move to a new internal/chaos/neutrongraph subpackage; the
engine no longer imports neutron, executor, or plan. The seeded engine
tests and the byte-identical golden decision schedule move with it and
stay green, proving the refactor is invisible for Neutron.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@b42labs.com>
Give the churn engine a third action class alongside create and delete:
a mutation of a live instance (a Cinder volume extend) that is neither.
Each step draws, with probability ResizeRatio, a mutation of a present,
not-yet-mutated node carrying a Mutate closure; a node is mutated at
most once per lifetime and re-armed when re-created. The draw is
double-gated on the graph having mutable nodes and a positive ratio, so
a Neutron graph never touches the RNG here and its decision schedule
stays byte-for-byte identical — the golden schedule proves it.

Mutations do not change the population, so the churn controller's
economics are untouched; they consume one fan-out slot like any API
call. Result and ChaosStats gain a Mutates counter (omitempty, with a
conditional table row) so extend activity is visible in a run record
even when OTEL export is off.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@b42labs.com>
Give the Cinder scenario its own chaos block, mirroring the Neutron one
(duration, interval, parallel, churn_ratio, target_fill) plus the
block-storage-specific resize_ratio: the per-tick probability of
extending a live, not-yet-resized volume to its planned target. The
block is validated (nil-safe, ratios in [0,1], interval min <= max) and
duplicated by design so a typo in either service's scenario still fails
loudly under strict unmarshal.

Every shipped Cinder profile now carries a chaos block (5m/30m/1h), so
`cinder chaos --scenario scenarios/cinder/<profile>.yaml` runs without a
--duration flag. The small fixture gains the matching block; because
Scenario now holds a *Chaos, the profile-fixture test compares with
reflect.DeepEqual instead of ==.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@b42labs.com>
Map a Cinder plan onto the chaos engine: one volume node per volume
(parentless, mutable to its planned resizeToGiB when it has a target)
and one snapshot node per snapshot, parented on its source volume so the
engine never snapshots an absent volume nor deletes a volume with live
snapshots. Readiness is folded into each operation — a create or extend
completes only at available, a delete only once the resource is gone —
and each volume's snapshot/extend/delete operations are serialized behind
a per-volume mutex. The builder drives every call through the cinder
executor's retry policy, now exported as WithRetry.

The engine gains one guard the cinder graph is the first to need: skip a
mutation when the create failed. Neutron creates are all-or-nothing, but
a Cinder create can succeed yet fail readiness (a volume stuck at error);
that instance is published so it stays deletable and recorded, but must
not be extended. Fake-backed tests cover the lifecycle, envelope, extend-
once-per-lifetime, gigabytes bound, per-volume serialization, the not-
ready and terminal-error paths, and schedule determinism.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@b42labs.com>
Wire the cinder churn graph into a `cinder chaos` subcommand mirroring
`neutron chaos`: the same flag surface and three-layer config merge
(defaults < scenario chaos block < flags), plus --volume-type and the
block-storage-specific --resize-ratio. It authenticates, resolves the
volume type, pre-checks quota against the full plan envelope, builds the
cindergraph, runs the churn, records the run with ChaosStats and the
volume type, and — unless interrupted or --no-cleanup — tears the volumes
and snapshots down by metadata (snapshots before volumes, each operation
bounded by --timeout) and runs a leak check. An interrupted or
--no-cleanup run prints the `cinder cleanup --run-id` reclaim hint.

buildCinderPlanFromFlags now also returns the scenario so the command can
read its chaos block; generate, apply, and monitor ignore it. Command
tests mirror the neutron chaos tests: required scenario and duration,
flag-over-block precedence, resize-ratio override, invalid-scenario
short-circuit, and shipped profiles running without --duration.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@b42labs.com>
Document the new `cinder chaos` churn/soak mode in §15: add it to the
commands block and the phase/roadmap status, add a "Chaos duration"
column to the profile table, and add a "Churn / soak mode (cinder
chaos)" subsection covering the reuse of the Neutron churn engine, the
volume/snapshot lifecycle, the readiness rule, extend-as-mutation with
the new resize_ratio knob (default 0.3, --resize-ratio overrides, 0
disables), the ChaosStats/OTEL outputs, and metadata-based reclamation of
an interrupted run.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@b42labs.com>
@berendt
berendt marked this pull request as ready for review July 3, 2026 08:29
@berendt
berendt merged commit ada4568 into main Jul 3, 2026
2 checks passed
@berendt
berendt deleted the implement/issue-32-cinder-chaos branch July 3, 2026 08:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cinder chaos: volume/snapshot churn with extend mutations within a scenario envelope

1 participant