fix(nix): require swarm domain only when a hyperhive service is enabled
The swarm.domain assertion in hive-network.nix fired on every host that imported the module, so a host that enables nothing failed eval. It now fires only when one of the hyperhive service switches is on (every deploy.*.enable that runs something, gateway, gateway.dns, network, otel, snapshotStore). The requirement itself is unchanged: any host that runs a hyperhive service still needs swarm.domain. The core-toggle module-eval suite gains a case: a missing swarm.domain is refused on a hive and on a swarm-service-only host, and a host enabling nothing passes every assertion. Closes #4887
This commit is contained in:
parent
eded8f2e4e
commit
fb2fff0668
4 changed files with 71 additions and 13 deletions
|
|
@ -27,6 +27,38 @@ let
|
|||
hostCount = pow2 (32 - cfg.bridgePrefixLength);
|
||||
# Mask off host bits to get the network base address.
|
||||
networkBase = builtins.bitAnd (ipToInt cfg.bridgeIp) (4294967295 - hostCount + 1);
|
||||
|
||||
# Every switch that runs a hyperhive service on this host. Left out:
|
||||
# `github.enable` (on by default, runs nothing by itself), the gateway's
|
||||
# and matrix's sub-features, and `allSwarmServices`/`singleHostSwarm`,
|
||||
# which only take effect through the switches listed here.
|
||||
anyServiceEnabled =
|
||||
let
|
||||
h = config.services.hyperhive;
|
||||
d = h.deploy;
|
||||
in
|
||||
lib.any lib.id [
|
||||
d.hive-controller.enable
|
||||
d.swarm-controller.enable
|
||||
d.swarm-ui.enable
|
||||
d.forgejo.enable
|
||||
d.forgejo.ci.enable
|
||||
d.matrix.enable
|
||||
d.authelia.enable
|
||||
d.bao.enable
|
||||
d.nats.enable
|
||||
d.swarm-otel.enable
|
||||
d.grafana.enable
|
||||
d.victoriametrics.enable
|
||||
d.victorialogs.enable
|
||||
d.swarm-secret-publisher.enable
|
||||
d.wireguard.enable
|
||||
h.gateway.enable
|
||||
h.gateway.dns.enable
|
||||
h.network.enable
|
||||
h.otel.enable
|
||||
h.snapshotStore.enable
|
||||
];
|
||||
in
|
||||
{
|
||||
# Hive-internal network — the host-side bridge every container in a
|
||||
|
|
@ -187,25 +219,26 @@ in
|
|||
];
|
||||
})
|
||||
|
||||
# Un-gated: the swarm's options are identical on every host, so a host
|
||||
# running no hive and no swarm service needs the value too. The
|
||||
# `.invalid` fallbacks described above keep this message reachable.
|
||||
{
|
||||
# Gated on any hyperhive service, not only the hive: the swarm's options
|
||||
# are identical on every host, so a host running only a swarm service
|
||||
# needs the value too. The `.invalid` fallbacks described above keep
|
||||
# this message reachable.
|
||||
(lib.mkIf anyServiceEnabled {
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.services.hyperhive.swarm.domain != null;
|
||||
message = ''
|
||||
hyperhive requires services.hyperhive.swarm.domain to be set
|
||||
on every host, to the same value on every host of the swarm —
|
||||
the DNS domain of the swarm, of which each hive occupies one
|
||||
sub-domain. A guessed value would be a wrong hostname that
|
||||
evaluates cleanly and deploys. Set it
|
||||
on every host that runs a hyperhive service, to the same value
|
||||
on every host of the swarm — the DNS domain of the swarm, of
|
||||
which each hive occupies one sub-domain. A guessed value would
|
||||
be a wrong hostname that evaluates cleanly and deploys. Set it
|
||||
(`services.hyperhive.swarm.domain = "example.com";`) — with
|
||||
`hiveName` it also derives `services.hyperhive.domain` for you.
|
||||
'';
|
||||
}
|
||||
];
|
||||
}
|
||||
})
|
||||
|
||||
# The bridge itself, up only where something hangs off it. Private
|
||||
# netns is still the only container mode.
|
||||
|
|
|
|||
|
|
@ -117,8 +117,10 @@ in
|
|||
`services.hyperhive.hiveName`, list the hives by name, and no
|
||||
hive in the swarm states an address at all.
|
||||
|
||||
**Required** on every host that imports this module, with the
|
||||
same value on every host of the swarm, and deliberately not
|
||||
**Required** on every host that runs a hyperhive service (a
|
||||
`services.hyperhive.deploy.*` service, the gateway, the bridge,
|
||||
`otel` or the snapshot store), with the same value on every host
|
||||
of the swarm, and deliberately not
|
||||
defaulted. A guessed swarm domain is a wrong hostname that
|
||||
evaluates cleanly and deploys, which is worse than an eval
|
||||
failure telling an operator to write down the one address their
|
||||
|
|
|
|||
|
|
@ -503,6 +503,28 @@ let
|
|||
}
|
||||
&& !(refusedHiveName { deploy.hive-controller.enable = false; });
|
||||
}
|
||||
{
|
||||
# Refused wherever any hyperhive service runs, the hive or a swarm
|
||||
# service alone. The host enabling nothing is the control that it is
|
||||
# gated at all, and has to pass every assertion: it is what an
|
||||
# operator gets from importing the module.
|
||||
name = "a missing swarm.domain is refused on a hive and on a swarm-service host, and a host enabling nothing evaluates";
|
||||
ok =
|
||||
let
|
||||
noDomain = extra: hive ({ swarm.domain = null; } // extra);
|
||||
refusedSwarmDomain =
|
||||
extra:
|
||||
lib.any (
|
||||
a: !a.assertion && lib.hasInfix "services.hyperhive.swarm.domain to be set" a.message
|
||||
) (noDomain extra).assertions;
|
||||
in
|
||||
refusedSwarmDomain { }
|
||||
&& refusedSwarmDomain {
|
||||
deploy.hive-controller.enable = false;
|
||||
deploy.nats.enable = true;
|
||||
}
|
||||
&& lib.all (a: a.assertion) (noDomain { deploy.hive-controller.enable = false; }).assertions;
|
||||
}
|
||||
];
|
||||
in
|
||||
runGroup "core-toggle" cases
|
||||
|
|
|
|||
Loading…
Reference in a new issue