feat(guests): cap guest resources and gate boot-start (task 0008) #34

Merged
alexion merged 1 commits from task-0008-guest-resource-limits into main 2026-07-25 21:52:54 -04:00
Owner

Task: .claude/tasks/0008-guest-resource-limits.md

Summary

Adds the Host-side placement that caps a Guest's resources and controls whether it starts at boot.

  • A limits field — memory, cpu, tasksMax — maps to the guest's own container@<name>.service unit as MemoryMax, CPUQuota, and TasksMax.
    A filterAttrs drops any limit left null, so an unset limit writes no key and systemd keeps its uncapped default.
  • memory and cpu are strings passed through to systemd verbatim (2G, 150%); tasksMax is a positive int.
  • An autoStart placement option, on by default, drives the container's autoStart directly (was mkDefault true).
    The backend gates wantedBy = [ "machines.target" ] on it, so false leaves the unit defined but out of machines.target — startable on demand, not at boot.
  • neogaia's skeleton guest carries modest demonstrative caps, following task 0002's precedent of exercising the guest path on this host through nix flake check.

No deviations from the plan; all four acceptance criteria are met and verified by nix eval and a passing nix flake check.

Review

Risk

Overall: Medium

  • Blast radius: Low — contained to the lib.nix guest helper plus one host's demonstrative caps; opt-in options only.
  • Reversibility: Low — pure config additions, no migrations or deletions; autoStart still defaults true.
  • Test coverage: Medium — nix flake check builds and passes, but no test asserts the caps land on the unit; correctness rests on eval-time wiring.
  • Sensitive domain: Medium — touches cgroup enforcement (MemoryMax/CPUQuota/TasksMax); a mis-mapped value could OOM-kill or throttle a guest, though confined to it.
  • Size & complexity: Low — small linear diff; a drop-nulls filterAttrs and a mkIf.
  • Runtime criticality: Medium — constrains how live guests are bounded, but only guests using the backend are affected.

Unaddressed findings

Standards — two judgement calls, kept deliberately:

  • Repeated Switches (lib.nix): mkIf (cfg.backend == "container") now guards both the new serviceConfig and the pre-existing containers.<name> block.
    Kept as per-attribute guarding, which is idiomatic here; folding both under one conditional would nest the whole config block for a single predicate.
  • Divergent Change (lib.nix): autoStart is a hard assignment (cfg.autoStart) while sibling container settings keep mkDefault.
    Intentional — autoStart is the host-owned placement control, so it should bind directly rather than stay overridable by a guest interior.

Spec — clean pass, no findings.

— Claude

Task: `.claude/tasks/0008-guest-resource-limits.md` ## Summary Adds the Host-side placement that caps a Guest's resources and controls whether it starts at boot. - A `limits` field — `memory`, `cpu`, `tasksMax` — maps to the guest's own `container@<name>.service` unit as `MemoryMax`, `CPUQuota`, and `TasksMax`. A `filterAttrs` drops any limit left null, so an unset limit writes no key and systemd keeps its uncapped default. - `memory` and `cpu` are strings passed through to systemd verbatim (`2G`, `150%`); `tasksMax` is a positive int. - An `autoStart` placement option, on by default, drives the container's `autoStart` directly (was `mkDefault true`). The backend gates `wantedBy = [ "machines.target" ]` on it, so `false` leaves the unit defined but out of `machines.target` — startable on demand, not at boot. - `neogaia`'s skeleton guest carries modest demonstrative caps, following task 0002's precedent of exercising the guest path on this host through `nix flake check`. No deviations from the plan; all four acceptance criteria are met and verified by `nix eval` and a passing `nix flake check`. ## Review ### Risk **Overall: Medium** - Blast radius: Low — contained to the `lib.nix` guest helper plus one host's demonstrative caps; opt-in options only. - Reversibility: Low — pure config additions, no migrations or deletions; `autoStart` still defaults true. - Test coverage: Medium — `nix flake check` builds and passes, but no test asserts the caps land on the unit; correctness rests on eval-time wiring. - Sensitive domain: Medium — touches cgroup enforcement (`MemoryMax`/`CPUQuota`/`TasksMax`); a mis-mapped value could OOM-kill or throttle a guest, though confined to it. - Size & complexity: Low — small linear diff; a drop-nulls `filterAttrs` and a `mkIf`. - Runtime criticality: Medium — constrains how live guests are bounded, but only guests using the backend are affected. ### Unaddressed findings Standards — two judgement calls, kept deliberately: - **Repeated Switches** (`lib.nix`): `mkIf (cfg.backend == "container")` now guards both the new `serviceConfig` and the pre-existing `containers.<name>` block. Kept as per-attribute guarding, which is idiomatic here; folding both under one conditional would nest the whole config block for a single predicate. - **Divergent Change** (`lib.nix`): `autoStart` is a hard assignment (`cfg.autoStart`) while sibling container settings keep `mkDefault`. Intentional — `autoStart` is the host-owned placement control, so it should bind directly rather than stay overridable by a guest interior. Spec — clean pass, no findings. — Claude
alexion added 1 commit 2026-07-25 21:27:24 -04:00
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.
alexion merged commit 0b7d409fbc into main 2026-07-25 21:52:54 -04:00
alexion deleted branch task-0008-guest-resource-limits 2026-07-25 21:52:54 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: alexion/dotfiles#34