Watch
0
0
Fork
You've already forked hyperhive
0

force each container's unit configs in the checks about it

This commit is contained in:
atlas 2026-10-25 20:48:42 +01:00 • committed by mara
commit 549c198449
6 changed files with 46 additions and 16 deletions

View file

@ -24,6 +24,7 @@ let
baoSettings baoSettings
baoStream baoStream
bridgePorts bridgePorts
forceServiceConfigs
; ;
baoPkcs11 = hive { baoPkcs11 = hive {
@ -55,6 +56,12 @@ let
tlsDir = "/var/lib/swarm-bao-tls"; tlsDir = "/var/lib/swarm-bao-tls";
cases = [ cases = [
{
# Every unit in the container merges without a priority collision, not
# only the keys the cases here read.
name = "the store's container units merge without a priority collision";
ok = forceServiceConfigs baoPkcs11.containers.swarm-bao.config;
}
{ {
# The store's seal is spread over six gates — the stanza, the # The store's seal is spread over six gates — the stanza, the
# provisioning unit, two bind mounts, a device and an EnvironmentFile. # provisioning unit, two bind mounts, a device and an EnvironmentFile.

View file

@ -20,6 +20,7 @@ let
}) })
hive hive
runGroup runGroup
forceServiceConfigs
; ;
# Store and controller on one machine, with a CN no default could supply. # Store and controller on one machine, with a CN no default could supply.
@ -109,6 +110,12 @@ let
a: !a.assertion && lib.hasInfix "swarm-controller.baoClientCertFile and" a.message a: !a.assertion && lib.hasInfix "swarm-controller.baoClientCertFile and" a.message
) m.assertions; ) m.assertions;
cases = [ cases = [
{
# Every unit in the container merges without a priority collision, not
# only the keys the cases here read.
name = "the store's container units merge without a priority collision beside the controller";
ok = forceServiceConfigs baoControllerHere.containers.swarm-bao.config;
}
{ {
# The queue client secret lives only in the store, so a controller that # The queue client secret lives only in the store, so a controller that
# cannot log in there cannot reach the queue. Refused at eval rather than # cannot log in there cannot reach the queue. Refused at eval rather than

View file

@ -21,6 +21,7 @@ let
hive hive
hiveWithController hiveWithController
runGroup runGroup
forceServiceConfigs
; ;
# The store and a service that reads from it, versus the store alone. The # The store and a service that reads from it, versus the store alone. The
@ -61,6 +62,12 @@ let
}; };
cases = [ cases = [
{
# Every unit in the container merges without a priority collision, not
# only the keys the cases here read.
name = "the homeserver's container units merge without a priority collision";
ok = forceServiceConfigs baoWithMatrix.containers.hive-matrix.config;
}
{ {
# A hive holds no shared queue credential for its agents, wherever the # A hive holds no shared queue credential for its agents, wherever the
# store runs. The control: hive-c0re renders on both hosts. # store runs. The control: hive-c0re renders on both hosts.

View file

@ -21,6 +21,7 @@ let
hive hive
runGroup runGroup
baoSettings baoSettings
forceServiceConfigs
; ;
baoTwoAddresses = hive { baoTwoAddresses = hive {
@ -75,6 +76,12 @@ let
scrapeJob = scrapeJobIn "swarm-otel"; scrapeJob = scrapeJobIn "swarm-otel";
baoScrapeJob = scrapeJobIn "swarm-bao"; baoScrapeJob = scrapeJobIn "swarm-bao";
cases = [ cases = [
{
# Every unit in the container merges without a priority collision, not
# only the keys the cases here read.
name = "the store's container units merge without a priority collision";
ok = forceServiceConfigs baoWithCollector.containers.swarm-bao.config;
}
{ {
# Same gap one tier up, and it needs its own arm: this collector # Same gap one tier up, and it needs its own arm: this collector
# already had six scrape targets, so a pass here is about the seventh # already had six scrape targets, so a pass here is about the seventh

View file

@ -21,6 +21,7 @@ let
hive hive
hiveWithController hiveWithController
runGroup runGroup
forceServiceConfigs
baoNames baoNames
baoStream baoStream
bridgePorts bridgePorts
@ -84,21 +85,6 @@ let
deploy.review-classifier.enable = true; deploy.review-classifier.enable = true;
}; };
# A priority collision is a property of the *option*, not
# of the merged value's interior — nix throws the moment the value is
# demanded at all, so `seq`-ing each `serviceConfig` value to WHNF is
# both necessary and sufficient. `deepSeq` over-specifies this: it keeps
# walking *into* the resulting value after the merge already succeeded,
# and a package/derivation-shaped value's `override`/`overrideAttrs`
# self-reference sends it into nixpkgs' fixpoint machinery and blows the
# stack (measured — this is not a hypothetical).
forceCiServiceConfigs =
let
svcs = withCi.containers.swarm-ci-runner.config.systemd.services;
vals = lib.concatMap (s: builtins.attrValues (s.serviceConfig or { })) (builtins.attrValues svcs);
in
builtins.foldl' (acc: v: builtins.seq v acc) true vals;
# The host fetches that restart their consumer when the store's value # The host fetches that restart their consumer when the store's value
# changes (../host-modules/lib/refresh-consumer.nix), each on a fixture # changes (../host-modules/lib/refresh-consumer.nix), each on a fixture
# that renders it. # that renders it.
@ -692,7 +678,7 @@ let
# instantiates a host with `containers.swarm-ci-runner` actually enabled, so # instantiates a host with `containers.swarm-ci-runner` actually enabled, so
# the collision only surfaces on operator deploy, not in CI. # the collision only surfaces on operator deploy, not in CI.
name = "the CI container's unit definitions merge without a priority collision"; name = "the CI container's unit definitions merge without a priority collision";
ok = forceCiServiceConfigs; ok = forceServiceConfigs withCi.containers.swarm-ci-runner.config;
} }
{ {
# It spends money on an operator's key, so no host runs it by default. # It spends money on an operator's key, so no host runs it by default.

View file

@ -253,6 +253,21 @@ let
"echo 'module-eval-${name}: ${toString (builtins.length bad)} of ${toString (builtins.length cases)} properties broke' >&2 && exit 1" "echo 'module-eval-${name}: ${toString (builtins.length bad)} of ${toString (builtins.length cases)} properties broke' >&2 && exit 1"
} }
''; '';
# `serviceConfig` is an `attrsOf`: each key merges lazily, and a priority
# collision throws only when that key is demanded. A check reading
# `LoadCredential` therefore says nothing about `Restart`. Takes one
# container's `config`; `true` once every unit's every `serviceConfig` value
# is at WHNF. `seq` per value, not `deepSeq`: walking into a derivation-shaped
# value's `override` self-reference overflows the stack.
forceServiceConfigs =
containerCfg:
let
vals = lib.concatMap (s: builtins.attrValues (s.serviceConfig or { })) (
builtins.attrValues containerCfg.systemd.services
);
in
builtins.foldl' (acc: v: builtins.seq v acc) true vals;
in in
{ {
inherit hive; inherit hive;
@ -272,4 +287,5 @@ in
inherit carriesJournaldSeverity; inherit carriesJournaldSeverity;
inherit swarmServiceEnables; inherit swarmServiceEnables;
inherit runGroup; inherit runGroup;
inherit forceServiceConfigs;
} }