Watch
0
0
Fork
You've already forked hyperhive
0

move hiveName to deploy.hive-controller; only a hive host needs a name

This commit is contained in:
atlas 2026-10-26 16:06:11 +01:00 • committed by mara
commit 0c6e8fc5a2
37 changed files with 402 additions and 215 deletions

View file

@ -9,6 +9,7 @@
}:
let
hiveCfg = config.services.hyperhive;
hiveName = hiveCfg.deploy.hive-controller.hiveName;
in
{
imports = [
@ -46,8 +47,8 @@ in
# would recreate the second path (and, since that default reads
# `swarm.domain` too, a value that can differ from the directory's).
default =
if hiveCfg.hiveName != null && hiveCfg.swarm.hives ? ${hiveCfg.hiveName} then
hiveCfg.swarm.hives.${hiveCfg.hiveName}.domain
if hiveName != null && hiveCfg.swarm.hives ? ${hiveName} then
hiveCfg.swarm.hives.${hiveName}.domain
else
null;
defaultText = lib.literalExpression "services.hyperhive.swarm.hives.\${hiveName}.domain, or null when there is no entry for this hive";
@ -90,7 +91,7 @@ in
hive's address belongs in the swarm directory, which every hive in
the swarm shares a copy of:
services.hyperhive.swarm.hives."${toString hiveCfg.hiveName}".domain = "${toString hiveCfg.domain}";
services.hyperhive.swarm.hives."${toString hiveName}".domain = "${toString hiveCfg.domain}";
(Or drop the value entirely if it is the conventional
`<hiveName>.<swarm.domain>` — that is the directory entry's own
@ -115,7 +116,7 @@ in
occupies its own sub-domain of it, which is why every entry in
`services.hyperhive.swarm.hives` defaults its `domain` to
`<name>.<swarm.domain>` — set this plus
`services.hyperhive.hiveName`, list the hives by name, and no
`services.hyperhive.deploy.hive-controller.hiveName`, list the hives by name, and no
hive in the swarm states an address at all.
**Required** on every host that runs a hyperhive service (a
@ -129,56 +130,69 @@ in
'';
};
# Human display name for this hive. Distinct from the DNS domain
# above (machine-readable) — see docs/process/conventions.md::Hive identity
# for the domain-vs-name-vs-swarm distinction + the env-var
# propagation chain. The swarm's display name is
# `services.hyperhive.swarm.name`, one level out: this hive is named
# here, the swarm it belongs to is named there.
options.services.hyperhive.hiveName = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "pr1ma";
description = ''
Human-readable name of this single-host hive instance.
**Required** when this host runs a hive, the swarm's secret store
or its homeserver
(`services.hyperhive.deploy.hive-controller.enable`,
`deploy.bao.enable`, `deploy.matrix.enable`). Distinct from
`services.hyperhive.domain` (the machine-addressable DNS name)
and not merely cosmetic: a hive occupies
`<hiveName>.<swarm.domain>`, so this is the label the hive is
*addressed* by as well as the one it is called. Exposed to
agents as `HYPERHIVE_HIVE_NAME`; surfaced in the dashboard
chrome and per-agent system prompt.
'';
};
# Each of these deployments turns `hiveName` into an identifier with no
# fallback: hive-c0re's OIDC client and matrix localpart, the CN of the
# store's `client.pem` (./glue-bao-tls.nix), and the `hives/<name>` path
# the queue credential reader fetches. A null there renders
# as an empty string that evaluates and deploys.
# The hive's name is `deploy.hive-controller.hiveName`, declared in
# ./deploy.nix beside the switch that makes a host run a hive. The
# identity surfaces (label, domain, display names, env-var chain) are in
# docs/process/conventions.md::Hive identity.
#
# A hive turns the name into an identifier with no fallback: hive-c0re's
# OIDC client and matrix localpart, the CN of the hive's `client.pem`
# (./glue-bao-tls.nix), and the `hives/<name>` path of its secrets. A null
# there renders as an empty string that evaluates and deploys.
config.assertions = [
{
assertion =
!(
hiveCfg.deploy.hive-controller.enable || hiveCfg.deploy.bao.enable || hiveCfg.deploy.matrix.enable
)
|| hiveCfg.hiveName != null;
assertion = !hiveCfg.deploy.hive-controller.enable || hiveName != null;
message = ''
hyperhive requires services.hyperhive.hiveName to be set on a host
that runs a hive, the swarm's secret store or its homeserver — it is
this hive's label within the swarm, and the leftmost part of the
domain it is addressed by (`<hiveName>.<swarm.domain>`), not only a
display name. Set it (`services.hyperhive.hiveName = "pr1ma";`).
hyperhive requires services.hyperhive.deploy.hive-controller.hiveName
to be set on a host that runs a hive — it is this hive's label
within the swarm, and the leftmost part of the domain it is
addressed by (`<hiveName>.<swarm.domain>`), not only a display name.
Set it (`services.hyperhive.deploy.hive-controller.hiveName = "pr1ma";`).
'';
}
{
# An EMPTY `hives` fires this too, deliberately: since
# `swarm.domain` is required, every hive is in a swarm — a swarm of
# one is still a swarm — so a directory with no entry for this host
# is missing one either way. It also has to fire here, because this
# host's own domain is read out of the directory: without the entry
# `services.hyperhive.domain` is null and the generic required-domain
# assertion in ./hive-network.nix would fire instead, naming an
# option the operator should not be setting.
#
# Guarded on `hiveName != null` so the required-hiveName assertion
# above is what fires for that case — two assertions naming the same
# missing value is noise.
assertion =
!hiveCfg.deploy.hive-controller.enable || hiveName == null || hiveCfg.swarm.hives ? ${hiveName};
message = ''
services.hyperhive.swarm.hives has no entry for this hive
(services.hyperhive.deploy.hive-controller.hiveName = "${toString hiveName}").
`hives` describes every hive in the swarm including this one,
so that every host can share one identical attrset, and this
hive's own domain is derived from its entry. Add:
services.hyperhive.swarm.hives."${toString hiveName}" = { };
No fields are needed: `domain` defaults to
`<name>.<swarm.domain>`. Set it in the entry if this hive is
addressed by something else.
Declared hives: ${lib.concatStringsSep ", " (lib.attrNames hiveCfg.swarm.hives)}
'';
}
];
config.services.hyperhive.deploy.hive-controller.dashboardDomain =
if hiveName != null && hiveCfg.swarm.dashboardDomains ? ${hiveName} then
hiveCfg.swarm.dashboardDomains.${hiveName}
else
null;
# The one hive-level option that describes something ABOVE the hive,
# which is why it sits under `swarm` with the swarm-global services
# rather than beside `hiveName`.
# rather than beside the hive's name.
options.services.hyperhive.swarm.name = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;