refactor(nix): a hive's domain comes out of the swarm directory

`services.hyperhive.domain` and `swarm.hives.<hiveName>.domain` were two
homes for one value with nothing asserting they agreed. The failure that
buys is the worst shape a config defect has: it evaluates cleanly, and
the symptom ("the other hives can't reach me") appears on a machine
other than the misconfigured one.

The directory is now the single source. `hives.<name>.domain` gains the
`<name>.<swarm.domain>` default -- a derivation from two values an
operator had to state explicitly, not a guess -- so a conventional swarm
is a list of names and a hive addressed by something else says so in the
one place every other hive reads. `services.hyperhive.domain` reads its
own entry; the direct formula is deleted rather than kept as a fallback,
which would have restored the second path (and, reading `swarm.domain`
itself, a second path that can disagree).

Setting it directly still wins, with a deprecation warning: nothing
breaks today, but a value written only there is invisible to the swarm.

The self-entry assertion now fires on an EMPTY directory too. Since
`swarm.domain` became required, every hive is in a swarm -- a swarm of
one is still a swarm -- and this host's address is read out of the
directory, so the entry is missing either way and the precise message
should be the one that fires.

Upgrading costs one line on hives that never listed themselves:
`services.hyperhive.swarm.hives.<hiveName> = { };`, no value.
This commit is contained in:
atlas 2026-08-05 21:48:20 +02:00 committed by mara
commit 3b6576faee
5 changed files with 221 additions and 122 deletions

View file

@ -87,14 +87,18 @@ listener on `bridgeIp` is on the host's bridge interface.
{
services.hyperhive = {
enable = true;
domain = "darkest.space";
# network.bridgeIp = "10.42.0.1"; # default
hiveName = "pr1ma";
swarm.domain = "darkest.space";
swarm.hives.pr1ma = { }; # -> domain = pr1ma.darkest.space
# network.bridgeIp = "10.42.0.1"; # default
};
}
```
Requires `services.hyperhive.domain` to be set — the dnsmasq resolver
is authoritative for `<hive-domain>` and its sub-domains.
is authoritative for `<hive-domain>` and its sub-domains. You do not
write it: it is read from this hive's entry in the swarm directory
(`docs/swarm/README.md` § Hive identity config).
## Bridge addressing

View file

@ -22,8 +22,14 @@ the additional config needed when the swarm spans multiple hosts.
services.hyperhive = {
swarm.domain = "example.com"; # required — the swarm's DNS domain
hiveName = "pr1ma"; # required — this hive's label in it
# domain = "pr1ma.example.com"; # derived from the two above
swarm.name = "constellat1on"; # shared swarm display name (optional)
# required — the directory, identical on every host in the swarm.
# Names only: each entry's `domain` defaults to <name>.<swarm.domain>.
swarm.hives = {
pr1ma = { };
edge = { };
};
};
```
@ -34,12 +40,22 @@ and deploys — an eval failure asking the operator to write the address
down is the cheaper outcome. **Upgrading past this release means setting
both once.**
`domain` is required too, but you no longer have to *write* it: it
defaults to `<hiveName>.<swarm.domain>`, since every hive in a swarm
occupies its own sub-domain of it. A hive that pins `domain` explicitly
keeps exactly the value it has today — that's why this is a default and
not a rename: re-rooting where a value *comes from* must not reinterpret
the values already deployed.
`domain` is required too, but you no longer *write* it: it is read from
this hive's own entry in the directory, whose `domain` defaults to
`<name>.<swarm.domain>`. So a conventional swarm states no addresses at
all, and a hive addressed by something else states it in the one place
the other hives read — `swarm.hives.edge.domain = "edge.elsewhere.example";`.
Setting `services.hyperhive.domain` directly still works and still wins,
with a **deprecation warning**. The reason it's deprecated is not tidiness:
that option is local to one host, the directory is copied to every host,
so a value written only there leaves every peer pointing somewhere else
with nothing detecting the disagreement.
⚠️ **Upgrading:** a hive that has been running on `swarm.domain` +
`hiveName` alone now needs its own directory entry —
`services.hyperhive.swarm.hives.<hiveName> = { };`, one line, no value.
Eval fails naming it if you forget.
`domain` drives `HYPERHIVE_HIVE_DOMAIN` in every container so agents can
form qualified labels (`iris@pr1ma.example.com`).