swarm: run the agent queue credential reader before hive-c0re

Ruled: swarm-bao-queue-agent.service must run before hive-c0re.service
and be wanted (not required) by it, so no agent container renders
ahead of the reader's attempt at its credential. An unreachable store
delays hive-c0re's start by the reader's own start-limit window rather
than failing it outright.

Refs #4314
This commit is contained in:
atlas 2026-09-13 00:57:59 +02:00 committed by mara
commit f8dd737456
3 changed files with 31 additions and 6 deletions

View file

@ -163,7 +163,10 @@ The **second reader** is the agent containers' queue credential:
the client id it authenticates, because that's how a queue client reads them —
the secret by path, the id by value. No local fallback exists, and none is
possible, so absent files mean this hive's agents don't connect, which is what
a swarm looks like before the publisher on the authelia host has run.
a swarm looks like before the publisher on the authelia host has run. The
reader runs before `hive-c0re.service` and is wanted (not required) by it, so
an agent container never renders ahead of the credential; an unreachable store
delays the daemon's start rather than failing it.
⚠️ **Service↔store mTLS is its own trust domain.** A credential you must
already hold to authenticate can't be fetched from the thing it authenticates

View file

@ -103,11 +103,17 @@ in
];
wants = lib.optionals baoDeploy.enable [ "container@${baoCfg.machine}.service" ];
requires = lib.optionals baoDeploy.enable [ "swarm-bao-pki.service" ];
# Ordered `Before=` nothing, because the consumer does not exist yet.
# Agent containers are created at runtime, so no static unit name can be
# named here anyway; the slice that bind-mounts these files in adds the
# edge through hive-c0re's `container@h-<agent>.service` drop-in.
wantedBy = [ "multi-user.target" ];
# Ordered before hive-c0re, so no agent container renders ahead of an
# attempt at its credential. `Wants=`, not `Requires=`: a store this
# unit can't reach delays hive-c0re's start by its own start-limit
# window (`TimeoutStartSec`, retried up to `startLimitBurst` times
# below) rather than failing it — hive-c0re starts once that window
# elapses, whatever credential is or isn't on disk by then.
before = [ "hive-c0re.service" ];
wantedBy = [
"multi-user.target"
"hive-c0re.service"
];
path = [
baoDeploy.package
pkgs.coreutils

View file

@ -1226,6 +1226,22 @@ let
name = "the queue credential reader's journal reaches the collector";
ok = builtins.elem "swarm-bao-queue-agent" baoRemoteReader.services.hyperhive.swarm.otel.journaldUnits;
}
{
# No agent container may render before this unit has had its attempts,
# and the edge that guarantees it must delay hive-c0re rather than sink
# it: an unreachable store is this unit's `Restart=on-failure` window,
# not a reason for the daemon that renders every agent to fail its own
# start.
name = "the queue credential reader orders before hive-c0re and is wanted, not required, by it";
ok =
let
u = baoRemoteReader.systemd.services.swarm-bao-queue-agent;
in
builtins.elem "hive-c0re.service" (u.before or [ ])
&& builtins.elem "hive-c0re.service" (u.wantedBy or [ ])
&& !(builtins.elem "hive-c0re.service" (u.requiredBy or [ ]))
&& !(builtins.elem "hive-c0re.service" (u.requires or [ ]));
}
{
# The doctrine three glue files state, as a property a rewrite has to
# keep: a client is defined by holding a certificate the store accepts,