The single module-eval derivation forced ~62 full nixosSystem fixtures live at once to compute its cases list: 10.6GB peak RSS / 5m25s to evaluate, by far the dominant cost in nix flake check. Splits it into 21 independent checks.module-eval-* derivations (1-7 fixtures each) sharing builders/helpers via module-eval/lib.nix, so no single derivation needs more than a handful of fixtures live at once. A few cases spanning two clusters carry a small duplicated fixture rather than threading shared state through lib.nix.
128 lines
5 KiB
Nix
128 lines
5 KiB
Nix
# `checks.module-eval-swarm-services-switch` — see ./lib.nix for the shared
|
|
# rationale (why this suite exists, naming convention, "evaluates
|
|
# not executes").
|
|
{
|
|
pkgs,
|
|
lib,
|
|
self,
|
|
nixosSystem,
|
|
}:
|
|
let
|
|
inherit
|
|
(import ./lib.nix {
|
|
inherit
|
|
pkgs
|
|
lib
|
|
self
|
|
nixosSystem
|
|
;
|
|
})
|
|
hive
|
|
runGroup
|
|
bridgePortsOrNone
|
|
swarmServiceEnables
|
|
;
|
|
|
|
# The swarm-services toggle with the central one off, so the only thing
|
|
# that can enable the gateway/resolver/bridge here is that toggle's own
|
|
# module — every other module that asserts them is behind `enable`.
|
|
swarmServicesOnly = hive {
|
|
enable = false;
|
|
deploy.allSwarmServices = true;
|
|
};
|
|
|
|
# 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;
|
|
};
|
|
|
|
# The swarm's shared services hosted HERE without the all-local mode — a
|
|
# services box with hives elsewhere, the shape ./host-modules/
|
|
# swarm-required-services.nix documents the switch for.
|
|
swarmServicesHere = hive { deploy.allSwarmServices = true; };
|
|
|
|
# Same, with one of those services placed on another host. Every derivation
|
|
# in that module is `mkDefault` so this stays expressible.
|
|
swarmServicesBaoElsewhere = hive {
|
|
deploy.allSwarmServices = true;
|
|
deploy.bao.enable = false;
|
|
};
|
|
cases = [
|
|
{
|
|
# `lib.all` over an empty set holds vacuously, so the roster is counted
|
|
# before it is read: a helper that lost a member would otherwise turn
|
|
# this case green by measuring nothing.
|
|
name = "hosting the swarm's shared services turns on every service that switch owns";
|
|
ok =
|
|
let
|
|
es = swarmServiceEnables swarmServicesHere;
|
|
in
|
|
lib.length (lib.attrNames es) == 9 && lib.all lib.id (lib.attrValues es);
|
|
}
|
|
{
|
|
# The switch fills in for an operator who has not spoken and yields to
|
|
# one who has — that is what keeps a shared service placeable on a host
|
|
# of its own. A plain assignment or `mkForce` would satisfy both cases
|
|
# above and break this one. `nats` is the control: without it the case
|
|
# also passes on a fixture where nothing came on at all.
|
|
name = "placing one shared service elsewhere survives the switch that would enable it";
|
|
ok =
|
|
let
|
|
es = swarmServiceEnables swarmServicesBaoElsewhere;
|
|
in
|
|
!es.bao && es.nats;
|
|
}
|
|
{
|
|
# The controller sits on the OTHER tier: `singleHostSwarm` places it
|
|
# (./host-modules/local-defaults.nix) and swarm-ui follows the
|
|
# controller. Pinned so that moving a service between tiers is a
|
|
# decision someone makes rather than a merge nobody reads.
|
|
name = "hosting the swarm's shared services does not make a hive the swarm's control plane";
|
|
ok =
|
|
!swarmServicesHere.services.hyperhive.deploy.swarm-controller.enable
|
|
&& !swarmServicesHere.services.hyperhive.deploy.swarm-ui.enable;
|
|
}
|
|
{
|
|
# 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);
|
|
}
|
|
{
|
|
name = "the swarm UI claims the swarm apex where this host serves it";
|
|
ok = swarmUiHere.services.nginx.virtualHosts ? "t.local";
|
|
}
|
|
{
|
|
# The swarm-services toggle enables them explicitly, from its own
|
|
# module rather than from any of their defaults.
|
|
name = "the swarm-services toggle turns on the gateway, resolver and bridge by itself";
|
|
ok =
|
|
swarmServicesOnly.services.hyperhive.gateway.enable
|
|
&& swarmServicesOnly.services.hyperhive.gateway.dns.enable
|
|
&& swarmServicesOnly.services.hyperhive.network.enable;
|
|
}
|
|
{
|
|
# An operator's explicit `false` beats every `mkDefault` assertion,
|
|
# which is what keeps "asserted by whoever needs it" from being a
|
|
# setting the operator cannot turn off.
|
|
name = "an explicit gateway.enable = false wins over the modules asserting it";
|
|
ok = !(hive { gateway.enable = false; }).services.nginx.enable;
|
|
}
|
|
];
|
|
in
|
|
runGroup "swarm-services-switch" cases
|