deploy: give every option an enable, and name the controller one

Two corrections from review, applied forward on this branch rather than
by rewriting it.

`deploy.<service>` was a bare bool, which makes
`deploy.forgejo = { enable; ci; }` unrepresentable -- the nested
CI-runner sub-option this namespace was designed around. Every entry is
now an attrset with an `enable`, so a second per-host deployment
decision becomes an ordinary addition rather than a migration.

`deploy.controller` is now `deploy.swarm-controller`, consistent with
`deploy.swarm-ui`, which was introduced in the same commit.

89 references rewritten across 24 files -- nix, Rust, docs, and the
repo's own CLAUDE.md.

The prefix-anchored sweep missed exactly one, and it was live code:
hive-tls.nix spells it `hyperhiveCfg.deploy.controller` -- the only
`hyperhiveCfg` prefix among 45 references. A suffix grep
(`\.deploy\.<name>`) finds it; a path-anchored one cannot, because the
head of a reference is whatever alias the reading file happens to bind.
This commit is contained in:
atlas 2026-08-30 04:05:28 +02:00 committed by mara
commit d3b40da1c8
24 changed files with 137 additions and 121 deletions

View file

@ -345,7 +345,7 @@ let
'';
in
{
# `enable` moved to `services.hyperhive.deploy.authelia` — see
# `enable` moved to `services.hyperhive.deploy.authelia.enable` — see
# ./deploy.nix. Whether this host runs the swarm's SSO provider is a
# deployment decision; what stays here is what authelia IS, including
# `url` and the OIDC client registry every hive needs as a *client*
@ -427,7 +427,7 @@ in
url = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = if deployCfg.authelia then "https://${cfg.domain}" else null;
default = if deployCfg.authelia.enable then "https://${cfg.domain}" else null;
defaultText = lib.literalExpression ''if enable then "https://''${domain}" else null'';
example = "https://auth.example.com";
description = ''
@ -467,8 +467,8 @@ in
oidc.hiveIdentities = lib.mkOption {
type = lib.types.bool;
default = deployCfg.nats;
defaultText = lib.literalExpression "services.hyperhive.deploy.nats";
default = deployCfg.nats.enable;
defaultText = lib.literalExpression "services.hyperhive.deploy.nats.enable";
description = ''
Mint one machine client per hive in
{option}`services.hyperhive.swarm.hives`, so each hive can
@ -810,7 +810,7 @@ in
bridgeUrl = lib.mkOption {
type = lib.types.nullOr lib.types.str;
readOnly = true;
default = if deployCfg.authelia then "http://127.0.0.1:${toString cfg.bridgePort}" else null;
default = if deployCfg.authelia.enable then "http://127.0.0.1:${toString cfg.bridgePort}" else null;
defaultText = lib.literalExpression ''if enable then "http://127.0.0.1:''${bridgePort}" else null'';
description = ''
Where `swarm-authelia-bridge` answers, **as seen from this
@ -829,7 +829,7 @@ in
};
};
config = lib.mkIf (hyperhiveCfg.enable && deployCfg.authelia) {
config = lib.mkIf (hyperhiveCfg.enable && deployCfg.authelia.enable) {
# The derived half of the client list, declared the same way an
# operator declares one. Everything downstream then reads a single
# uniformly-typed `cfg.oidc.clients` and cannot tell the parts apart —
@ -964,7 +964,7 @@ in
# Authelia's own gateway surface: the vhost that fronts it and the
# name the hive resolver answers for. Both live here rather than in
# the gateway, and both are inside `deployCfg.authelia` — that guard is the
# the gateway, and both are inside `deployCfg.authelia.enable` — that guard is the
# load-bearing part.
#
# ⚠️ Every hive in a swarm knows `authelia.url`, but only the host
@ -1009,9 +1009,11 @@ in
# Written out in full rather than through a `let` binding so the gate and
# the option it gates are visibly the same path: gating the wrong one is
# not a build error, it is a target that is always declared or never is.
services.hyperhive.swarm.otel.scrapeTargets = lib.mkIf config.services.hyperhive.deploy.otel {
authelia = "127.0.0.1:${toString cfg.metricsPort}";
};
services.hyperhive.swarm.otel.scrapeTargets =
lib.mkIf config.services.hyperhive.deploy.otel.enable
{
authelia = "127.0.0.1:${toString cfg.metricsPort}";
};
# This swarm-ui quick-links entry, same guard as the vhost/DNS name
# above (only the host actually running the container claims it —
@ -1397,7 +1399,7 @@ in
# collector is registered — see `metricsRule` above,
# which is where the reasoning for both halves lives.
lib.optional forgeCfg.behindGateway metricsRule
++ lib.optional deployCfg.swarm-ui {
++ lib.optional deployCfg.swarm-ui.enable {
domain = uiCfg.domain;
subject = [ "group:${operatorGroup}" ];
policy = "one_factor";