deploy: move the matrix homeserver toggle out of swarm

swarm.matrix.enable was the last toggle still spelled swarm.*, which
is the namespace every host in the swarm agrees on - and "does this
host run the homeserver" is exactly what differs between them. It
moves to deploy.matrix.enable with the rest; the genuinely swarm-wide
matrix settings stay where they are.

mkRenamedOptionModule keeps existing configs evaluating with one
warning naming both paths.

The sweep for readers had to be unanchored and cross-language: three
of them were outside nix, including a hive-c0re error message telling
the operator to set the old name. A dotted grep also cannot see the
rename module's own list form, so that was checked separately.
This commit is contained in:
atlas 2026-08-30 14:56:09 +02:00 committed by mara
commit 2aa924d85a
8 changed files with 40 additions and 34 deletions

View file

@ -58,7 +58,7 @@ hivectl forge reconcile-config iris --verbose # include the full diff, not
Manual entry to the same idempotent matrix provisioning flow Manual entry to the same idempotent matrix provisioning flow
`hive-c0re` runs at boot. Requires the `hive-matrix` container to be `hive-c0re` runs at boot. Requires the `hive-matrix` container to be
running (`services.hyperhive.swarm.matrix.enable = true`). running (`services.hyperhive.deploy.matrix.enable = true`).
```bash ```bash
hivectl matrix create-user iris # provision (or re-provision) matrix account for agent `iris` hivectl matrix create-user iris # provision (or re-provision) matrix account for agent `iris`

View file

@ -1,7 +1,7 @@
//! Optional matrix-tuwunel wiring: shared registration token (host) + //! Optional matrix-tuwunel wiring: shared registration token (host) +
//! per-agent UIAA registration → `<agent-state>/matrix-token`. No-op //! per-agent UIAA registration → `<agent-state>/matrix-token`. No-op
//! when the `hive-matrix` container isn't running, so operators who //! when the `hive-matrix` container isn't running, so operators who
//! haven't flipped `services.hyperhive.swarm.matrix.enable = true` pay //! haven't flipped `services.hyperhive.deploy.matrix.enable = true` pay
//! nothing. //! nothing.
//! //!
//! See `docs/matrix.md::Provisioning flow (registration token)` for //! See `docs/matrix.md::Provisioning flow (registration token)` for

View file

@ -487,7 +487,7 @@ fn require_matrix_present() -> Result<()> {
return Ok(()); return Ok(());
} }
anyhow::bail!( anyhow::bail!(
"no matrix homeserver configured — set services.hyperhive.swarm.matrix.enable = true to run one \ "no matrix homeserver configured — set services.hyperhive.deploy.matrix.enable = true to run one \
here, or services.hyperhive.swarm.matrix.apiUrl to point at an existing one, before \ here, or services.hyperhive.swarm.matrix.apiUrl to point at an existing one, before \
provisioning matrix users" provisioning matrix users"
) )

View file

@ -54,7 +54,7 @@ let
boot.loader.grub.enable = false; boot.loader.grub.enable = false;
system.stateVersion = "25.11"; system.stateVersion = "25.11";
services.hyperhive.enable = lib.mkForce false; services.hyperhive.enable = lib.mkForce false;
services.hyperhive.swarm.matrix.enable = lib.mkForce false; services.hyperhive.deploy.matrix.enable = lib.mkForce false;
} }
) )
]; ];

View file

