Repository navigation
Retain selectable deploy generations, not just a single-step rollback #16043
Description
Parent: SLM method-adoption umbrella (#16028). Source: NixOS generations.
Method
Every build is a generation that is retained and selectable. nixos-rebuild switch activates
now and sets the default boot entry; older generations remain intact and listable
(list-generations: number, date, version, kernel); --rollback returns to the previous one; and
every retained generation is selectable from the boot menu, so a configuration that breaks the
running system is still recoverable from outside it.
The verbs are the other half of the idea. NixOS separates what most systems conflate into one
"deploy":
| verb | activate now | default next start | retained |
|---|---|---|---|
switch |
yes | yes | yes |
boot |
no | yes | yes |
test |
yes | no | no |
build |
no | no | no |
Already-exists audit
services/blue_green.py:277-302 rollback() unwinds this deployment — rollbackable_statuses
gates it, and _execute_rollback returns the borrowed roles. Combined with
post_deploy_monitor_duration and health-gated auto_rollback (:763), recovery from the deploy
you just ran is genuinely strong, and stronger than any of the nine reference works.
What is absent is depth. There is no list of prior known-good deploys and no way to select one, so
recovering from a bad deploy that has already been superseded is not a supported operation — the
only route back is to redeploy an older commit and hope the intervening state is compatible.
services/deploy_artifacts.py is the natural home for retained artifact sets.
Change
- Retain the last N deploy generations per role as selectable artifact sets, with a stated retention
policy. - List them with the facts an operator needs to choose: generation number, deployed commit, date,
health outcome. - Allow selecting any retained generation, not only the previous one.
- Consider splitting the deploy verb along NixOS's axes — at minimum, separate "activate now" from
"make this the target that a restart converges to".
Hidden cost — this is the whole design
N generations means N retained artifact sets. Without an explicit retention policy this is disk
exhaustion with extra steps, and the failure will land on the node with the least headroom. The
retention policy is not a detail to settle later; it is the feature. NixOS's own honest limitation
is worth copying too — it exposes "roll back one" as a command and defers arbitrary selection to a
separate interface rather than pretending one verb covers both.
Acceptance criteria
- The last N deploy generations per role are retained as selectable artifact sets
- Retention is an explicit, documented, configurable policy — not an unbounded accumulation
- Generations are listable with commit, date and health outcome
- Any retained generation can be selected, not only the previous one
- Disk headroom is checked before retaining, and exhaustion degrades by evicting oldest rather than failing a deploy
- Existing blue-green auto-rollback behaviour is unchanged
Implementation Order
Wave: 2
Depends on: #16032 (per-commit checksum manifest — a generation needs a verifiable identity)
Activity