hyperhive/nix/host-modules
Repository files (latest commit first)
Filename Latest commit message Latest commit date
atlas 8891b46943 feat(swarm-controller): aggregate per-hive status from the swarm queue
The controller connects to the swarm queue as its own client and serves
what each hive last said about itself at GET /api/hives/status.

THE QUEUE IS THE STORE. A hive publishes into the `hive-status` JetStream
KV bucket (history 1) and the controller reads it per request, keeping no
copy. A cache here would be a second answer to the same question, free to
disagree with the first, and the disagreement surfaces as a hive reading
healthy on a dashboard while the bucket says otherwise. Whichever side
arrives first creates the bucket; both want the same shape.

Rows come from the roster rather than from the bucket, so an empty bucket
renders as a swarm nobody has heard from instead of a healthy one, and
`never_reported` stays distinct from `stale` - went quiet is a fault,
never spoke is usually a deployment that has not happened. Freshness is
derived at read time and never stored as a flag, because a stored
`healthy` boolean goes stale silently the moment nothing arrives, which
is the failure this endpoint is designed against. The timestamp is the
NATS server's, applied when the value landed, so a publisher cannot make
itself look fresher than it is.

Authentication is per connection attempt, not per process. Authelia
issues `client_credentials` tokens that expire in 3599s, and auth happens
at CONNECT, so a long-lived connection is fine but a reconnect an hour
later needs a token minted an hour later. `with_auth_callback` is re-run
by async-nats for each attempt, which handles expiry by construction
rather than by a timer - the alternative fails in the way this subsystem
exists to prevent, with the controller still serving while its data
quietly stops updating.

Three failure shapes are deliberate:

- A half-set environment is fatal; an absent one is not. Silently
  behaving like an unconfigured host is how every hive ends up reading
  `never_reported` with nothing to point at.
- The endpoint answers 503 rather than an empty list when the store
  cannot be read. "I cannot reach the store" and "every hive is silent"
  are different answers, and rendering the second turns a local fault
  into an apparent swarm-wide outage.
- `retry_on_initial_connect` makes the daemon and the queue bootable in
  either order, and the status handler refuses when the client is not
  Connected rather than issuing a request into it - a request made in
  that window does not fail, it waits, so every poll would hang and
  learn nothing. `Pending` is the state a never-connected client is in,
  which is why the test is `!= Connected` and not `== Disconnected`.

The rendering rules are a pure function over a map, so the semantics are
tested against a table rather than against a running server. The KV read,
the credential rotation and the 503 paths are covered behaviourally
instead: a real NATS server with a rotating token endpoint, asserting
that the controller recovers only when the credential rotates, and
mutation-tested by holding the credential wrong for the same window.
2026-08-15 18:37:23 +02:00
..
hive-c0re feat(otel): one path out of the hive, not two 2026-08-15 11:46:24 +02:00
hive-forge swarm-controller: serve swarm-wide service quick links (hyperhive#3289) 2026-08-15 14:24:52 +02:00
hive-gateway docs(3202): state the file's scope positively 2026-08-14 09:52:44 +02:00
lib feat(nix): issue each hive's CA under a swarm root CA 2026-08-05 15:57:50 +02:00
default.nix feat(3112): the swarm-nats container, fail-closed 2026-08-14 16:26:12 +02:00
hive-ci.nix feat(nix): move the forge host options under services.hyperhive.swarm 2026-08-05 03:44:53 +02:00
hive-matrix.nix swarm-controller: serve swarm-wide service quick links (hyperhive#3289) 2026-08-15 14:24:52 +02:00
hive-network.nix docs(3191): the gateway's comments describe a host service, not a container 2026-08-12 12:20:28 +02:00
hive-priv.nix fix(#2573): also add /etc/tmpfiles.d to hive-priv ReadWritePaths (same EROFS class) 2026-07-18 16:39:20 +02:00
hive-tls.nix docs(3191): drop the migration history from the gateway comments 2026-08-12 13:26:58 +02:00
hyperhive.nix refactor(nix): a hive's domain comes out of the swarm directory 2026-08-05 22:43:17 +02:00
local-defaults.nix refactor(3202): all-local asserts the host's own /etc/hosts entries 2026-08-13 17:26:08 +02:00
otel.nix docs(otel): validateConfigFile is a parser, not a wiring check 2026-08-15 12:13:48 +02:00
swarm-authelia.nix feat(swarm-authelia): one machine client per hive in the roster 2026-08-15 14:26:05 +02:00
swarm-ca.nix fix(nix): a missing swarm-services leaf must not kill the whole gateway 2026-08-06 00:30:22 +02:00
swarm-controller.nix feat(swarm-controller): aggregate per-hive status from the swarm queue 2026-08-15 18:37:23 +02:00
swarm-nats.nix feat(swarm-authelia): let an oidc client say it is a machine client 2026-08-15 13:33:31 +02:00
swarm-peers-removed.nix refactor(nix): swarm.peers becomes swarm.hives, a directory of every hive 2026-08-05 20:44:16 +02:00
swarm-required-services.nix refactor(nix): make all-local a deployment mode, not a default 2026-08-05 19:41:11 +02:00
swarm-snapshot-store.nix refactor(#2862): keep the option at services.hyperhive.snapshotStore 2026-07-31 19:03:24 +02:00
swarm-ui.nix swarm-controller: serve swarm-wide service quick links (hyperhive#3289) 2026-08-15 14:24:52 +02:00
swarm-wireguard.nix refactor(nix): swarm.peers becomes swarm.hives, a directory of every hive 2026-08-05 20:44:16 +02:00
swarm.nix feat(3167): options + certificate name for the swarm UI 2026-08-12 17:29:13 +02:00