# Glue: tell the swarm controller where the swarm's collector is and which # authelia runs on this host. # # ONE PAIRING PER FILE — controller ← the services whose coordinates it reads # from the environment. Deleting this leaves a controller that exports no # metrics, and a `swarmctl` that fails `user add` saying the authelia binary and # users file are unset. # # ⚠️ Everything here is gated on the controller being here: # `systemd.services.swarm-controller.environment` on a host without the # controller would define a unit with no ExecStart. # # authelia → `swarmctl`'s wrapper, not the daemon's unit. Also gated on authelia # running HERE: the controller can be enabled on a host that is not the swarm's # SSO host, and there `swarmctl user add` must fail saying the value is unset — # a guessed path would resolve cleanly and write a file nothing reads. The # CONFIGURED authelia, not whatever is on PATH: the argon2 parameters baked into # a hash have to match the verifier's. # # collector → the daemon's unit. `vcs_metrics`/`hive_jobq_metrics` read the # standard `OTEL_EXPORTER_OTLP_ENDPOINT` and are silent no-ops without it. No # gate beyond the controller: the controller always exports to the swarm's # collector, which the swarm always has (./swarm-bao.nix, # ./glue-swarm-otel-oidc-client.nix), and `deploy.swarm-otel.enable` only says it # runs HERE. The endpoint is its swarm-service name through the gateway, never a # loopback literal, with no trailing slash: the http exporter appends # `/v1/metrics` and the gateway route strips `/${producerName}`. The port suffix # is elided on 443, as in ./swarm-bao.nix. # `SWARM_CONTROLLER_OTEL_AUDIENCE` is the audience ./glue-controller-oidc-client.nix # registers and ./swarm-otel.nix's `oidc/${producerName}` authenticator checks. { lib, config, ... }: let hyperhiveCfg = config.services.hyperhive; deployCfg = hyperhiveCfg.deploy; otelSwarmCfg = hyperhiveCfg.swarm.otel; queueClientId = hyperhiveCfg.swarm.controller.queueClientId; gatewayPortSuffix = lib.optionalString ( hyperhiveCfg.gateway.httpsPort != 443 ) ":${toString hyperhiveCfg.gateway.httpsPort}"; in { config = lib.mkIf deployCfg.swarm-controller.enable ( lib.mkMerge [ (lib.mkIf deployCfg.authelia.enable { services.hyperhive.deploy.swarm-controller.swarmctlEnvironment = { SWARMCTL_AUTHELIA_BIN = "${deployCfg.authelia.package}/bin/authelia"; SWARMCTL_AUTHELIA_USERS_FILE = deployCfg.authelia.hostUsersFile; }; }) { systemd.services.swarm-controller.environment = { OTEL_EXPORTER_OTLP_ENDPOINT = "https://${otelSwarmCfg.domain}${gatewayPortSuffix}/${otelSwarmCfg.producerName}"; SWARM_CONTROLLER_OTEL_AUDIENCE = queueClientId; }; } ] ); }