Give the Host-side placement a `limits` field — `memory`, `cpu`, and `tasksMax` — that caps the guest's `container@<name>.service` unit via `MemoryMax`, `CPUQuota`, and `TasksMax`, uncapped by default so an unset limit contributes no key and systemd keeps its default. Add an `autoStart` placement option, on by default, driving the container's boot-start so a Host can define a guest without starting it at boot. Give neogaia's skeleton guest modest demonstrative caps.
2.3 KiB
2.3 KiB
spec, blocked-by
| spec | blocked-by |
|---|---|
| guests | 0002-guest-walking-skeleton |
What to build
The Host-side placement that caps a Guest's resources so one misbehaving service cannot starve its Host, plus the boot-start toggle.
A Host sets limits — memory, cpu, and tasksMax — applied to the guest's unit, uncapped by default.
A Host sets autoStart to control whether the Guest starts at boot, on by default.
Acceptance criteria
- A Host setting
guests.<path>.limits.memory,.cpu, or.tasksMaxapplies the corresponding cap to the guest's unit. - Each limit is uncapped when unset.
autoStartstarts the Guest at boot by default, and disabling it leaves the Guest defined but not started at boot.- A Host with a capped Guest builds via
nix flake check, and the resolved unit caps are verifiable bynix eval.
Implementation Notes
- The caps map to the guest's own systemd unit,
container@<name>.service, which the container backend generates. The guest module contributesserviceConfig.MemoryMax,.CPUQuota, and.TasksMax, and the module system merges these with the backend's ownserviceConfigfor that unit. Only set caps appear: afilterAttrsdrops any limit left null, so an unset limit contributes no key and systemd keeps its uncapped default rather than the module writing an explicit "infinity". limits.memoryandlimits.cpuare strings passed through to systemd verbatim (2G,150%), since systemd already parses size and percentage forms and re-inventing the parsing here would only narrow what the operator can express.limits.tasksMaxis a positive int, matchingTasksMax's count.autoStartis now a placement option defaulting true, and the container'sautoStartreads from it directly rather than the previousmkDefault true. The backend gateswantedBy = [ "machines.target" ]onautoStart, sofalseleaves thecontainer@<name>.serviceunit fully defined but out ofmachines.target— startable on demand, not at boot — verified by evaluation.neogaia's skeleton guest carries modest demonstrative caps (memory = "1G",cpu = "100%",tasksMax = 512), following task 0002's precedent of exercising the guest path on this host through its ownnix flake check. ItsautoStartis left at the default so 0002's live boot smoke test is unaffected.