From 40ebd45c66ffc4b813942b1c55a2723cf18bc26b Mon Sep 17 00:00:00 2001 From: atlas Date: Tue, 13 Oct 2026 10:35:25 +0200 Subject: [PATCH] glue: hive-otel's ordering after authelia moves out of the otel module The hive collector's secret-wait unit read deploy.authelia.enable to order itself after authelia's container. That ordering is now set by glue-hive-otel-authelia.nix, which restates the unit's own gate (otel's `waits`). The rendered unit is unchanged. The hive-otel module-eval fixture `hiveOtel` gains authelia, and a case pins the edge with authelia here and its absence without. Part of #3742. --- nix/host-modules/default.nix | 1 + nix/host-modules/glue-hive-otel-authelia.nix | 40 ++++++++++++++++++++ nix/host-modules/otel.nix | 9 ++--- nix/module-eval/hive-otel.nix | 19 ++++++++++ 4 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 nix/host-modules/glue-hive-otel-authelia.nix diff --git a/nix/host-modules/default.nix b/nix/host-modules/default.nix index 90a46a5d..5d9a7f20 100644 --- a/nix/host-modules/default.nix +++ b/nix/host-modules/default.nix @@ -32,6 +32,7 @@ ./glue-controller-oidc-client.nix ./glue-forge-oidc-client.nix ./glue-grafana-oidc-client.nix + ./glue-hive-otel-authelia.nix ./glue-hive-tls-bao-identity.nix ./glue-logs-auth-bao-identity.nix ./glue-matrix-ctl-bao-identity.nix diff --git a/nix/host-modules/glue-hive-otel-authelia.nix b/nix/host-modules/glue-hive-otel-authelia.nix new file mode 100644 index 00000000..7f4dd9a0 --- /dev/null +++ b/nix/host-modules/glue-hive-otel-authelia.nix @@ -0,0 +1,40 @@ +# Glue: where authelia runs on this host, the hive collector's wait for its +# client secret file is ordered after authelia's container, because the +# named file may be one authelia mints. +# +# ONE PAIRING PER FILE — the hive collector's secret-wait unit ← authelia's +# container, and nothing else. Deleting this leaves a wait that polls for the +# file without ordering against anything, which is what a host without +# authelia already gets. +# +# ⚠️ Gated on the unit existing, not only on authelia being here: setting +# `systemd.services.hive-otel-client-secret.after` on a host without the unit +# would define one with no ExecStart. The gate restates ./otel.nix's `waits` +# (a sender identity, and a secret file that is not the one the store fetch +# writes); a change to `waits` must change it here too. +{ + lib, + config, + ... +}: +let + hyperhiveCfg = config.services.hyperhive; + otel = hyperhiveCfg.otel; + autheliaMachine = hyperhiveCfg.swarm.authelia.machine; + + # ./otel.nix: `senderAuth`, `hiveLeaf`, `fetches`, `fetchedSecretPath`. + senderAuth = otel.clientSecretFile != null && hyperhiveCfg.hiveName != null; + hiveLeaf = + hyperhiveCfg.deploy.bao.clientCertFile != null && hyperhiveCfg.deploy.bao.clientKeyFile != null; + fetchedSecretPath = "/var/lib/hive-otel-oidc/${hyperhiveCfg.swarm.authelia.hiveClientPrefix}${toString hyperhiveCfg.hiveName}.secret"; + fetches = senderAuth && hiveLeaf && otel.clientSecretFile == fetchedSecretPath; + waits = senderAuth && !fetches; +in +{ + config = lib.mkIf (hyperhiveCfg.deploy.authelia.enable && otel.enable && waits) { + systemd.services.hive-otel-client-secret = { + after = [ "container@${autheliaMachine}.service" ]; + requires = [ "container@${autheliaMachine}.service" ]; + }; + }; +} diff --git a/nix/host-modules/otel.nix b/nix/host-modules/otel.nix index bf6e9bc2..ba83b510 100644 --- a/nix/host-modules/otel.nix +++ b/nix/host-modules/otel.nix @@ -340,6 +340,7 @@ in fetches = senderAuth && hiveLeaf && otel.clientSecretFile == fetchedSecretPath; # An operator-delivered file has no unit that restarts the collector # once it lands, so the collector waits for it instead. + # ./glue-hive-otel-authelia.nix restates this gate. waits = senderAuth && !fetches; secretWaitUnit = "hive-otel-client-secret"; # Written by swarm-secret-publish on authelia's host. The nix half of @@ -752,11 +753,9 @@ in # transaction and gates on it. Stating the order from both sides too # would be one more thing to keep consistent for no added guarantee. # - # When authelia runs on this host the named file may be one it mints. - # Elsewhere there is no local unit to order against — naming one that - # does not exist orders nothing, silently. - after = lib.optional deployCfg.authelia.enable "container@${autheliaCfg.machine}.service"; - requires = lib.optional deployCfg.authelia.enable "container@${autheliaCfg.machine}.service"; + # Where authelia runs on this host the named file may be one it mints; + # ./glue-hive-otel-authelia.nix orders this unit after its container + # and restates `waits`. serviceConfig = { Type = "oneshot"; RemainAfterExit = true; diff --git a/nix/module-eval/hive-otel.nix b/nix/module-eval/hive-otel.nix index 99a379b3..e4e5a5b4 100644 --- a/nix/module-eval/hive-otel.nix +++ b/nix/module-eval/hive-otel.nix @@ -25,9 +25,12 @@ let # This hive's own collector, which is a HOST service — unlike the swarm # tier's, which lives in a container and is read through `otelSettings`. + # The IdP is here too, with a hand-named secret file: the collector's wait + # for that file exists beside authelia's container. hiveOtel = hive { otel.enable = true; otel.clientSecretFile = "/var/lib/hive-otel-oidc/client.secret"; + deploy.authelia.enable = true; }; # A hive holding its own store leaf, placed by hand, and naming no secret @@ -299,6 +302,22 @@ let && waitsFor hiveOtel && waitsFor baoWithHiveOtel; } + { + # ../host-modules/glue-hive-otel-authelia.nix orders the wait after + # authelia's container. `hiveOtel` has the IdP; `baoWithHiveOtel` waits + # on the same kind of file without it, and must not name a container + # that is not there — `Requires=` on an absent unit fails the job. + name = "the hive collector's secret wait is ordered after authelia's container only where authelia runs here"; + ok = + let + container = "container@${hiveOtel.services.hyperhive.swarm.authelia.machine}.service"; + wait = machine: machine.systemd.services.hive-otel-client-secret; + in + builtins.elem container (wait hiveOtel).after + && builtins.elem container (wait hiveOtel).requires + && !(builtins.elem container (wait baoWithHiveOtel).after) + && !(builtins.elem container (wait baoWithHiveOtel).requires); + } ]; in runGroup "hive-otel" cases