@ -152,6 +152,24 @@ in
''; '';
}; };
matrix.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Run the swarm's matrix homeserver matrix-tuwunel, in a
`hive-matrix` container on this host.
Derives from
{option}`services.hyperhive.swarm.enableRequiredServices` with
the other once-per-swarm services. Set it here directly to put
the homeserver somewhere other than the host holding the rest.
Client-side settings stay in
{option}`services.hyperhive.swarm.matrix.*`, which every hive
agrees on; this is only the decision to run it here.
'';
};
nats.enable = lib.mkOption { nats.enable = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = false; default = false;

View file

@ -162,7 +162,7 @@ in
// //
lib.optionalAttrs lib.optionalAttrs
( (
config.services.hyperhive.swarm.matrix.enable config.services.hyperhive.deploy.matrix.enable
&& config.services.hyperhive.swarm.matrix.gatewayHost != null && config.services.hyperhive.swarm.matrix.gatewayHost != null
) )
{ {

View file

@ -164,6 +164,13 @@ in
[ "services" "hyperhive" "matrix" ] [ "services" "hyperhive" "matrix" ]
[ "services" "hyperhive" "swarm" "matrix" ] [ "services" "hyperhive" "swarm" "matrix" ]
) )
# "does THIS host run it" is a per-host decision, and `swarm.*` is the
# namespace every host in the swarm agrees on. The rest of the matrix
# settings genuinely are swarm-wide and stay where they are.
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "matrix" "enable" ]
[ "services" "hyperhive" "deploy" "matrix" "enable" ]
)
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "matrix" "sso" "enable" ] '' (lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "matrix" "sso" "enable" ] ''
SSO is no longer optional: a homeserver that runs at all delegates SSO is no longer optional: a homeserver that runs at all delegates
login to the swarm's authelia. login to the swarm's authelia.
@ -177,21 +184,6 @@ in
]; ];
options.services.hyperhive.swarm.matrix = { options.services.hyperhive.swarm.matrix = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Run hive-matrix a private matrix-tuwunel homeserver (in a
nixos-container) for hyperhive agents.
Matrix is a swarm-wide service one homeserver, not one per
hive so `services.hyperhive.swarm.enableRequiredServices`
turns this on as part of saying the swarm's shared services live
on this host. Set it here directly to run the homeserver
somewhere other than the host that holds the rest of them.
'';
};
package = lib.mkOption { package = lib.mkOption {
type = lib.types.package; type = lib.types.package;
default = pkgs.matrix-tuwunel; default = pkgs.matrix-tuwunel;
@ -254,9 +246,9 @@ in
apiUrl = lib.mkOption { apiUrl = lib.mkOption {
type = lib.types.nullOr lib.types.str; type = lib.types.nullOr lib.types.str;
default = if cfg.enable then "http://127.0.0.1:${toString cfg.httpPort}" else null; default = if deployCfg.matrix.enable then "http://127.0.0.1:${toString cfg.httpPort}" else null;
defaultText = lib.literalExpression '' defaultText = lib.literalExpression ''
if services.hyperhive.swarm.matrix.enable if services.hyperhive.deploy.matrix.enable
then "http://127.0.0.1:''${toString services.hyperhive.swarm.matrix.httpPort}" then "http://127.0.0.1:''${toString services.hyperhive.swarm.matrix.httpPort}"
else null else null
''; '';
@ -411,8 +403,8 @@ in
gui = { gui = {
enable = lib.mkOption { enable = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = cfg.enable; default = deployCfg.matrix.enable;
defaultText = lib.literalExpression "config.services.hyperhive.swarm.matrix.enable"; defaultText = lib.literalExpression "config.services.hyperhive.deploy.matrix.enable";
description = '' description = ''
Serve a matrix web client at `matrix.''${services.hyperhive.domain}/`. Serve a matrix web client at `matrix.''${services.hyperhive.domain}/`.
Requires `matrix.gatewayHost != null` (default `matrix.<hive>` Requires `matrix.gatewayHost != null` (default `matrix.<hive>`
@ -498,7 +490,7 @@ in
}; };
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf deployCfg.matrix.enable {
# Matrix's own gateway surface: the sub-domain vhost, the name the # Matrix's own gateway surface: the sub-domain vhost, the name the
# hive resolver answers for, and the Accept-header map that vhost's # hive resolver answers for, and the Accept-header map that vhost's
# SPA fallback reads. All three are matrix knowledge and none of # SPA fallback reads. All three are matrix knowledge and none of

View file

@ -48,15 +48,11 @@ in
# Same precedence reasoning as ./local-defaults.nix: fills in for an # Same precedence reasoning as ./local-defaults.nix: fills in for an
# operator who hasn't spoken, yields to one who has. # operator who hasn't spoken, yields to one who has.
config.services.hyperhive.swarm = { #
# The last one still spelled `swarm.*.enable`. Everything else that # Everything derives under `deploy.*` now, because "does THIS host run
# used to derive here — the queue, the SSO provider, the collector, # it" is a per-host decision and `swarm.*` has to be identical on every
# the metrics pair, the log store — now derives below under # host. Same switch, same rule, one attribute path.
# `deploy.*`, because "does THIS host run it" is a per-host decision config.services.hyperhive.deploy.matrix.enable = lib.mkDefault swarmCfg.enableRequiredServices;
# and `swarm.*` has to be identical on every host. Same switch, same
# rule, different attribute path.
matrix.enable = lib.mkDefault swarmCfg.enableRequiredServices;
};
# The collector that feeds the pair above (note: no `swarm.` prefix, # The collector that feeds the pair above (note: no `swarm.` prefix,
# this is ./otel.nix's existing per-hive option). # this is ./otel.nix's existing per-hive option).