Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ All notable changes to blockstor are recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/), and the project follows
[Semantic Versioning](https://semver.org/).

## v0.1.17 — 2026-07-04

Adversarial-hardening release. A red/blue agent loop attacked the control-plane / API / store / controller surface through the public REST + `linstor` CLI interfaces (concurrency, cache-lag, autoplace/tiebreaker/quorum, VolumeNumber races, snapshot bookkeeping, node evict/restore/lost/drain, input-boundary fuzzing, reconciler races). Two adversarial passes across the V1–V5 sweep, snapshot-restore, resource-connection-path, pagination-under-mutation and every CRD↔wire transcode surfaced THREE real breaks — all the same class: a `modify` path skipping the validation or field-carry-across the `create` path enforces — fixed below (that seam is now mined dry and guarded by a carry-across tripwire). DRBD-kernel scenarios (satellite mkfs/attach, split-brain, real sync) and two parity/product questions were deferred to the live stand (see "Deferred").

### Fixed

- **VD-scoped modify no longer drops the per-volume DRBD minor / device identity (#177, Bug 433)** — a legal `vd set-size` grow or `vd set-property` silently dropped `RD.Spec.VolumeDefinitions[].DRBDMinor` (the `/dev/drbd<N>` identity): `PatchVolumeDefinitionSpec` rebuilt the entry through `wireToCRDVD`, whose wire type carries no minor field. It self-heals in isolation (the allocator re-picks the same value) but once a lower minor is freed by routine RD churn the allocator re-stamps a DIFFERENT minor — a permanent device-identity change on a live resized volume, violating the CRD's own carry-across invariant (`ResourceDefinitionVolume.DRBDMinor` — "never overwritten … preserved through a REST modify"). Same wire-rebuild-drops-operator-only-field class as Bug 206/208. Fix: `wireToCRDVDPreserving` carries the minor across both write-backs, and `ResourceDefinitionVolume` is now registered in the carry-across tripwire test so the class can't silently ship again. Pinned at L1 (store) + integration fail-on-bug, with L6 cli-matrix + L7 replay (new `drbd_minor` await kind) authored (on-stand run deferred).
- **`rg modify` no longer accepts an invalid layer_stack that a resource then inherits (#178, Bug 434)** — `linstor resource-group modify --layer-list` stored a `select_filter.layer_stack` the CREATE path refuses, and an RD created against that RG inherited it unvalidated (`handleRDCreate` validated BEFORE `inheritLayerStackFromRG`), persisting an unmaterializable layer stack in the RD spec even though a direct rd-create 400s the same stack. Same modify-bypasses-create-validation class as the resize-bounds fix. Fix: `rgUpdateWireGate` validates the layer_stack on rg-modify, plus a defense-in-depth re-validation of the inherited stack after `inheritLayerStackFromRG`. Pinned at L1 (rest) + integration fail-on-bug, with L6 cli-matrix + L7 replay authored (on-stand run deferred).
- **`vd set-size` no longer stores an unmaterializable out-of-range volume size (#175)** — the CREATE path refuses `size_kib` outside `[4 MiB, 16 TiB]` via `validateVDSize` (Bug 155) so the satellite never hot-loops on `drbdadm create-md`, but the RESIZE path (`PUT .../volume-definitions/{vn}`, `linstor vd set-size`) skipped that gate: a below-floor force-shrink (e.g. 3 MiB) or an over-ceiling grow (> 16 TiB) returned 200 and stored the size verbatim, reproducing the exact Bug-155 hot-loop through the resize verb — and it did not self-heal. `rejectVDPatchSize` now runs the create path's bounds gate (`validateVDSize` + byte-identical `writeVDSizeRejection` FAIL_INVLD_VLM_SIZE envelope) BEFORE the shrink-vs-force gate; `force` waives the shrink-direction opt-in, never the physical floor/ceiling. In-bounds resizes (incl. in-bounds force-shrink) are unaffected. Pinned at L1 (handler) + integration (envtest) fail-on-bug, with the L6 cli-matrix `vd-resize-bounds-rejected` cell + L7 replay authored (on-stand run deferred, stand-pending task).

### Testing & infrastructure

- **Integration lane no longer rotate-flakes on the heaviest autoplace-convergence cases (#176)** — the per-group Eventually budgets were already scaled ×3 on CI (v0.1.16), but `TestGroupFRToggleDiskful2DisklessReapsTieBreaker` and `TestGroupJ/CSICreateVolumeFromEmpty` still timed out at exactly 90s under full-suite runner contention while completing in ~8s locally — placer/mock-satellite starvation, not a hang. The CI scale is now ×5 (30s → 150s); fail-safe (green runs return the instant the predicate passes; a genuine hang still fails at the job `-timeout=15m` ceiling).

### Deferred (pending the live dev-kvaps DRBD stand + LINSTOR oracle)

- **DRBD-kernel tier** — satellite mkfs/attach, split-brain, real sync, finalizer drain: unexercisable by the mock satellite; the real remaining production risk.
- **N3 (product decision)** — a transient diskful-node drain-and-return permanently over-replicates (place_count=2 ends at 3 diskful + 0 witness): evict backfills the witness→diskful to keep redundancy and blockstor has no excess-replica trim, diverging from upstream `evacuate`'s net-neutral migrate. No data loss / wedge.
- **N4 (parity decision)** — `linstor r td --diskless` on the last diskful replica is accepted, leaving a diskless-only (dataless) resource. blockstor deliberately allows deleting the last diskful (bug-hunt #6); whether the toggle should be refused needs the LINSTOR oracle (cli-parity-refresh) to settle. Proposed fix: force-gated guard mirroring the U130 delete escape.

## v0.1.16 — 2026-07-02

Bugfix release. Production-readiness hardening pass over v0.1.15: a multi-replica read-consistency alignment in the apiserver, an auto-snapshot bookkeeping race fix, and an Integration-lane reliability fix surfaced while re-validating the release on CI.
Expand Down