fix(#3343): move the all-local queue derivations into the deployment mode

Review point: the co-located defaults are an auto-deploy special case and
belong with the other ones, not inside each option's own default. An
option should describe itself; the mode describes what a deployment shape
implies. local-defaults.nix already says exactly this in its header.

Options now default to empty (= unset, which the assertions refuse), and
enableAllLocalDefaults fills in loopback + the minted secret path.
This commit is contained in:
atlas 2026-08-16 19:30:43 +02:00
commit 072dbd80a7
2 changed files with 43 additions and 17 deletions

View file

@ -88,5 +88,33 @@ in
# instead would be wrong: a hive in a larger swarm can legitimately
# want the shared services without being the host that controls them.
controller.enable = lib.mkDefault cfg.enableAllLocalDefaults;
# The controller's queue coordinates. Co-location is what makes these
# derivable at all — loopback only reaches the queue when the queue is
# here, and the minted client secret only exists on the host authelia
# ran its first boot on — so they belong to the mode that asserts this
# box is the whole deployment, not to the options' own `default`.
#
# Deriving them from `swarm.nats.enable` / `swarm.authelia.enable`
# inside those defaults is the mixing this file exists to prevent: the
# option would be describing a deployment shape instead of describing
# itself, and "what does all-local turn on?" would stop having one
# answer.
#
# ⚠️ Must live INSIDE this attrset, not as a second
# `config.services.hyperhive.swarm.…` path beside it — written that
# way the two definitions of `swarm` collide and the nested one is
# silently lost. The gate caught exactly that: mode on, `natsUrl`
# still "".
#
# The *requirement* stays in `swarm-controller.nix` as an assertion:
# needing a queue is the controller's own property in every topology,
# and only the convenience is local.
controller.queue.natsUrl = lib.mkIf cfg.enableAllLocalDefaults (
lib.mkDefault "nats://127.0.0.1:${toString config.services.hyperhive.swarm.nats.port}"
);
controller.queue.clientSecretFile = lib.mkIf cfg.enableAllLocalDefaults (
lib.mkDefault "${config.services.hyperhive.swarm.authelia.hostClientSecretDir}/swarm-controller.secret"
);
};
}

View file

@ -189,19 +189,19 @@ in
queue = {
natsUrl = lib.mkOption {
type = lib.types.str;
default = lib.optionalString natsCfg.enable "nats://127.0.0.1:${toString natsCfg.port}";
defaultText = lib.literalExpression ''
if swarm.nats.enable then "nats://127.0.0.1:''${toString swarm.nats.port}" else ""
'';
default = "";
example = "nats://queue.example.com:4222";
description = ''
Where the controller reaches the swarm queue.
Defaults to loopback when this host runs the queue the queue
container shares the host netns, so that address is correct
here and is not the `localhost`-means-the-agent trap that
applies inside agent containers. Set it explicitly when the
queue lives elsewhere.
Empty means unset, which the assertion below refuses a
controller with no queue is not a lighter controller.
`enableAllLocalDefaults` fills this in with loopback, because
that address is only correct when the queue is on this host:
its container shares the host netns. That derivation lives with
the mode rather than here, so this option describes itself
rather than a deployment shape.
'';
};
@ -221,20 +221,18 @@ in
clientSecretFile = lib.mkOption {
type = lib.types.str;
default = lib.optionalString autheliaCfg.enable "${autheliaCfg.hostClientSecretDir}/${queueClientId}.secret";
defaultText = lib.literalExpression ''
"''${swarm.authelia.hostClientSecretDir}/swarm-controller.secret"
'';
default = "";
example = "/var/lib/secrets/swarm-controller-queue.secret";
description = ''
Path on **this** host holding the plaintext of the controller's
OAuth2 client secret. A path, never a value: the secret would
otherwise land in the world-readable nix store.
Defaults to the file authelia's first-boot generator mints when
authelia runs here. When it doesn't, the operator places the
secret and names it the controller cannot mint its own,
because minting happens inside authelia's state directory.
The controller cannot mint its own minting happens inside
authelia's state directory during its first boot so away from
that host the operator places the secret and names it here.
`enableAllLocalDefaults` points this at the minted file, which
is exactly the case where one exists locally.
Read by `LoadCredential`, so it needs to be readable by root at
unit start and nothing more; the daemon's own user never sees