nix: drop the central-toggle conjunct from four compound gates
`services.hyperhive.enable` is going away (Refs #4500). These four blocks ANDed it with a second condition that was already the load-bearing one: the bridge-firewall hole asks whether an operator named any `network.exposeHostPorts`, and the three swarm-level services ask their own `deploy.*.enable`, each of which defaults false (swarm-ui derives from the controller's toggle, a sibling deployment decision) and none of which is derived from the hive toggle. So dropping the conjunct turns nothing on by itself — the remaining condition still decides. The way that claim fails is by something becoming unconditional, so module-eval gets absence arms for all four, each asserted on a host with the hive ON and on one with it OFF, plus the two controls that make the absences mean something. The swarm-controller arm is probed by the credential oneshot and by the daemon's `ExecStart` rather than by the unit name: hive-tls defines an environment key on that name, which leaves an inert fragment behind on any hive with a CA whether or not the controller runs there.
This commit is contained in:
parent
87970a8c93
commit
ce3b3d9467
5 changed files with 105 additions and 4 deletions
|
|
@ -276,7 +276,7 @@ in
|
|||
# is firewall-only by design: a host service that binds `0.0.0.0` already
|
||||
# serves the bridge IP, so an extra bridge-IP proxy would only collide
|
||||
# (EADDRINUSE) with it. Merges with the [ 80 443 ] gateway ports above.
|
||||
(lib.mkIf (config.services.hyperhive.enable && cfg.exposeHostPorts != [ ]) {
|
||||
(lib.mkIf (cfg.exposeHostPorts != [ ]) {
|
||||
networking.firewall.interfaces.${cfg.bridgeName}.allowedTCPPorts = cfg.exposeHostPorts;
|
||||
})
|
||||
];
|
||||
|
|
|
|||
|
|
@ -698,7 +698,7 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (config.services.hyperhive.enable && deployCfg.swarm-controller.enable) {
|
||||
config = lib.mkIf deployCfg.swarm-controller.enable {
|
||||
# The daemon and the oneshot that mints its credential — the second one
|
||||
# failing leaves the first running and unable to authenticate anywhere.
|
||||
services.hyperhive.swarm.otel.journaldUnits = [
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (config.services.hyperhive.enable && deployCfg.swarm-otel.enable) {
|
||||
config = lib.mkIf deployCfg.swarm-otel.enable {
|
||||
# The gateway name, inside `deployCfg.swarm-otel.enable` — that guard is the load-bearing
|
||||
# part. Every hive in a swarm may know this collector exists, but only
|
||||
# the host that RUNS it may claim the name; a client hive declaring the
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
config = lib.mkIf (config.services.hyperhive.enable && deployCfg.swarm-ui.enable) {
|
||||
config = lib.mkIf deployCfg.swarm-ui.enable {
|
||||
assertions = [
|
||||
{
|
||||
# The `_` default server already answers for the hive domain
|
||||
|
|
|
|||
|
|
@ -491,6 +491,43 @@ let
|
|||
machine:
|
||||
machine.networking.firewall.interfaces.${machine.services.hyperhive.network.bridgeName}.allowedTCPPorts;
|
||||
|
||||
# Same list, on a host that may not declare the interface at all: the
|
||||
# `[ 80 443 ]` block is what creates the attr, and it is off where the hive
|
||||
# is. Reading it through `bridgePorts` would throw rather than report an
|
||||
# empty exposure, which is precisely the state the cases below assert.
|
||||
bridgePortsOrNone =
|
||||
machine:
|
||||
(machine.networking.firewall.interfaces.${machine.services.hyperhive.network.bridgeName} or {
|
||||
allowedTCPPorts = [ ];
|
||||
}
|
||||
).allowedTCPPorts;
|
||||
|
||||
# A host that installs the modules and turns nothing on. The per-service
|
||||
# deployment toggles are what decide whether the swarm-level services render
|
||||
# here, and none of them is derived from the hive being on, so this renders
|
||||
# the same absences `bare` does — the arms below assert both, because a
|
||||
# service that had quietly become unconditional would still look right on
|
||||
# only one of them.
|
||||
centralToggleOff = hive { enable = false; };
|
||||
|
||||
# Ports asked for on such a host. The request is the whole condition: the
|
||||
# firewall hole exists because an operator named a port, not because the
|
||||
# hive is running, and an agent reaching a host service is a claim about
|
||||
# the host's own listeners either way.
|
||||
exposedPortsNoHive = hive {
|
||||
enable = false;
|
||||
network.exposeHostPorts = [ 5432 ];
|
||||
};
|
||||
|
||||
# The swarm UI where its own toggle is on — the control the absence arm
|
||||
# needs, since nothing else in this suite renders this vhost and an arm
|
||||
# saying "it is not there" would hold just as well if it were never there.
|
||||
# Package stubbed per this file's header: the vhost roots at it.
|
||||
swarmUiHere = hive {
|
||||
deploy.swarm-ui.enable = true;
|
||||
deploy.swarm-ui.package = pkgs.emptyDirectory;
|
||||
};
|
||||
|
||||
baoTwoAddresses = hive {
|
||||
deploy.bao.enable = true;
|
||||
deploy.bao.extraListenAddresses = [ "10.0.0.1" ];
|
||||
|
|
@ -3032,6 +3069,70 @@ let
|
|||
in
|
||||
!(s.listener ? metrics) && !(s ? telemetry);
|
||||
}
|
||||
{
|
||||
# The four blocks below used to be gated on the hive being enabled AND
|
||||
# their own condition. The second half was always the load-bearing one —
|
||||
# none of these conditions is derived from the hive toggle — so these
|
||||
# arms pin what the conjunct was doing: nothing. Each is written against
|
||||
# a host with the hive OFF as well as one with it on, because the way a
|
||||
# dropped conjunct fails is by making something unconditional, and that
|
||||
# shows up as a service appearing where nothing asked for it.
|
||||
name = "no bridge port is opened for an exposeHostPorts nobody set";
|
||||
ok =
|
||||
!(builtins.elem 5432 (bridgePortsOrNone bare))
|
||||
&& !(builtins.elem 5432 (bridgePortsOrNone centralToggleOff));
|
||||
}
|
||||
{
|
||||
# Control for the arm above, and the one place this slice is not inert:
|
||||
# the ports are opened because they were named, on a host that never
|
||||
# turned the hive on. The bridge firewall is the host's own, so there is
|
||||
# nothing here for the hive toggle to have been protecting.
|
||||
name = "a named exposeHostPorts opens its bridge port on the host's own say-so";
|
||||
ok = builtins.elem 5432 (bridgePortsOrNone exposedPortsNoHive);
|
||||
}
|
||||
{
|
||||
# `deploy.swarm-controller.enable`, which defaults false and is
|
||||
# deliberately not derived from the hive toggle — a swarm has one
|
||||
# controller, so the host that runs it says so itself.
|
||||
#
|
||||
# Probed by what the daemon needs in order to run, not by
|
||||
# `? swarm-controller`: ./host-modules/hive-tls.nix defines an
|
||||
# environment key on that unit name, which leaves the attr
|
||||
# present-but-inert (no `ExecStart`, empty `wantedBy`) on every hive
|
||||
# that has a CA — see the comment there. The credential oneshot has no
|
||||
# second definer, so its absence is the unambiguous half.
|
||||
name = "the swarm controller does not run unless this host is told to run it";
|
||||
ok =
|
||||
let
|
||||
inert =
|
||||
machine:
|
||||
!(machine.systemd.services ? swarm-controller-credential)
|
||||
&& !(
|
||||
(machine.systemd.services.swarm-controller or { serviceConfig = { }; }).serviceConfig ? ExecStart
|
||||
);
|
||||
in
|
||||
inert bare && inert centralToggleOff;
|
||||
}
|
||||
{
|
||||
# `deploy.swarm-otel.enable`, same shape: the swarm's collector is one
|
||||
# host's job, and the container is the whole of what it renders.
|
||||
name = "the swarm collector container is absent unless this host is told to run it";
|
||||
ok = !(bare.containers ? swarm-otel) && !(centralToggleOff.containers ? swarm-otel);
|
||||
}
|
||||
{
|
||||
# `deploy.swarm-ui.enable`, which defaults to the controller's toggle —
|
||||
# derived from a sibling deployment decision, still not from the hive
|
||||
# toggle. `t.local` is the fixtures' swarm domain, which is the apex the
|
||||
# UI claims; the arm below is what proves this vhost renders at all.
|
||||
name = "the swarm UI vhost is absent unless this host is told to serve it";
|
||||
ok =
|
||||
!(bare.services.nginx.virtualHosts ? "t.local")
|
||||
&& !(centralToggleOff.services.nginx.virtualHosts ? "t.local");
|
||||
}
|
||||
{
|
||||
name = "the swarm UI claims the swarm apex where this host serves it";
|
||||
ok = swarmUiHere.services.nginx.virtualHosts ? "t.local";
|
||||
}
|
||||
];
|
||||
|
||||
bad = builtins.filter (c: !c.ok) cases;
|
||||
|
|
|
|||
Loading…
Reference in a new issue