deploy the closure the swarm declares, read no forge head, drop the update badge
This commit is contained in:
parent
279428a66f
commit
47c2acb640
2 changed files with 647 additions and 2001 deletions
|
|
@ -41,12 +41,12 @@ No MCP tool exists for config changes: opening the PR IS the request.
|
|||
and publishes a deploy request carrying that commit on that hive's
|
||||
deploy subject. With no such hive, or more than one, it deploys
|
||||
nothing and logs a warning naming them.
|
||||
5. If the commit already is the one the agent's last successful build pinned
|
||||
(the `applied/.<n>.config-rev` marker), the hive does nothing. Otherwise it
|
||||
queues a rebuild, which resolves its pins from `internal/meta` like any
|
||||
rebuild. The request's commit only feeds that check: the hive keeps no copy
|
||||
of the config. An agent with no container on that hive yet ignores the
|
||||
commit; its first deploy builds whatever `internal/meta` pins.
|
||||
5. If the closure the swarm declares for the agent is the one the hive last
|
||||
applied (the `applied/.<n>.closure` marker), the hive does nothing.
|
||||
Otherwise it queues a rebuild, which downloads the declared closure. The
|
||||
request's commit plays no part: the hive keeps no copy of the config and
|
||||
reads no forge head. An agent with no container on that hive yet gets its
|
||||
first deploy from the declared closure.
|
||||
|
||||
This path runs **no eval-verify**. A merged config that doesn't
|
||||
evaluate or build fails the rebuild, so the agent's rebuilds keep failing
|
||||
|
|
@ -130,35 +130,24 @@ nginx include in line with the live agents. `provision_container`, `destroy`,
|
|||
which means `nixos-container list` failed, and it fails when `HIVE_FORGE_URL`
|
||||
is unset, since every agent would come up with no forge.
|
||||
|
||||
The dashboard's `deployed:<sha12>` chip per container row shows the config
|
||||
commit the agent's last successful build pinned.
|
||||
|
||||
## The swarm's meta flake
|
||||
|
||||
swarm-controller commits `internal/meta`: one `flake.nix` and `flake.lock` for
|
||||
every agent any hive places (the pins:
|
||||
[`docs/swarm/builder.md`](../swarm/builder.md#meta-flake-lock)). The swarm
|
||||
builder builds every agent from it, and a hive deploys that build. While the
|
||||
repo has no commit that pins an agent's current config, that agent's deploy
|
||||
fails and names the agent. The controller queues
|
||||
swarm has recorded no build of an agent, that agent's deploy fails and names the
|
||||
agent. The controller queues
|
||||
its update of the repo before the deploy request for a merged config commit
|
||||
and for a new agent, and sends the deploy only when that update succeeded and
|
||||
the swarm builder built the agent from the updated repo (the
|
||||
[deploy gate](../swarm/builder.md#deploy-gate)). A failed build skips the deploy, and the timer builds again.
|
||||
|
||||
- **Choosing the commit.** The rebuild's `MetaSync` node reads the repo's
|
||||
default-branch head with the hive's read token (`forge::reader_token()`)
|
||||
and takes it when its `flake.nix` builds the agent the way the agent needs now:
|
||||
a custom agent from the config commit at the head of `agent-configs/<n>`
|
||||
`main`, an archetype agent from the archetype it has now. An agent switched
|
||||
between custom and archetype, or to another archetype, fails that test.
|
||||
A repo with no commit, a head that lacks the agent and a head behind the
|
||||
config each fail the deploy with an error that names the agent. `MetaSync` records the commit,
|
||||
with the hyperhive and config commits the head pins, in `hive-c0re`'s own state,
|
||||
`/var/lib/hyperhive/meta-rev/<n>`, which the agent can't write (the container mounts its runtime
|
||||
directory read-write); `Prebuild` and `Swap` read that
|
||||
record, so both expect the closure of one commit. A first deploy resolves the commit in its `Create`
|
||||
node, since it has no `MetaSync`.
|
||||
- **Choosing the closure.** The hive doesn't choose. It deploys the closure the
|
||||
agent's record in `agent-closures` declares, whichever `internal/meta` commit
|
||||
the builder built it from, and reads no forge head. The rebuild's `MetaSync`
|
||||
node only prepares it (the agent's archetype, its runtime directories, the
|
||||
agent set).
|
||||
- **The closure.** The hive builds nothing. `Prebuild`, `Swap` and `Create` read
|
||||
the agent's record in the swarm's `agent-closures` bucket (the controller
|
||||
writes it from the builder's reply) and have `hive-priv` download the closure
|
||||
|
|
@ -168,22 +157,20 @@ the swarm builder built the agent from the updated repo (the
|
|||
that agent returned. On the wire the
|
||||
`hive_priv_sock::PrivRequest` variants carry a required field:
|
||||
`{"op":"update_container","name":"atlas","stream":true,"toplevel":"/nix/store/<hash>-nixos-system-atlas"}`.
|
||||
The three cases when the swarm's closure isn't the one this hive expects
|
||||
are in [`docs/swarm/builder.md`](../swarm/builder.md#rebuilds-download-the-closure).
|
||||
A rebuild with no record, or none the builder pushed, fails with an error
|
||||
that names the agent; see
|
||||
[`docs/swarm/builder.md`](../swarm/builder.md#rebuilds-download-the-closure).
|
||||
- **Hyperhive.** The commit pins one hyperhive rev for the swarm, so an agent
|
||||
runs the hyperhive of the controller's deploy, not its hive's.
|
||||
- **Markers.** After a successful build `hive-c0re` writes the hyperhive
|
||||
commit the head pins to `applied/.<n>.hyperhive-rev`, and the config
|
||||
commit to `applied/.<n>.config-rev` (none for an archetype agent). The boot
|
||||
reconcile ([below](#autoupdate-on-startup)) and the dashboard's update chip
|
||||
read them.
|
||||
- **Marker.** After a successful swap or create `hive-c0re` writes the closure's
|
||||
store path to `applied/.<n>.closure`. The autoupdate pass
|
||||
([below](#autoupdate-on-startup)) compares it with the record.
|
||||
|
||||
## Deploy markers per agent
|
||||
|
||||
```
|
||||
/var/lib/hyperhive/applied/ deploy markers - core-only
|
||||
├── .<name>.hyperhive-rev # hyperhive commit of the last good build
|
||||
└── .<name>.config-rev # config commit of the last good build
|
||||
└── .<name>.closure # store path of the last closure applied
|
||||
|
||||
/var/lib/hyperhive/meta/ plain hive state - core
|
||||
├── topology.json # the live agent set
|
||||
|
|
@ -191,8 +178,11 @@ the swarm builder built the agent from the updated repo (the
|
|||
```
|
||||
|
||||
hive-c0re keeps no copy of an agent's config: the forge's `agent-configs/<name>`
|
||||
`main` is the only one, and a config change is a PR against it. The two markers
|
||||
record what the agent's last successful build pinned, and nothing else.
|
||||
`main` is the only one, and a config change is a PR against it. The marker
|
||||
records the closure last applied, and nothing else. Hives that ran before the
|
||||
marker existed have `.<name>.hyperhive-rev`, `.<name>.config-rev` and
|
||||
`meta-rev/<name>` files instead. Nothing reads them any more, and you can
|
||||
delete them.
|
||||
|
||||
Older hives also kept an *applied* repo at `applied/<name>` and a *proposed*
|
||||
clone at `agents/<name>/config`. Nothing reads either any more, and you can
|
||||
|
|
@ -210,9 +200,8 @@ The bundled `hive-forge` container runs on the swarm's forge host
|
|||
(`deploy.forgejo.enable`, see [`../swarm/services.md`](../swarm/services.md)).
|
||||
Every agent created through the swarm has a repo in the private
|
||||
`agent-configs` Forgejo org, created and seeded by swarm-controller.
|
||||
hive-c0re pushes nothing to it and keeps no clone: forge `main` advances only
|
||||
by an operator's merge. The hive reads the head of `main`, to resolve the
|
||||
commit `internal/meta` pins.
|
||||
hive-c0re pushes nothing to it, keeps no clone and reads nothing from it: forge
|
||||
`main` advances only by an operator's merge.
|
||||
|
||||
Each agent is a **write collaborator on its own** `agent-configs/<name>`
|
||||
repo — so it can push a branch and open a config PR — but not a member
|
||||
|
|
@ -356,29 +345,30 @@ swarm-level alert could carry the same signal).
|
|||
|
||||
`hive-c0re serve` runs `auto_update::run` in a background task right
|
||||
after opening the coordinator. It enumerates managed containers and
|
||||
rebuilds any whose recorded hyperhive rev differs from the one
|
||||
`internal/meta` pins now. That's how a hive that missed the swarm's
|
||||
fan-out catches up. Sub-agents and the root agent go through the same
|
||||
graceful rebuild subgraph.
|
||||
rebuilds any whose closure marker differs from the store path the agent's
|
||||
record in `agent-closures` declares. That's how a hive that missed the
|
||||
swarm's deploy request catches up, and it repeats every five minutes, which
|
||||
covers a request lost while the hive is up. Sub-agents and the root agent go
|
||||
through the same graceful rebuild subgraph.
|
||||
|
||||
"Rev" = the hyperhive commit pinned by the head of `internal/meta`, as
|
||||
the hive reads it with its forge token. Marker
|
||||
file: `/var/lib/hyperhive/applied/.<name>.hyperhive-rev`, written after
|
||||
a successful build. If the hive can't read the pin (no forge token, the
|
||||
forge down, `internal/meta` not published yet), the scan rebuilds
|
||||
nothing; a rebuild would have no flake to build from either. A hive deploy
|
||||
alone doesn't rebuild agents.
|
||||
The comparison reads the record and the marker
|
||||
(`/var/lib/hyperhive/applied/.<name>.closure`, written after a successful
|
||||
swap or create) and nothing on the forge. It rebuilds nothing when the hive
|
||||
can't tell: no connection to the swarm queue, no record, a closure the builder
|
||||
didn't push, or an agent with no marker. The last case covers every agent on
|
||||
the first boot after the marker arrived, so that boot rebuilds nothing; the
|
||||
agent's next deploy request from the swarm writes the marker. The periodic pass
|
||||
attempts a declared store path once per process, and skips an agent while a
|
||||
rebuild of it waits or runs, so a closure that fails to deploy doesn't
|
||||
restart its agent every five minutes. Restarting `hive-c0re`, or a rebuild from
|
||||
the agent's menu, tries again.
|
||||
|
||||
A stopped agent gets its rebuild at its next start: the start path upgrades
|
||||
the start of a stale, stopped agent to a rebuild followed by the start. In
|
||||
the window after a config merge, before the swarm's update has pinned the new
|
||||
config, that rebuild fails with the error that names the agent, and the
|
||||
agent stays stopped until the update lands and you ask for the start again.
|
||||
the window after a config merge, before the swarm's builder has recorded the
|
||||
new closure, the rebuild deploys the previous one.
|
||||
|
||||
The dashboard surfaces pending config changes per agent: a clickable
|
||||
"needs update ↻" badge appears whenever the config commit that `internal/meta`
|
||||
pins for the agent's next build differs from the one its last build pinned. The badge POSTs `/api/rebuild/<name>`, which inserts the
|
||||
same `job_queue::templates::rebuild` DAG so manual triggers and the
|
||||
startup scan can't drift. When at least one container is stale, a
|
||||
top-level `↻ UPD4TE 4LL` button appears that loops over every
|
||||
stale container.
|
||||
The dashboard shows no pending-update state: the hive applies a changed
|
||||
declaration itself. The agent menu's rebuild queues the same
|
||||
`job_queue::templates::rebuild` DAG, which downloads and applies the declared
|
||||
closure again.
|
||||
|
|
|
|||
|
|
@ -544,8 +544,8 @@ Isolation still holds by default: a container has its *own* dirs and,
|
|||
unless it holds the permission, nothing else.
|
||||
|
||||
Under `/var/lib/hyperhive/applied/` — the hive-c0re-only deploy markers
|
||||
`.<name>.hyperhive-rev` and `.<name>.config-rev`: the hyperhive and config
|
||||
commits the agent's last successful build pinned. No config lives here; the
|
||||
`.<name>.closure`: the store path of the closure the agent was last swapped to
|
||||
or created from. No config lives here; the
|
||||
forge's `agent-configs/<name>` is the only copy. A hive that predates this
|
||||
finds per-agent `applied/<name>` repos here. Nothing reads them any more, and
|
||||
you can delete them.
|
||||
|
|
|
|||
Loading…
Reference in a new issue