Skip to content

Declarative Apply: grow, create, and shrink partitions; remove Run#23

Open
eriknordmark wants to merge 2 commits into
diskfs:mainfrom
eriknordmark:esp-b-create
Open

Declarative Apply: grow, create, and shrink partitions; remove Run#23
eriknordmark wants to merge 2 commits into
diskfs:mainfrom
eriknordmark:esp-b-create

Conversation

@eriknordmark

@eriknordmark eriknordmark commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Reconcile a GPT disk to a desired set of partitions in a single, idempotent,
restart-safe pass. Apply grows partitions, creates absent ones (with an
empty filesystem), and optionally shrinks one to free space.

This began as "create a partition as part of a resize" (#22) and, following
review, folds the remaining Run capabilities into Apply and removes Run,
so there is a single entry point that can do it all.

Behavior

  • desired is monotonically non-destructive: absent ⇒ create, smaller than its
    size ⇒ grow (relocate + copy, partition number preserved), already ≥ size ⇒
    no-op (never shrunk).
  • Matching: a PartitionSpec locates an existing partition to grow by
    Match (name/label/uuid); without Match it is keyed by GUID, and an absent
    GUID is created (the GUID becomes the created partition's identity). A matched
    partition's type/label are asserted so it never operates on an unexpected disk.
  • Shrink is the only reducing operation and is optional: to an explicit
    size, or — when the size is 0 — shrink-to-fit (only as much as the grows and
    creates need). When nil, nothing can be shrunk by accident.
  • Disk discovery: with no disk given, the disk is discovered from the
    identifiers; by-name (e.g. sda3) identifiers are resolved to UUIDs via sysfs.
  • A created partition's GPT entry is published only by the single final table
    write, so "entry present ⇒ filesystem present" and an interrupted create
    converges on re-run.

Go API

Apply(disk, desired []PartitionSpec, shrink *ShrinkSpec, fixErrors, dryRun)
the signature is unchanged, so existing callers (e.g. EVE's storage-resizer)
need no code change. PartitionSpec gains an optional Match PartitionIdentifier;
ShrinkSpec.Size == 0 requests shrink-to-fit. Run, PartitionChange, and
NewPartitionChange are removed.

CLI

The resize/apply subcommands collapse into a single bare command:

# before
resizer resize --grow-partition name:sda1:20G --shrink-partition name:sda3 /dev/sda
# after
resizer --partition match=name:sda1,minsize=20G --shrink name:sda3 /dev/sda

--partition takes guid= or match=<id> plus minsize= (and optional
label=,type=,index=,fs=); --shrink takes identifier:value[:size] (size
optional for to-fit); the disk is an optional positional argument. --preserve-numbers
is dropped — partition numbers are always preserved.

Tests

Suites ported from Run to Apply, plus new coverage for by-name/label
matching, shrink-to-fit, disk discovery, and name resolution. The full
end-to-end suite, the opt-in SIGKILL chaos soak, and golangci-lint all pass.

Commits

Two commits: the declarative Apply feature (grow/create/shrink, remove Run,
single bare resizer CLI, tests + README) and a separate go-diskfs re-pin to
current master.

@eriknordmark
eriknordmark force-pushed the esp-b-create branch 2 times, most recently from cf4f1d5 to 358f8d8 Compare July 8, 2026 23:50
@eriknordmark
eriknordmark marked this pull request as ready for review July 9, 2026 03:01
@eriknordmark

Copy link
Copy Markdown
Contributor Author

@deitch ready for review. Note the open question in the description: this moves the existing grow/shrink CLI under a resizer resize subcommand to make room for the new resizer apply (create + declarative reconcile) — the Go API stays additive (Run unchanged, Apply new). Worth your take on whether to keep both or standardize on apply. Thanks!

@deitch

deitch commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

It is a good open question. I do think Apply is better than Run (and the CLI equivalents), and as you said, it is almost a superset. Keeping both also can create confusion. On the other hand, we lose the "by name/label" options and the shrink capabilities. Should we move those into Apply and then a single one can do it all?

@eriknordmark

Copy link
Copy Markdown
Contributor Author

@deitch done — folded Run's remaining capabilities into Apply and removed Run, so there's a single entry point that does it all:

  • By name/label/uuid matching: a PartitionSpec can set Match (name/label/uuid) to locate an existing partition to grow; without it the spec is keyed by GUID (match-or-create, as before). The shrink already took an identifier.
  • Shrink-to-fit: ShrinkSpec.Size == 0 shrinks only as much as the grows/creates need (the old auto-fit); a positive size still shrinks to exactly that.
  • Auto-discovery + by-name: Apply with an empty disk discovers it from the identifiers, and by-name (sda3) identifiers resolve to UUIDs via sysfs.

Apply's Go signature is unchanged, so existing callers (EVE's storage-resizer) need no code change. On the CLI the resize/apply subcommands collapse into a single bare resizer [disk] (--partition gains match=; --shrink's size is optional for to-fit).

Tests were ported from Run to Apply, with new coverage for matching, shrink-to-fit, discovery, and name resolution; the full suite, the SIGKILL chaos soak, and golangci-lint are all green.

One thing I dropped: the --preserve-numbers toggle — Apply always preserves partition numbers (the safe default the consumer relies on). Happy to re-add it as an option if you'd prefer.

eriknordmark and others added 2 commits July 18, 2026 08:44
Apply is the single entry point for reconciling a GPT disk to a desired
set of partitions in an idempotent, restart-safe pass. It grows a
partition to at least its size, creates it (with an empty filesystem)
when absent, and optionally shrinks one partition to free space -- to an
explicit size, or (when the size is zero) only as much as the grows and
creates need. An existing partition is matched by GUID or by
name/label/uuid; with no disk given, the disk is discovered from the
identifiers and kernel device names are resolved via sysfs. A created
partition's GPT entry is published only by the final table write, so an
interrupted run converges on re-run.

Run is removed, and the cmd/resizer CLI collapses from resize/apply
subcommands into a single bare `resizer [disk]`. Apply's Go signature is
unchanged, so existing callers (e.g. EVE's storage-resizer) are
unaffected.

Implements diskfs#22.

Signed-off-by: eriknordmark <erik@zededa.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Not required by this PR. Since the previous pin, go-diskfs gained a
squashfs read fix for images with no fragment or xattr table (#413) and
an added GPT round-trip test (#414); the resizer depends on neither.
Bumped only to keep the module on current go-diskfs master.

Signed-off-by: eriknordmark <erik@zededa.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@eriknordmark eriknordmark changed the title Create a partition (and filesystem) as part of a resize Declarative Apply: grow, create, and shrink partitions; remove Run Jul 18, 2026
@eriknordmark

Copy link
Copy Markdown
Contributor Author

@deitch follow-up now that this is polished for review: restructured into two commits — the declarative Apply feature (grow/create/shrink, Run removed, single bare resizer CLI, tests + README) and a separate go-diskfs re-pin to master — rebased onto main. Full end-to-end suite, the SIGKILL chaos soak, and golangci-lint v2.6 all pass, and EVE's storage-resizer compiles unchanged against the new API. Retitled accordingly; ready for your review.

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.

2 participants