feat(nix): first-class container-runner support — services.lab.container.* #219
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab!219
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/218"
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?
Closes #218
A
services.lab.containersubmodule giving container-runner deployments (ADR-0052/ADR-0053) first-class NixOS options instead of hand-wiredextraFlags/extraPackages/ rawserviceConfigoverrides. Implemented to the grilled contract in the issue body; DoD is every acceptance criterion except the maintainer's landing gate.Option surface
container.enable(explicit switch gating all host mutations — never option non-emptiness),container.toolsImages(attrsOf nonEmptyStrkeyed by provider ID),container.defaultImage(nullable; per-repoimage_refalone is valid, ADR-0053),container.subIdRange(default{ start = 100000; count = 65536; }, nullable opt-out, overridable on collision).What enabling does
--container-tools-image provider=ref[,provider=ref…](name-sorted comma-join) and--container-imageinto ExecStart beforeextraFlags, so a hand-rolled migration flag still wins (Go flag parser takes the last occurrence).virtualisation.podman.enable = true(crun + policy.json/registries.conf viavirtualisation.containers), podman + passt on the unit PATH (what preflight probes and the pane argv resolves against).Delegate = true;RuntimeDirectory=lab+RuntimeDirectoryPreserve=yes(+ mode 0700) +XDG_RUNTIME_DIR=/run/lab— Preserve is load-bearing next toKillMode=process: containers that survive a lab restart must not have the runtime dir wiped underneath them.sub{Uid,Gid}Rangesonusers.users.<user>vialib.mkMerge, so the ranges land on operator-brought users too.container.enablewith emptytoolsImagesfails atnixos-rebuildeval (seedUser precedent). Deliberately nodefaultImageassertion, no provider-ID key validation, no digest-pin enforcement.Verification (all run locally, green)
container.enable = falseconfig rendered fromb59ae43:nix/module.nixvs this branch, identical pinned config/package — byte-identical (old == newin one nix eval). Also made permanent: thenixos-modulecheck now greps the disabled dummy's unit for the absence of--container*,Delegate=,RuntimeDirectory*, andXDG_RUNTIME_DIR.nixos-modulecheck extended: container-enabled unit greps (comma-joined tools flag with name-sorted order,--container-image,Delegate=true,RuntimeDirectory=lab+Preserve=yes+Mode=0700,XDG_RUNTIME_DIR=/run/lab, podman + passt store paths on PATH); eval-asserts for the empty-toolsImagesassertion message,defaultImage = null(tools flag renders, image flag doesn't),subIdRangedefault/custom/null/disabled, andvirtualisation.podman.enableon/off. Mutation-tested: perturbing the dummy'sdefaultImagefails the check.nixos-container-closurecheck builds a full container-enabled NixOS system closure with dummy refs (tmpfs root, no bootloader, no real agent CLIs) — option typos and assertion regressions fail CI without booting anything. Its own attr so the eval/grep check stays cheap.nix flake checkgreen.Docs
docs/ops.md: option-table rows for
container.*; "What the host must provide" now leads with the one-block NixOS config (bullets kept as the cross-distro/preflight substance + by-hand guidance);RuntimeDirectoryPreserverationale; stateDir sizing note for the rootless image store under<state>/.local/share/containersplus a matching backup-exclusion bullet (digest-pinned, re-pulled on demand); CI disk note mentions the new closure check.Maintainer landing gate (per the issue, not in this PR's DoD): validate on a real host — preflight green after one rebuild, a container-runner repo spawns, and running containers survive a lab restart with their runtime dir intact.
🤖 Generated with Claude Code
Add a services.lab.container submodule so container-runner deployments (ADR-0052/ADR-0053) stop hand-wiring extraFlags, Delegate=yes, unit PATH packages, subuid/subgid ranges, and the rootless runtime dir from docs/ops.md: - Options: container.enable (gates ALL host mutations, never option non-emptiness), toolsImages (attrsOf nonEmptyStr keyed by provider ID), defaultImage (nullable — per-repo image_ref alone is valid), subIdRange (default 100000/65536, nullable opt-out, overridable on collision). - Flags: --container-tools-image provider=ref[,provider=ref…] (name-sorted comma-join) and --container-image, rendered before extraFlags so a hand-rolled migration flag still wins. - Provisioning under enable: virtualisation.podman.enable, podman+passt on the unit PATH, Delegate=true, RuntimeDirectory=lab with RuntimeDirectoryPreserve=yes (+0700) and XDG_RUNTIME_DIR=/run/lab — Preserve is load-bearing next to KillMode=process so podman-attached containers survive a lab restart — and sub{Uid,Gid}Ranges on the service user (merges onto operator-brought users too). - Eval assertion: container.enable with empty toolsImages fails at nixos-rebuild eval (seedUser precedent). Deliberately no defaultImage assertion, no provider-ID key validation, no digest-pin enforcement. - Checks: nixos-module gains container-enabled unit greps, subIdRange / defaultImage / assertion eval-asserts, and zero-diff guards pinning that a container-disabled unit stays byte-identical to today's output (proven againstb59ae43with a pinned package); new nixos-container-closure check builds a container-enabled NixOS system closure with dummy refs. - docs/ops.md: NixOS guidance collapses to services.lab.container.*; stateDir sizing + backup-exclusion notes for the rootless image store under <state>/.local/share/containers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>[autoland] verdict: pass
Clean PASS. Both CI gates green (ci/native success; ci-nix/flake-check success in 19m15s — ran the full nix flake check including the extended nixos-module greps/asserts and the new nixos-container-closure full-system build). Title is Conventional Commits; Closes #218 present and matches head afk/218. Diff scope is exactly module.nix + flake.nix + docs/ops.md, each change mapping to an issue-#218 acceptance criterion with no drive-by edits. main is a direct ancestor of the head, so no conflict.