swarm-bao-forge-publisher starts on the deploy that adds it
The publisher was wanted only by container@hive-forge.service. A switch starts a new unit only through the targets that want it, and the container is already running, so the deploy that introduced the publisher left it dead until the next container restart or boot; the path unit cannot help, because the mint's only-once guard never rewrites the file. - The publisher is also wanted by multi-user.target, like swarm-secret-publish. - A token file that is not there yet exits 0 instead of waiting 120s and failing: the path unit runs the publisher when the mint writes it, so a switch with the forge container down does not fail. TimeoutStartSec is 60. - swarm-controller loses its After= on the publisher: a switch issues the two jobs separately, so it ordered nothing there, and the background re-read covers the gap. - The controller's background re-read logs at info once the backoff is capped, one line per five minutes, so a forge host that never got its publisher leaf stays visible; earlier retries stay at debug. Refs #4998
This commit is contained in:
parent
2d2d7529fc
commit
597fdebaf3
4 changed files with 52 additions and 32 deletions
|
|
@ -1057,12 +1057,13 @@ in
|
|||
# reason `hive-forge-oidc-secret` gives, and under the forge's own store
|
||||
# identity, so nothing here asks where the store or the controller is.
|
||||
#
|
||||
# It can only depend on the container being up, not on the in-container
|
||||
# oneshot that mints the token (containers run their own systemd instance,
|
||||
# invisible to this one by unit name), so it polls the same bounded way
|
||||
# `hive-forge-oidc-secret` does. It runs whenever the token can have
|
||||
# changed: each time the container starts (`wantedBy`), and each time the
|
||||
# file is written (`systemd.paths.swarm-bao-forge-publisher` below).
|
||||
# It runs at boot and on a switch that adds or changes it
|
||||
# (`multi-user.target`), each time the container starts, and each time the
|
||||
# mint writes the file
|
||||
# (`systemd.paths.swarm-bao-forge-publisher` below). The mint is a oneshot in
|
||||
# the container's own systemd, invisible to this one by unit name, so a
|
||||
# missing file is not an error: the path unit runs this again when the mint
|
||||
# writes it, the shape of `swarm-secret-publish`.
|
||||
#
|
||||
# ⚠️ No `RemainAfterExit`. A oneshot that stays `active (exited)` turns
|
||||
# every later start into a no-op, so neither trigger would run it again.
|
||||
|
|
@ -1085,21 +1086,22 @@ in
|
|||
];
|
||||
wants = lib.optionals deployCfg.bao.enable [ "container@${baoCfg.machine}.service" ];
|
||||
requires = lib.optionals deployCfg.bao.enable [ "swarm-bao-pki.service" ];
|
||||
wantedBy = [ "container@hive-forge.service" ];
|
||||
wantedBy = [
|
||||
"multi-user.target"
|
||||
"container@hive-forge.service"
|
||||
];
|
||||
path = [
|
||||
deployCfg.bao.package
|
||||
pkgs.coreutils
|
||||
];
|
||||
# ../lib/store-retry.nix: a sealed or unreachable store is retried, and
|
||||
# so is a token the forge has not minted yet.
|
||||
# ../lib/store-retry.nix: a sealed or unreachable store is retried.
|
||||
inherit (storeRetry) startLimitBurst startLimitIntervalSec;
|
||||
serviceConfig = storeRetry.serviceConfig // {
|
||||
Type = "oneshot";
|
||||
SyslogIdentifier = "swarm-bao-forge-publisher";
|
||||
# Longer than the 120s bounded wait below. `DefaultTimeoutStartSec`
|
||||
# is 90s, so without this systemd kills the unit at 90 — before it
|
||||
# can emit the message naming the file it was waiting for.
|
||||
TimeoutStartSec = "180s";
|
||||
# Bounded here so the number a switch waits on is in this file. A sealed
|
||||
# store answers on the port and never answers the write.
|
||||
TimeoutStartSec = 60;
|
||||
};
|
||||
environment = {
|
||||
BAO_ADDR = "https://${baoCfg.domain}:${toString baoCfg.port}";
|
||||
|
|
@ -1123,13 +1125,9 @@ in
|
|||
|
||||
src=${lib.escapeShellArg swarmControllerTokenHostPath}
|
||||
|
||||
for _ in $(seq 1 60); do
|
||||
[ -s "$src" ] && break
|
||||
sleep 2
|
||||
done
|
||||
if [ ! -s "$src" ]; then
|
||||
echo "forge has not minted $src after 120s" >&2
|
||||
exit 1
|
||||
echo "the forge has not minted $src yet; the path unit publishes it when it does" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
err="$(mktemp)"
|
||||
|
|
|
|||
|
|
@ -718,12 +718,7 @@ in
|
|||
systemd.services.swarm-controller = {
|
||||
description = "hyperhive swarm-level controller daemon";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
# Where the forge runs here too, the first read waits out one publish
|
||||
# attempt. `After=` on a unit this host does not define is a no-op.
|
||||
after = [
|
||||
"network.target"
|
||||
"swarm-bao-forge-publisher.service"
|
||||
];
|
||||
after = [ "network.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${deployCfg.swarm-controller.package}/bin/swarm-controller";
|
||||
|
|
|
|||
|
|
@ -292,12 +292,16 @@ let
|
|||
&& lib.hasInfix "bao kv put secret/swarm/controller/swarm-controller/forge/token value=@\"$src\"" u.script
|
||||
&& lib.hasInfix "/var/lib/nixos-containers/hive-forge/var/lib/forgejo/swarm-controller-token" u.script
|
||||
&& lib.elem "container@hive-forge.service" u.wantedBy
|
||||
# The deploy that adds the unit starts it only through a target.
|
||||
&& lib.elem "multi-user.target" u.wantedBy
|
||||
&& !(allLocal.systemd.services ? hive-forge-swarm-controller-token);
|
||||
}
|
||||
{
|
||||
# What makes it re-run. A oneshot left `active (exited)` makes every later
|
||||
# start a no-op, so `RemainAfterExit` would silence both triggers: the
|
||||
# container's start (`wantedBy`, above) and a write of the token file.
|
||||
# start a no-op, so `RemainAfterExit` would silence every trigger: the
|
||||
# targets and the container's start (`wantedBy`, above) and a write of
|
||||
# the token file. A missing file exits 0, so a switch with the container
|
||||
# down does not fail.
|
||||
name = "the forge publisher re-runs on each container start and each write of the token file";
|
||||
ok =
|
||||
let
|
||||
|
|
@ -308,6 +312,8 @@ let
|
|||
p.pathConfig.PathChanged
|
||||
== "/var/lib/nixos-containers/hive-forge/var/lib/forgejo/swarm-controller-token"
|
||||
&& p.pathConfig.Unit == "swarm-bao-forge-publisher.service"
|
||||
&& lib.hasInfix "the path unit publishes it when it does" (publisher allLocal).script
|
||||
&& lib.hasInfix "exit 0" (publisher allLocal).script
|
||||
&& lib.elem "multi-user.target" p.wantedBy
|
||||
&& !(bare.systemd.paths ? swarm-bao-forge-publisher);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue