Declarative disk layouts (disko templates) #6
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
#4 Installer GUI
jmarya/myverse
Reference
jmarya/myverse#6
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
myverse has no disk story at all. Grepping the tree: zero
fileSystems, zeroswapDevices, and no bootloader enablement anywhere exceptprofiles/features/secure_boot.nixforce-disabling systemd-boot. Every host has to hand-write partitioning, mounts, swap and boot config.hosts/liveonly escapes this because the installer-cd module supplies it.Two consequences:
Design: a template is a module, not a partition table
The tempting version of this is "ship some disko snippets." That earns nothing, because partitioning is never the whole decision. A LUKS+btrfs root also implies
boot.initrd.systemd.enable, an unlock mechanism,boot.supportedFilesystems,services.btrfs.autoScrub,boot.tmp.useTmpfs, an ESP sized for the generation count, and a swap policy that does not contradictprofiles.zram.So: a disk template is a NixOS module that happens to contain a
disko.devicesattrset. If templates emit only partitions, every host re-derives the tail by hand.Option surface
Two rules to bake in hard:
by-idpaths only./dev/nvme0n1reorders across boots and kernel versions. The module should reject a bare/dev/sdXoutright; the installer's probe resolves the friendly name the user clicked into a stable one. Cheap now, unfixable later.enabledefaults tofalse, even when a device class sets alayoutdefault. The class supplies the opinion; the host supplies the consent plus the device. Nothing partitions a disk as a side effect of importingmyverse.nixosModules.server.btrfs subvolume policy
Every btrfs template uses subvolumes — they are free and they make snapshots, quota, and (later) impermanence possible.
But the split stays deliberately shallow, because moving a file between subvolumes is a physical copy.
rename(2)cannot cross a subvolume boundary, somvdegrades to copy+delete. A layout that looks tidy on paper turns routine file management into gigabytes of pointless I/O.The rule: split along boundaries nobody moves files across.
@/@home/home/@nix/nix/nixby rename; excluded from snapshots@log/var/log@snapshots/.snapshotsExplicitly not doing: a separate
@data/@mediaalongside@home, or splitting/var/libout of/var. Those are exactly the boundaries users and services move files across.Mount options:
compress=zstd,noatimethroughout.Catalogue
Small on purpose — every template is a VM test to maintain.
minimalserver@,@nix,@log). Optional LUKS. No hibernate.appliance@,@nix,@log). No encryption. Tuned for power-cut rather than clean shutdown.workstation@,@home,@nix,@log,@snapshots). Swapfile sized for hibernate.impermanentis deliberately not a template — it becomes a flag on the existing ones once a state registry exists. Naming the option now means adding it later does not rename layouts.Decisions taken
profiles.disk, matching the ~20 existing NixOS modules. (myverse.*stays the flake-parts namespace.)espSizedefaults to 2G, flat. NixOS keeps N generations of kernel+initrd in the ESP, and lanzaboote adds signed images on top. The conventional 512M fills up and then boots fail confusingly.profiles/devices/server/default.nixalready capsconfigurationLimit = 5; this is the other half.bcachefs-tiered(nvme cache + HDD backing) is deferred to a follow-up. It is the most distinctly-myverse template and the least proven, and it roughly doubles the test surface.unlockships with all four values, but onlypassphrase,sshandnoneare implemented in v1.tpm2depends on secure-boot enrollment happening during provisioning, which does not exist yet. The option surface stays stable so adding it later is not a breaking change.Traps
Swap is three decisions pretending to be one. zram (
profiles.zram, currently defaults enabled), a real swap device (profiles.zswapexists for this), and hibernation (needs a resume device >= RAM, and does not work with swap-on-zram). Those two modules cannot see each other today, soswap = "hibernate"would silently do nothing on a desktop. The disk layer must own the decision and driveprofiles.zram.enablefrom it.Unlock policy is where disks collide with comin and secure boot. Server comin mode uses
operation = "boot", so an encrypted server reboots into its new generation and stops at a passphrase prompt forever. Each template must force an explicit choice rather than defaulting into that deadlock.These cannot be eval-tested. The existing
checksare cheapdrvPathevaluations, which catch nothing here — a layout can evaluate perfectly and produce an unbootable machine. disko shipsmakeDiskoTest; budget a real boot test per template. This is the main cost driver and the main reason the catalogue is four entries.Scope
In:
diskoflake input;profiles.diskmodule; the four templates; per-device-classlayoutdefaults (without enabling); raw-disko escape hatch; VM tests; docs inprofiles/README.md.Out: impermanence and the state registry; secrets/sops; the installer itself (#4); multi-disk mirroring and RAID (single boot disk plus optional single data disk in v1 — exotic pools go through the escape hatch).
Acceptance
profiles.diskmodule with the option surface above, rejecting non-by-iddevicesdisko.devicesand its matching NixOS configprofiles.zram/profiles.zswapdisko-install --flake .#<host>from amachines/<host>/disk.nixcontaining nothing but a layout name and a by-id deviceBlocks
#4 — the installer's disk step consumes this catalogue.