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 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 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 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 ⚠️ **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 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" ]; wants = lib.optionals baoDeploy.enable [ "container@${baoCfg.machine}.service" ];
requires = lib.optionals baoDeploy.enable [ "swarm-bao-pki.service" ]; requires = lib.optionals baoDeploy.enable [ "swarm-bao-pki.service" ];
# Ordered `Before=` nothing, because the consumer does not exist yet. # Ordered before hive-c0re, so no agent container renders ahead of an
# Agent containers are created at runtime, so no static unit name can be # attempt at its credential. `Wants=`, not `Requires=`: a store this
# named here anyway; the slice that bind-mounts these files in adds the # unit can't reach delays hive-c0re's start by its own start-limit
# edge through hive-c0re's `container@h-<agent>.service` drop-in. # window (`TimeoutStartSec`, retried up to `startLimitBurst` times
wantedBy = [ "multi-user.target" ]; # 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 = [ path = [
baoDeploy.package baoDeploy.package
pkgs.coreutils pkgs.coreutils

View file

@ -1226,6 +1226,22 @@ let
name = "the queue credential reader's journal reaches the collector"; name = "the queue credential reader's journal reaches the collector";
ok = builtins.elem "swarm-bao-queue-agent" baoRemoteReader.services.hyperhive.swarm.otel.journaldUnits; 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 # 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, # keep: a client is defined by holding a certificate the store accepts,