fix(battleship): declaratively ensure guest persist zvol before domain start #760
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "guest-persist-zvol-ensure"
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?
What
Declaratively guarantee the beefcake guest's
vdbpersist zvol (rpool/beefcake-persist) exists before the libvirt domain is defined/started, so a host cold-boot can never again fail on a missing backing disk.Why (the outage this fixes)
The guest domain (
packages/hosts/beefcake/slot-domain.nix) attaches two disks:vda→/dev/zvol/rpool/beefcake-blue(the real guest OS+data) andvdb→/dev/zvol/rpool/beefcake-persist(forward-plumbing for the unfinished Phase-4 shared persist).rpool/beefcake-persistwas never created, so the first true colddefine+start— a host reboot on 2026-07-13 — failed withCannot access storage file '/dev/zvol/rpool/beefcake-persist'and took the guest (all of beefcake's services) down.Prior reboots survived only because libvirt did a managed-save resume, which restores a running domain and does not re-validate disks. A cold
define+startvalidates every backing path, so the missing zvol stayed hidden until a genuinely cold boot.vdbis vestigial from the guest's point of view (it imports its rpool from vda only) but is still declared in the domain XML, so the host must provide it. Recovery was an imperativezfs create -s -V 100G rpool/beefcake-persist+ nixvirt restart — no data loss.The fix
systemd.services.ensure-guest-persist-zvoloneshot (Type=oneshot,RemainAfterExit=true) inpackages/hosts/battleship.nix:zfs create -s -V 100G rpool/beefcake-persist(sparse, 100 GiB, matching the size created during recovery so there's no divergence with the live zvol). It never destroys/recreates an existing zvol and never touchesbeefcake-blue./dev/zvol/...node to appear, erroring if it never does.After=zfs.target zfs-import.target,Before=nixvirt.service libvirtd.service,WantedBy=multi-user.target. Bothlibvirtd.service(autostarts domains during its own startup) andnixvirt.service(After=Requires=libvirtd.service, applies the declarative domains) can start the guest, so it's ordered before both.persistZvolDatasetto a top-levelletbinding so the dataset name and/dev/zvolpath share a single source of truth.Runbook (
lib/doc/beefcake-guest-hugepages.md)Adds an "Operational guards / lessons" section:
virsh domblklist beefcake-blueand confirm every/dev/zvol/...backing path exists (cold start validates all disks; managed-save resume does not).LoaderEntryDefault/LoaderEntryOneShotvar over loader.conf'sdefault; fix withbootctl set-oneshot <gen>.confthenbootctl set-default ''.Validation
nix fmtclean.nix eval .#nixosConfigurations.battleship.config.system.build.toplevel.drvPathsucceeds.After=zfs.target zfs-import.target,Before=nixvirt.service libvirtd.service,WantedBy=multi-user.target,Type=oneshot,RemainAfterExit=true.Applies on the next host activation — no reboot needed, since the zvol already exists live and the oneshot is a no-op there.
Not deployed, not merged.