Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df18d3d4d7 | ||
|
|
ce4d5187a9 | ||
|
|
cc82badd56 | ||
|
|
889a46729b | ||
|
|
e061e4b446 | ||
|
|
0fe0df8d63 | ||
|
|
190763b3a2 | ||
|
|
e091add37a | ||
|
|
0002c15dc3 | ||
|
|
d6f23ff371 |
14 changed files with 401 additions and 253 deletions
|
|
@ -3,9 +3,10 @@
|
||||||
Private Forgejo instance running in a nixos-container, used as the
|
Private Forgejo instance running in a nixos-container, used as the
|
||||||
swarm's persistent code-collaboration surface (issues, PRs, reviews,
|
swarm's persistent code-collaboration surface (issues, PRs, reviews,
|
||||||
attachments). Configured via `services.hyperhive.swarm.forge.*` (what the
|
attachments). Configured via `services.hyperhive.swarm.forge.*` (what the
|
||||||
forge IS to every hive — its package, names, ports, URLs) plus
|
forge IS to every hive — names, ports, URLs) plus
|
||||||
`services.hyperhive.deploy.forgejo.*` (what the host running it decides —
|
`services.hyperhive.deploy.forgejo.*` (what the host running it decides —
|
||||||
how it's served, what it mirrors, where its host-local secrets sit).
|
which build it runs, how it's served, what it mirrors, where its
|
||||||
|
host-local secrets sit).
|
||||||
Container
|
Container
|
||||||
shape, ROOT_URL / sub-domain routing, and operator-vs-in-cluster URL
|
shape, ROOT_URL / sub-domain routing, and operator-vs-in-cluster URL
|
||||||
handling live in [`docs/networking/gateway.md`](../networking/gateway.md); this file owns the
|
handling live in [`docs/networking/gateway.md`](../networking/gateway.md); this file owns the
|
||||||
|
|
|
||||||
|
|
@ -625,7 +625,7 @@ existing in the page DOM.
|
||||||
|
|
||||||
A static matrix web client (default `pkgs.fluffychat-web` rebuilt
|
A static matrix web client (default `pkgs.fluffychat-web` rebuilt
|
||||||
with `--base-href /matrix/`, swappable via
|
with `--base-href /matrix/`, swappable via
|
||||||
`services.hyperhive.swarm.matrix.gui.package`) served by the hive-gateway
|
`services.hyperhive.deploy.matrix.gui.package`) served by the hive-gateway
|
||||||
nginx container at `/matrix/` when
|
nginx container at `/matrix/` when
|
||||||
`services.hyperhive.deploy.matrix.gui.enable` is on (defaults to
|
`services.hyperhive.deploy.matrix.gui.enable` is on (defaults to
|
||||||
`matrix.enable`). c0re signals availability via the
|
`matrix.enable`). c0re signals availability via the
|
||||||
|
|
|
||||||
10
flake.nix
10
flake.nix
|
|
@ -142,19 +142,19 @@
|
||||||
agentBaseToplevel = lib.mkDefault self.packages.x86_64-linux.agent-base-toplevel;
|
agentBaseToplevel = lib.mkDefault self.packages.x86_64-linux.agent-base-toplevel;
|
||||||
managerToplevel = lib.mkDefault self.packages.x86_64-linux.ruth-toplevel;
|
managerToplevel = lib.mkDefault self.packages.x86_64-linux.ruth-toplevel;
|
||||||
};
|
};
|
||||||
services.hyperhive.swarm.controller.package =
|
services.hyperhive.deploy.swarm-controller.package =
|
||||||
lib.mkDefault
|
lib.mkDefault
|
||||||
self.packages.${pkgs.stdenv.hostPlatform.system}.swarm-controller;
|
self.packages.${pkgs.stdenv.hostPlatform.system}.swarm-controller;
|
||||||
services.hyperhive.swarm.controller.swarmctlPackage =
|
services.hyperhive.deploy.swarm-controller.swarmctlPackage =
|
||||||
lib.mkDefault
|
lib.mkDefault
|
||||||
self.packages.${pkgs.stdenv.hostPlatform.system}.swarmctl;
|
self.packages.${pkgs.stdenv.hostPlatform.system}.swarmctl;
|
||||||
services.hyperhive.swarm.ui.package =
|
services.hyperhive.deploy.swarm-ui.package =
|
||||||
lib.mkDefault
|
lib.mkDefault
|
||||||
self.packages.${pkgs.stdenv.hostPlatform.system}.swarm-ui;
|
self.packages.${pkgs.stdenv.hostPlatform.system}.swarm-ui;
|
||||||
services.hyperhive.swarm.nats.authPackage =
|
services.hyperhive.deploy.nats.authPackage =
|
||||||
lib.mkDefault
|
lib.mkDefault
|
||||||
self.packages.${pkgs.stdenv.hostPlatform.system}.swarm-nats-auth;
|
self.packages.${pkgs.stdenv.hostPlatform.system}.swarm-nats-auth;
|
||||||
services.hyperhive.swarm.authelia.bridgePackage =
|
services.hyperhive.deploy.authelia.bridgePackage =
|
||||||
lib.mkDefault
|
lib.mkDefault
|
||||||
self.packages.${pkgs.stdenv.hostPlatform.system}.swarm-authelia-bridge;
|
self.packages.${pkgs.stdenv.hostPlatform.system}.swarm-authelia-bridge;
|
||||||
services.hyperhive.gateway.swaggerUiTheme =
|
services.hyperhive.gateway.swaggerUiTheme =
|
||||||
|
|
|
||||||
|
|
@ -164,9 +164,10 @@ in
|
||||||
)
|
)
|
||||||
|
|
||||||
# The queue's callout identity. What stays under `swarm.nats` is what the
|
# The queue's callout identity. What stays under `swarm.nats` is what the
|
||||||
# queue IS to every hive — the ports it answers on, the client id it is
|
# queue IS to every hive — the ports it answers on and the client id it is
|
||||||
# registered under, the responder package; these five are what the host
|
# registered under; these five are what the host running it decides. The
|
||||||
# running it decides.
|
# responder package is one of them now, further down with the other
|
||||||
|
# `*.package` moves.
|
||||||
#
|
#
|
||||||
# ⚠️ The two PUBLIC keys move with their seeds. A public key looks
|
# ⚠️ The two PUBLIC keys move with their seeds. A public key looks
|
||||||
# swarm-wide, and the user key genuinely is published to every client that
|
# swarm-wide, and the user key genuinely is published to every client that
|
||||||
|
|
@ -195,9 +196,10 @@ in
|
||||||
)
|
)
|
||||||
|
|
||||||
# The rest of the forge split. What stays under `swarm.forge` is what the
|
# The rest of the forge split. What stays under `swarm.forge` is what the
|
||||||
# forge IS from any hive's point of view — its package, the names and ports
|
# forge IS from any hive's point of view — the names and ports it answers
|
||||||
# it answers on, the URLs it advertises, the client id it is registered
|
# on, the URLs it advertises, the client id it is registered under; these
|
||||||
# under; these five are what the host running it decides. `sso` splits
|
# five are what the host running it decides. Its package moved as well,
|
||||||
|
# further down with the other `*.package` moves. `sso` splits
|
||||||
# because its two halves are different facts: the client id must match the
|
# because its two halves are different facts: the client id must match the
|
||||||
# entry in authelia's register, the secret is a path on this machine.
|
# entry in authelia's register, the secret is a path on this machine.
|
||||||
#
|
#
|
||||||
|
|
@ -227,9 +229,10 @@ in
|
||||||
)
|
)
|
||||||
|
|
||||||
# The homeserver, split the same way. `swarm.matrix` keeps what it IS to
|
# The homeserver, split the same way. `swarm.matrix` keeps what it IS to
|
||||||
# every hive — its package, the name it answers to, the ports and URLs it
|
# every hive — the name it answers to, the ports and URLs it is reached
|
||||||
# is reached on, the client id it is registered under. These six are what
|
# on, the client id it is registered under. These six are what the host
|
||||||
# the host running it decides. ⚠️ `enable` is NOT here: it was renamed
|
# running it decides; its two packages moved as well, further down with
|
||||||
|
# the other `*.package` moves. ⚠️ `enable` is NOT here: it was renamed
|
||||||
# earlier and its shim lives in ./hive-matrix.nix, so that file is the one
|
# earlier and its shim lives in ./hive-matrix.nix, so that file is the one
|
||||||
# to check before assuming this table is the whole matrix story.
|
# to check before assuming this table is the whole matrix story.
|
||||||
(lib.mkRenamedOptionModule
|
(lib.mkRenamedOptionModule
|
||||||
|
|
@ -259,8 +262,9 @@ in
|
||||||
|
|
||||||
# Retention is read only where the container is defined, so it is a
|
# Retention is read only where the container is defined, so it is a
|
||||||
# decision of the host running the store rather than something the swarm
|
# decision of the host running the store rather than something the swarm
|
||||||
# agrees on. The two stores keep everything else — package, domain, port
|
# agrees on. The two stores keep their domain and port in `swarm.*`,
|
||||||
# — in `swarm.*`, because a client hive needs those to reach them.
|
# because a client hive needs those to reach them; `package` followed
|
||||||
|
# `enable` and `retentionPeriod` across in a later slice.
|
||||||
(lib.mkRenamedOptionModule
|
(lib.mkRenamedOptionModule
|
||||||
[ "services" "hyperhive" "swarm" "victoriametrics" "retentionPeriod" ]
|
[ "services" "hyperhive" "swarm" "victoriametrics" "retentionPeriod" ]
|
||||||
[ "services" "hyperhive" "deploy" "victoriametrics" "retentionPeriod" ]
|
[ "services" "hyperhive" "deploy" "victoriametrics" "retentionPeriod" ]
|
||||||
|
|
@ -335,6 +339,68 @@ in
|
||||||
[ "services" "hyperhive" "swarm" "wireguard" "persistentKeepalive" ]
|
[ "services" "hyperhive" "swarm" "wireguard" "persistentKeepalive" ]
|
||||||
[ "services" "hyperhive" "deploy" "wireguard" "persistentKeepalive" ]
|
[ "services" "hyperhive" "deploy" "wireguard" "persistentKeepalive" ]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Which build a service runs is a decision of the host that runs it, so
|
||||||
|
# every `*.package` follows its `enable` across. The split these replace
|
||||||
|
# was the sharpest case: `gui.enable` had already moved while
|
||||||
|
# `gui.package` stayed, so one client's two halves sat in two namespaces
|
||||||
|
# and ./hive-matrix.nix said so in a comment above the option.
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "matrix" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "matrix" "package" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "matrix" "gui" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "matrix" "gui" "package" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "grafana" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "grafana" "package" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "victorialogs" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "victorialogs" "package" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "victoriametrics" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "victoriametrics" "package" ]
|
||||||
|
)
|
||||||
|
# With this one `services.hyperhive.swarm.ui` holds nothing at all — it had
|
||||||
|
# exactly two options and both have moved, so the namespace now exists only
|
||||||
|
# as this entry and the `enable` one above it.
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "ui" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "swarm-ui" "package" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "nats" "authPackage" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "nats" "authPackage" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "authelia" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "authelia" "package" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "authelia" "bridgePackage" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "authelia" "bridgePackage" ]
|
||||||
|
)
|
||||||
|
# ⚠️ `swarm-controller`, not `hive-controller` — see the note in
|
||||||
|
# ./swarm-controller.nix. Both namespaces exist, so the wrong target here
|
||||||
|
# lands on a live option in hive-c0re's tree instead of failing.
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "controller" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "swarm-controller" "package" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "controller" "swarmctlPackage" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "swarm-controller" "swarmctlPackage" ]
|
||||||
|
)
|
||||||
|
# ⚠️ `deploy.forgejo`, not `deploy.forge` — the deploy-side name differs
|
||||||
|
# from the swarm-side one here, as it does for the controller and the UI.
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "hyperhive" "swarm" "forge" "package" ]
|
||||||
|
[ "services" "hyperhive" "deploy" "forgejo" "package" ]
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
# ⚠️ `deploy.forgejo` is declared in ./hive-ci.nix, not here, and it is the
|
# ⚠️ `deploy.forgejo` is declared in ./hive-ci.nix, not here, and it is the
|
||||||
|
|
|
||||||
|
|
@ -232,21 +232,6 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
package = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
default = pkgs.forgejo;
|
|
||||||
defaultText = lib.literalExpression "pkgs.forgejo";
|
|
||||||
description = ''
|
|
||||||
Forgejo package to run inside the container. Defaults to
|
|
||||||
`pkgs.forgejo` (the latest release line) rather than the
|
|
||||||
nixpkgs-module default of `pkgs.forgejo-lts`, because LTS
|
|
||||||
lags far behind on schema and the DB easily ends up "newer
|
|
||||||
than the binary" if the operator ever ran a non-LTS forgejo
|
|
||||||
against the same state dir. Override to `pkgs.forgejo-lts`
|
|
||||||
if you actively want the slower release train.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
rootUrl = lib.mkOption {
|
rootUrl = lib.mkOption {
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
|
@ -294,13 +279,28 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# What stays above is what the forge IS from any hive's point of view: its
|
# What stays above is what the forge IS from any hive's point of view: the
|
||||||
# package, the names and ports it answers on, the URLs it advertises, and
|
# names and ports it answers on, the URLs it advertises, and the client id
|
||||||
# the client id it is registered under. What lives here is what the host
|
# it is registered under. What lives here is what the host running it
|
||||||
# running it decides — how it is served, what it mirrors, and where its
|
# decides — which build it runs, how it is served, what it mirrors, and
|
||||||
# host-local secrets sit. Same rule as ./swarm-victorialogs.nix, and the
|
# where its host-local secrets sit. Same rule as ./swarm-victorialogs.nix,
|
||||||
# renames are in ./deploy.nix with the rest.
|
# and the renames are in ./deploy.nix with the rest.
|
||||||
options.services.hyperhive.deploy.forgejo = {
|
options.services.hyperhive.deploy.forgejo = {
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.forgejo;
|
||||||
|
defaultText = lib.literalExpression "pkgs.forgejo";
|
||||||
|
description = ''
|
||||||
|
Forgejo package to run inside the container. Defaults to
|
||||||
|
`pkgs.forgejo` (the latest release line) rather than the
|
||||||
|
nixpkgs-module default of `pkgs.forgejo-lts`, because LTS
|
||||||
|
lags far behind on schema and the DB easily ends up "newer
|
||||||
|
than the binary" if the operator ever ran a non-LTS forgejo
|
||||||
|
against the same state dir. Override to `pkgs.forgejo-lts`
|
||||||
|
if you actively want the slower release train.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
behindGateway = lib.mkOption {
|
behindGateway = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = config.services.hyperhive.enable;
|
default = config.services.hyperhive.enable;
|
||||||
|
|
@ -675,7 +675,7 @@ in
|
||||||
# the nix store — no separate hive-forge container rebuild needed,
|
# the nix store — no separate hive-forge container rebuild needed,
|
||||||
# and no persistent-state directory involved.
|
# and no persistent-state directory involved.
|
||||||
staticRootWithTheme = pkgs.runCommand "forgejo-static-with-theme" { } ''
|
staticRootWithTheme = pkgs.runCommand "forgejo-static-with-theme" { } ''
|
||||||
cp -r --no-preserve=mode,ownership ${cfg.package.data}/. $out/
|
cp -r --no-preserve=mode,ownership ${deployCfg.forgejo.package.data}/. $out/
|
||||||
mkdir -p $out/public/assets/css
|
mkdir -p $out/public/assets/css
|
||||||
cp ${./theme-catppuccin-vibec0re.css} \
|
cp ${./theme-catppuccin-vibec0re.css} \
|
||||||
$out/public/assets/css/theme-catppuccin-vibec0re.css
|
$out/public/assets/css/theme-catppuccin-vibec0re.css
|
||||||
|
|
@ -747,7 +747,7 @@ in
|
||||||
|
|
||||||
services.forgejo = {
|
services.forgejo = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = cfg.package;
|
package = deployCfg.forgejo.package;
|
||||||
database.type = "sqlite3";
|
database.type = "sqlite3";
|
||||||
lfs.enable = true;
|
lfs.enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
|
|
@ -1036,7 +1036,7 @@ in
|
||||||
FORGEJO_CUSTOM = "/var/lib/forgejo/custom";
|
FORGEJO_CUSTOM = "/var/lib/forgejo/custom";
|
||||||
};
|
};
|
||||||
path = [
|
path = [
|
||||||
cfg.package
|
deployCfg.forgejo.package
|
||||||
pkgs.coreutils
|
pkgs.coreutils
|
||||||
pkgs.gnugrep
|
pkgs.gnugrep
|
||||||
];
|
];
|
||||||
|
|
@ -1126,7 +1126,7 @@ in
|
||||||
FORGEJO_CUSTOM = "/var/lib/forgejo/custom";
|
FORGEJO_CUSTOM = "/var/lib/forgejo/custom";
|
||||||
};
|
};
|
||||||
path = [
|
path = [
|
||||||
cfg.package
|
deployCfg.forgejo.package
|
||||||
pkgs.coreutils
|
pkgs.coreutils
|
||||||
pkgs.gnugrep
|
pkgs.gnugrep
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -172,8 +172,9 @@ in
|
||||||
[ "services" "hyperhive" "swarm" "matrix" ]
|
[ "services" "hyperhive" "swarm" "matrix" ]
|
||||||
)
|
)
|
||||||
# "does THIS host run it" is a per-host decision, and `swarm.*` is the
|
# "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
|
# namespace every host in the swarm agrees on. What stays under
|
||||||
# settings genuinely are swarm-wide and stay where they are.
|
# `swarm.matrix` is the homeserver's identity as every hive sees it —
|
||||||
|
# its server name, its addresses, its federation policy.
|
||||||
(lib.mkRenamedOptionModule
|
(lib.mkRenamedOptionModule
|
||||||
[ "services" "hyperhive" "swarm" "matrix" "enable" ]
|
[ "services" "hyperhive" "swarm" "matrix" "enable" ]
|
||||||
[ "services" "hyperhive" "deploy" "matrix" "enable" ]
|
[ "services" "hyperhive" "deploy" "matrix" "enable" ]
|
||||||
|
|
@ -191,17 +192,6 @@ in
|
||||||
];
|
];
|
||||||
|
|
||||||
options.services.hyperhive.swarm.matrix = {
|
options.services.hyperhive.swarm.matrix = {
|
||||||
package = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
default = pkgs.matrix-tuwunel;
|
|
||||||
defaultText = lib.literalExpression "pkgs.matrix-tuwunel";
|
|
||||||
description = ''
|
|
||||||
matrix-tuwunel package to run inside the container. Defaults
|
|
||||||
to nixpkgs's `pkgs.matrix-tuwunel`. Override to pin a
|
|
||||||
specific upstream if you need an unreleased feature.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
serverName = lib.mkOption {
|
serverName = lib.mkOption {
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
|
@ -338,26 +328,6 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
gui = {
|
|
||||||
# Whether this host serves it is `deploy.matrix.gui.enable`.
|
|
||||||
package = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
default = fluffychat-web-fixed;
|
|
||||||
defaultText = lib.literalMD ''
|
|
||||||
`pkgs.fluffychat-web` with a `postInstall` patch that adds
|
|
||||||
the three files `flutter341.buildFlutterApplication` skips.
|
|
||||||
'';
|
|
||||||
description = ''
|
|
||||||
Static web client dist served at `gatewayHost`'s vhost
|
|
||||||
(`chat.<swarm-domain>` by default). Override
|
|
||||||
to swap fluffychat for hydrogen-web, cinny, element-web, or
|
|
||||||
an out-of-tree dist — any replacement is mounted at the
|
|
||||||
sub-domain root with the upstream-default `<base href "/">`,
|
|
||||||
no sub-path gymnastics needed.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# This homeserver always delegates login to the swarm's authelia, as
|
# This homeserver always delegates login to the swarm's authelia, as
|
||||||
# an OIDC relying party — matrix SSO (`m.login.sso`), offered
|
# an OIDC relying party — matrix SSO (`m.login.sso`), offered
|
||||||
# alongside password login. No toggle: a homeserver in a swarm is a
|
# alongside password login. No toggle: a homeserver in a swarm is a
|
||||||
|
|
@ -398,13 +368,24 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
# What stays above is what the homeserver IS from any hive's point of view:
|
# What stays above is what the homeserver IS from any hive's point of view:
|
||||||
# its package, the name it answers to, the ports and URLs it is reached on,
|
# the name it answers to, the ports and URLs it is reached on, and the client
|
||||||
# and the client id it is registered under. What lives here is what the host
|
# id it is registered under. What lives here is what the host running it
|
||||||
# running it decides — whether it is exposed, which peers it trusts, how large
|
# decides — which build it runs, whether it is exposed, which peers it trusts,
|
||||||
# a request it accepts, and where its host-local secrets sit. Same rule as
|
# how large a request it accepts, and where its host-local secrets sit. Same rule as
|
||||||
# ./swarm-victorialogs.nix; `enable` already lives in ./deploy.nix, which also
|
# ./swarm-victorialogs.nix; `enable` already lives in ./deploy.nix, which also
|
||||||
# carries the renames.
|
# carries the renames.
|
||||||
options.services.hyperhive.deploy.matrix = {
|
options.services.hyperhive.deploy.matrix = {
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.matrix-tuwunel;
|
||||||
|
defaultText = lib.literalExpression "pkgs.matrix-tuwunel";
|
||||||
|
description = ''
|
||||||
|
matrix-tuwunel package to run inside the container. Defaults
|
||||||
|
to nixpkgs's `pkgs.matrix-tuwunel`. Override to pin a
|
||||||
|
specific upstream if you need an unreleased feature.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
openFirewall = lib.mkOption {
|
openFirewall = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
|
@ -509,11 +490,28 @@ in
|
||||||
off, the dashboard's `M4TR1X →` tab is hidden. See
|
off, the dashboard's `M4TR1X →` tab is hidden. See
|
||||||
`docs/networking/gateway.md` for the discovery flow that lets clients
|
`docs/networking/gateway.md` for the discovery flow that lets clients
|
||||||
auto-find the sub-domain. The client build itself is
|
auto-find the sub-domain. The client build itself is
|
||||||
`swarm.matrix.gui.package` — which client, as opposed to whether
|
`deploy.matrix.gui.package` — which client, as opposed to whether
|
||||||
this host serves it.
|
this host serves it.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
gui.package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = fluffychat-web-fixed;
|
||||||
|
defaultText = lib.literalMD ''
|
||||||
|
`pkgs.fluffychat-web` with a `postInstall` patch that adds
|
||||||
|
the three files `flutter341.buildFlutterApplication` skips.
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
Static web client dist served at `gatewayHost`'s vhost
|
||||||
|
(`chat.<swarm-domain>` by default). Override
|
||||||
|
to swap fluffychat for hydrogen-web, cinny, element-web, or
|
||||||
|
an out-of-tree dist — any replacement is mounted at the
|
||||||
|
sub-domain root with the upstream-default `<base href "/">`,
|
||||||
|
no sub-path gymnastics needed.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
sso.clientSecretFile = lib.mkOption {
|
sso.clientSecretFile = lib.mkOption {
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
|
@ -634,7 +632,7 @@ in
|
||||||
# fluffychat at sub-domain root, SPA-fallback via the
|
# fluffychat at sub-domain root, SPA-fallback via the
|
||||||
# Accept-header `$matrix_spa_target` map above.
|
# Accept-header `$matrix_spa_target` map above.
|
||||||
"/" = {
|
"/" = {
|
||||||
alias = "${cfg.gui.package}/";
|
alias = "${deployCfg.matrix.gui.package}/";
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
try_files $uri $uri/ $matrix_spa_target =404;
|
try_files $uri $uri/ $matrix_spa_target =404;
|
||||||
'';
|
'';
|
||||||
|
|
@ -999,7 +997,7 @@ in
|
||||||
|
|
||||||
services.matrix-tuwunel = {
|
services.matrix-tuwunel = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = cfg.package;
|
package = deployCfg.matrix.package;
|
||||||
settings.global = {
|
settings.global = {
|
||||||
server_name = effectiveServerName;
|
server_name = effectiveServerName;
|
||||||
# `address` + `port` are upstream `listOf` — wrap singles.
|
# `address` + `port` are upstream `listOf` — wrap singles.
|
||||||
|
|
@ -1084,7 +1082,7 @@ in
|
||||||
"oidc_client_secret:${toString deployCfg.matrix.sso.clientSecretFile}"
|
"oidc_client_secret:${toString deployCfg.matrix.sso.clientSecretFile}"
|
||||||
];
|
];
|
||||||
|
|
||||||
environment.systemPackages = [ cfg.package ];
|
environment.systemPackages = [ deployCfg.matrix.package ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -320,22 +320,12 @@ let
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# `enable` moved to `services.hyperhive.deploy.authelia.enable` — see
|
# `enable` and both packages moved to `services.hyperhive.deploy.authelia`
|
||||||
# ./deploy.nix. Whether this host runs the swarm's SSO provider is a
|
# — see ./deploy.nix. Whether this host runs the swarm's SSO provider, and
|
||||||
# deployment decision; what stays here is what authelia IS, including
|
# which build it runs, are deployment decisions; what stays here is what
|
||||||
# `url` and the OIDC client registry every hive needs as a *client*
|
# authelia IS, including `url` and the OIDC client registry every hive needs
|
||||||
# whether or not it runs the container.
|
# as a *client* whether or not it runs the container.
|
||||||
options.services.hyperhive.swarm.authelia = {
|
options.services.hyperhive.swarm.authelia = {
|
||||||
package = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
default = pkgs.authelia;
|
|
||||||
defaultText = lib.literalExpression "pkgs.authelia";
|
|
||||||
description = ''
|
|
||||||
authelia package to run in the container. Defaults to
|
|
||||||
nixpkgs's; override to pin a specific upstream.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
port = lib.mkOption {
|
port = lib.mkOption {
|
||||||
type = lib.types.port;
|
type = lib.types.port;
|
||||||
default = 9091;
|
default = 9091;
|
||||||
|
|
@ -699,17 +689,6 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
bridgePackage = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarm-authelia-bridge";
|
|
||||||
description = ''
|
|
||||||
`swarm-authelia-bridge` package — the only process allowed to
|
|
||||||
write `usersFile`. Wired by default from this flake's own
|
|
||||||
package set (see `flake.nix`); override to run a different
|
|
||||||
build.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
bridgePort = lib.mkOption {
|
bridgePort = lib.mkOption {
|
||||||
type = lib.types.port;
|
type = lib.types.port;
|
||||||
default = 9092;
|
default = 9092;
|
||||||
|
|
@ -750,16 +729,37 @@ in
|
||||||
|
|
||||||
# What stays above is what authelia IS to every hive: where it answers
|
# What stays above is what authelia IS to every hive: where it answers
|
||||||
# (`url`), the OIDC register every service checks itself against, its port.
|
# (`url`), the OIDC register every service checks itself against, its port.
|
||||||
# What the host running the container decides is here, and all three of
|
# What the host running the container decides is here — which two builds it
|
||||||
# these are the same kind of thing — a filesystem path that only exists on
|
# runs, and three filesystem paths that only exist on the machine running
|
||||||
# the machine that runs `swarm-authelia`. A hive that does not run it has
|
# `swarm-authelia`. A hive that does not run it has nothing at any of those
|
||||||
# nothing at any of them. `enable` already lives in ./deploy.nix, which
|
# paths. `enable` already lives in ./deploy.nix, which also carries the
|
||||||
# also carries the renames.
|
# renames.
|
||||||
#
|
#
|
||||||
# ⚠️ `usersFile` is a path *inside* the container and still belongs here:
|
# ⚠️ `usersFile` is a path *inside* the container and still belongs here:
|
||||||
# a path's scope is the scope of the filesystem it names, and that
|
# a path's scope is the scope of the filesystem it names, and that
|
||||||
# filesystem is this host's container root.
|
# filesystem is this host's container root.
|
||||||
options.services.hyperhive.deploy.authelia = {
|
options.services.hyperhive.deploy.authelia = {
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.authelia;
|
||||||
|
defaultText = lib.literalExpression "pkgs.authelia";
|
||||||
|
description = ''
|
||||||
|
authelia package to run in the container. Defaults to
|
||||||
|
nixpkgs's; override to pin a specific upstream.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
bridgePackage = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarm-authelia-bridge";
|
||||||
|
description = ''
|
||||||
|
`swarm-authelia-bridge` package — the only process allowed to
|
||||||
|
write `usersFile`. Wired by default from this flake's own
|
||||||
|
package set (see `flake.nix`); override to run a different
|
||||||
|
build.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
usersFile = lib.mkOption {
|
usersFile = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "${stateDir}/users.yml";
|
default = "${stateDir}/users.yml";
|
||||||
|
|
@ -1111,7 +1111,7 @@ in
|
||||||
# password for the users file. Without it the container runs
|
# password for the users file. Without it the container runs
|
||||||
# authelia and cannot invoke it: the unit's ExecStart resolves
|
# authelia and cannot invoke it: the unit's ExecStart resolves
|
||||||
# through the store path, and nothing puts the CLI on PATH.
|
# through the store path, and nothing puts the CLI on PATH.
|
||||||
environment.systemPackages = [ cfg.package ];
|
environment.systemPackages = [ deployCfg.authelia.package ];
|
||||||
|
|
||||||
# This container shares the host netns, so its own
|
# This container shares the host netns, so its own
|
||||||
# firewall.service would rewrite the HOST ruleset at every
|
# firewall.service would rewrite the HOST ruleset at every
|
||||||
|
|
@ -1140,16 +1140,16 @@ in
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
before = [ "${unitName}.service" ];
|
before = [ "${unitName}.service" ];
|
||||||
requiredBy = [ "${unitName}.service" ];
|
requiredBy = [ "${unitName}.service" ];
|
||||||
# `cfg.package` is here for its CLI, not its daemon: the
|
# `deployCfg.authelia.package` is here for its CLI, not its
|
||||||
# client secrets are minted with `authelia crypto hash
|
# daemon: the client secrets are minted with `authelia crypto
|
||||||
# generate`, which is the only way to produce a digest in
|
# hash generate`, which is the only way to produce a digest in
|
||||||
# the exact form authelia will later verify.
|
# the exact form authelia will later verify.
|
||||||
path = [
|
path = [
|
||||||
pkgs.coreutils
|
pkgs.coreutils
|
||||||
]
|
]
|
||||||
++ lib.optionals oidcEnabled [
|
++ lib.optionals oidcEnabled [
|
||||||
pkgs.openssl
|
pkgs.openssl
|
||||||
cfg.package
|
deployCfg.authelia.package
|
||||||
];
|
];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
|
|
@ -1216,7 +1216,7 @@ in
|
||||||
"${unitName}.service"
|
"${unitName}.service"
|
||||||
];
|
];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${cfg.bridgePackage}/bin/swarm-authelia-bridge";
|
ExecStart = "${deployCfg.authelia.bridgePackage}/bin/swarm-authelia-bridge";
|
||||||
User = unitName;
|
User = unitName;
|
||||||
Group = unitName;
|
Group = unitName;
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
|
|
@ -1235,7 +1235,7 @@ in
|
||||||
# argon2 parameters baked into a hash have to match the
|
# argon2 parameters baked into a hash have to match the
|
||||||
# verifier's — same reasoning as `swarmctl`'s own
|
# verifier's — same reasoning as `swarmctl`'s own
|
||||||
# `SWARMCTL_AUTHELIA_BIN`.
|
# `SWARMCTL_AUTHELIA_BIN`.
|
||||||
SWARM_AUTHELIA_BRIDGE_AUTHELIA_BIN = "${cfg.package}/bin/authelia";
|
SWARM_AUTHELIA_BRIDGE_AUTHELIA_BIN = "${deployCfg.authelia.package}/bin/authelia";
|
||||||
# By name through the gateway, not loopback. A loopback
|
# By name through the gateway, not loopback. A loopback
|
||||||
# literal encodes "authelia is in my netns" at the call site,
|
# literal encodes "authelia is in my netns" at the call site,
|
||||||
# and authelia's OIDC endpoints are https-only in effect —
|
# and authelia's OIDC endpoints are https-only in effect —
|
||||||
|
|
@ -1255,7 +1255,7 @@ in
|
||||||
|
|
||||||
services.authelia.instances.${instance} = {
|
services.authelia.instances.${instance} = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = cfg.package;
|
package = deployCfg.authelia.package;
|
||||||
|
|
||||||
# Merged at RUNTIME alongside the nix-generated config, which
|
# Merged at RUNTIME alongside the nix-generated config, which
|
||||||
# is the whole reason the client digests can exist at all:
|
# is the whole reason the client digests can exist at all:
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ let
|
||||||
autheliaEnv = lib.optionalAttrs deployCfg.authelia.enable {
|
autheliaEnv = lib.optionalAttrs deployCfg.authelia.enable {
|
||||||
# The CONFIGURED authelia, not whatever is on PATH: the argon2
|
# The CONFIGURED authelia, not whatever is on PATH: the argon2
|
||||||
# parameters baked into a hash have to match the verifier's.
|
# parameters baked into a hash have to match the verifier's.
|
||||||
SWARMCTL_AUTHELIA_BIN = "${autheliaCfg.package}/bin/authelia";
|
SWARMCTL_AUTHELIA_BIN = "${deployCfg.authelia.package}/bin/authelia";
|
||||||
SWARMCTL_AUTHELIA_USERS_FILE = deployCfg.authelia.hostUsersFile;
|
SWARMCTL_AUTHELIA_USERS_FILE = deployCfg.authelia.hostUsersFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -196,7 +196,7 @@ let
|
||||||
# config back to it — and to get it wrong the day one of them changes.
|
# config back to it — and to get it wrong the day one of them changes.
|
||||||
swarmctlConfigured = pkgs.symlinkJoin {
|
swarmctlConfigured = pkgs.symlinkJoin {
|
||||||
name = "swarmctl-configured";
|
name = "swarmctl-configured";
|
||||||
paths = [ cfg.swarmctlPackage ];
|
paths = [ deployCfg.swarm-controller.swarmctlPackage ];
|
||||||
nativeBuildInputs = [ pkgs.makeWrapper ];
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||||
postBuild = ''
|
postBuild = ''
|
||||||
wrapProgram $out/bin/swarmctl ${
|
wrapProgram $out/bin/swarmctl ${
|
||||||
|
|
@ -243,30 +243,8 @@ in
|
||||||
# asserts it, and that was never an exception to "not derived from
|
# asserts it, and that was never an exception to "not derived from
|
||||||
# services.hyperhive.enable": that mode says "this box is the whole
|
# services.hyperhive.enable": that mode says "this box is the whole
|
||||||
# deployment", which answers the topology question outright, where
|
# deployment", which answers the topology question outright, where
|
||||||
# `enable` alone never can. What stays here is what the daemon IS.
|
# `enable` alone never can. Both packages moved to that same
|
||||||
|
# `deploy.swarm-controller` block. What stays here is what the daemon IS.
|
||||||
package = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarm-controller";
|
|
||||||
description = ''
|
|
||||||
swarm-controller package. Wired by default from this flake's own
|
|
||||||
package set (see `flake.nix`); override to run a different build.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
swarmctlPackage = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarmctl";
|
|
||||||
description = ''
|
|
||||||
`swarmctl` package — the swarm operator's CLI, installed on this
|
|
||||||
host alongside the daemon and wrapped with the paths it needs.
|
|
||||||
|
|
||||||
A separate option from `package` rather than a second binary in
|
|
||||||
the same derivation: the CLI runs as root and acts directly,
|
|
||||||
the daemon runs unprivileged and serves a socket, and pinning one
|
|
||||||
without the other is a thing an operator may legitimately want.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
staleAfterSeconds = lib.mkOption {
|
staleAfterSeconds = lib.mkOption {
|
||||||
type = lib.types.ints.positive;
|
type = lib.types.ints.positive;
|
||||||
|
|
@ -371,16 +349,39 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
# What stays above is what the controller IS to the swarm: the quick-links
|
# What stays above is what the controller IS to the swarm: the quick-links
|
||||||
# it publishes, the client id it is registered under, how stale a snapshot
|
# it publishes, the client id it is registered under, and how stale a
|
||||||
# may read, and its packages. What the host running it decides is here —
|
# snapshot may read. What the host running it decides is here — which two
|
||||||
# where its socket lives, and the three credentials it reads off local
|
# builds it runs, where its socket lives, and the three credentials it reads
|
||||||
# disk. `enable` already lives in ./deploy.nix, which also carries the
|
# off local disk. `enable` already lives in ./deploy.nix, which also carries
|
||||||
# renames.
|
# the renames.
|
||||||
#
|
#
|
||||||
# ⚠️ `deploy.swarm-controller`, NOT `deploy.hive-controller`. Both exist:
|
# ⚠️ `deploy.swarm-controller`, NOT `deploy.hive-controller`. Both exist:
|
||||||
# the latter is hive-c0re's namespace, where `tls.*` lives. A definition on
|
# the latter is hive-c0re's namespace, where `tls.*` lives. A definition on
|
||||||
# the wrong one lands on a live, unrelated option rather than failing.
|
# the wrong one lands on a live, unrelated option rather than failing.
|
||||||
options.services.hyperhive.deploy.swarm-controller = {
|
options.services.hyperhive.deploy.swarm-controller = {
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarm-controller";
|
||||||
|
description = ''
|
||||||
|
swarm-controller package. Wired by default from this flake's own
|
||||||
|
package set (see `flake.nix`); override to run a different build.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
swarmctlPackage = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarmctl";
|
||||||
|
description = ''
|
||||||
|
`swarmctl` package — the swarm operator's CLI, installed on this
|
||||||
|
host alongside the daemon and wrapped with the paths it needs.
|
||||||
|
|
||||||
|
A separate option from `package` rather than a second binary in
|
||||||
|
the same derivation: the CLI runs as root and acts directly,
|
||||||
|
the daemon runs unprivileged and serves a socket, and pinning one
|
||||||
|
without the other is a thing an operator may legitimately want.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
socketPath = lib.mkOption {
|
socketPath = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "/run/swarm-controller/controller.sock";
|
default = "/run/swarm-controller/controller.sock";
|
||||||
|
|
@ -591,7 +592,7 @@ in
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${cfg.package}/bin/swarm-controller";
|
ExecStart = "${deployCfg.swarm-controller.package}/bin/swarm-controller";
|
||||||
|
|
||||||
# The two differ on purpose. The queue credential is
|
# The two differ on purpose. The queue credential is
|
||||||
# unconditional — the assertions above make its path a value that
|
# unconditional — the assertions above make its path a value that
|
||||||
|
|
|
||||||
|
|
@ -111,20 +111,13 @@ in
|
||||||
# `enable` moved to `services.hyperhive.deploy.grafana.enable` — see
|
# `enable` moved to `services.hyperhive.deploy.grafana.enable` — see
|
||||||
# ./deploy.nix. Whether this host runs the swarm's Grafana is a
|
# ./deploy.nix. Whether this host runs the swarm's Grafana is a
|
||||||
# deployment decision, and `swarm.*` has to be identical on every host.
|
# deployment decision, and `swarm.*` has to be identical on every host.
|
||||||
# What stays here is what the service IS to every hive: its package, the
|
# What stays here is what the service IS to every hive: the name it is
|
||||||
# name it is served under, the port its `/metrics` is re-served on, and
|
# served under, the port its `/metrics` is re-served on, and the OIDC
|
||||||
# the OIDC client it is registered as. What the host running it decides —
|
# client it is registered as. What the host running it decides — which
|
||||||
# where its datasources point, which plugins are in its store path, and
|
# build it runs, where its datasources point, which plugins are in its
|
||||||
# the socket directory it shares with nginx — is below, under
|
# store path, and the socket directory it shares with nginx — is below,
|
||||||
# `deploy.grafana`.
|
# under `deploy.grafana`.
|
||||||
options.services.hyperhive.swarm.grafana = {
|
options.services.hyperhive.swarm.grafana = {
|
||||||
package = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
default = pkgs.grafana;
|
|
||||||
defaultText = lib.literalExpression "pkgs.grafana";
|
|
||||||
description = "Grafana package to run.";
|
|
||||||
};
|
|
||||||
|
|
||||||
machine = lib.mkOption {
|
machine = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
|
|
@ -217,15 +210,22 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
# What stays above is what the service IS to every hive. What the host
|
# What stays above is what the service IS to every hive. What the host
|
||||||
# running it decides is here: where its datasources point, which plugins sit
|
# running it decides is here: which build it runs, where its datasources
|
||||||
# in its store path, and the directory it shares a socket with nginx
|
# point, which plugins sit in its store path, and the directory it shares a
|
||||||
# through. `enable` already lives in ./deploy.nix, which also carries the
|
# socket with nginx through. `enable` already lives in ./deploy.nix, which
|
||||||
# renames.
|
# also carries the renames.
|
||||||
#
|
#
|
||||||
# ⚠️ Both datasource URLs are wiring and still move. A URL's scope is the
|
# ⚠️ Both datasource URLs are wiring and still move. A URL's scope is the
|
||||||
# scope of what it ADDRESSES, not the fact that it is a URL: both stores
|
# scope of what it ADDRESSES, not the fact that it is a URL: both stores
|
||||||
# bind loopback, so these can only ever mean "on this host".
|
# bind loopback, so these can only ever mean "on this host".
|
||||||
options.services.hyperhive.deploy.grafana = {
|
options.services.hyperhive.deploy.grafana = {
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.grafana;
|
||||||
|
defaultText = lib.literalExpression "pkgs.grafana";
|
||||||
|
description = "Grafana package to run.";
|
||||||
|
};
|
||||||
|
|
||||||
socketDir = lib.mkOption {
|
socketDir = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "/run/swarm-grafana";
|
default = "/run/swarm-grafana";
|
||||||
|
|
@ -624,7 +624,7 @@ in
|
||||||
|
|
||||||
services.grafana = {
|
services.grafana = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = cfg.package;
|
package = deployCfg.grafana.package;
|
||||||
|
|
||||||
# Passed through unconditionally, empty default included.
|
# Passed through unconditionally, empty default included.
|
||||||
# Upstream distinguishes `null` from `[ ]`, and both differences
|
# Upstream distinguishes `null` from `[ ]`, and both differences
|
||||||
|
|
|
||||||
|
|
@ -217,12 +217,14 @@ in
|
||||||
# ./deploy.nix. What stays here is what the queue IS: its domain,
|
# ./deploy.nix. What stays here is what the queue IS: its domain,
|
||||||
# ports, accounts and callout wiring.
|
# ports, accounts and callout wiring.
|
||||||
|
|
||||||
# ⚠️ Deliberately NO `package` option, unlike this module's siblings.
|
# ⚠️ Deliberately NO `package` option for the NATS server, anywhere —
|
||||||
# `services.nats` upstream does not expose one — it resolves
|
# not here and not under `deploy.nats` either, where every other
|
||||||
# `pkgs.nats-server` itself — so an option here would either be
|
# service's build now lives. `services.nats` upstream does not expose
|
||||||
# ignored or need an overlay to mean anything, and an option that
|
# one; it resolves `pkgs.nats-server` itself, so an option would be
|
||||||
# does not control what it names is worse than its absence. Pin the
|
# ignored or need an overlay to mean anything, and an option that does
|
||||||
# build with `nixpkgs.overlays` if you need to.
|
# not control what it names is worse than its absence. Pin the build
|
||||||
|
# with `nixpkgs.overlays` if you need to. (`deploy.nats.authPackage`
|
||||||
|
# is a different thing: the callout responder, which IS ours.)
|
||||||
|
|
||||||
port = lib.mkOption {
|
port = lib.mkOption {
|
||||||
type = lib.types.port;
|
type = lib.types.port;
|
||||||
|
|
@ -284,6 +286,19 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
# What stays above is what the queue IS to every hive: the ports it answers
|
||||||
|
# on and the client id it is registered under. What the host running it
|
||||||
|
# decides is below — which responder build it runs, whether it mints its own
|
||||||
|
# keypairs, and where the seeds sit. `enable` already lives in ./deploy.nix,
|
||||||
|
# which also carries the renames.
|
||||||
|
#
|
||||||
|
# ⚠️ The two PUBLIC keys move with their seeds rather than staying: peers
|
||||||
|
# receive the user key over the wire when they connect (docs/swarm/secrets.md),
|
||||||
|
# they never configure it, and splitting a keypair across two namespaces is
|
||||||
|
# worse than either placement.
|
||||||
|
options.services.hyperhive.deploy.nats = {
|
||||||
authPackage = lib.mkOption {
|
authPackage = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarm-nats-auth";
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarm-nats-auth";
|
||||||
|
|
@ -291,25 +306,15 @@ in
|
||||||
The auth-callout responder package.
|
The auth-callout responder package.
|
||||||
|
|
||||||
⚠️ Named `authPackage`, not `package`, on purpose: this module
|
⚠️ Named `authPackage`, not `package`, on purpose: this module
|
||||||
deliberately has **no** `package` option for the server itself
|
deliberately has **no** `package` option for the NATS server
|
||||||
(see the note above — upstream's `services.nats` resolves
|
itself, because upstream's `services.nats` resolves
|
||||||
`pkgs.nats-server` on its own), so a bare `package` here would
|
`pkgs.nats-server` on its own — see the note above
|
||||||
read as "the NATS package" and mean something else entirely.
|
`options.services.hyperhive.swarm.nats`. A bare `package` here
|
||||||
|
would read as "the NATS package" and mean something else
|
||||||
|
entirely.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
# What stays above is what the queue IS to every hive: the ports it answers
|
|
||||||
# on, the client id it is registered under, the responder package. The
|
|
||||||
# callout identity below is what the host running it decides — whether it
|
|
||||||
# mints its own keypairs, and where the seeds sit. `enable` already lives in
|
|
||||||
# ./deploy.nix, which also carries the renames.
|
|
||||||
#
|
|
||||||
# ⚠️ The two PUBLIC keys move with their seeds rather than staying: peers
|
|
||||||
# receive the user key over the wire when they connect (docs/swarm/secrets.md),
|
|
||||||
# they never configure it, and splitting a keypair across two namespaces is
|
|
||||||
# worse than either placement.
|
|
||||||
options.services.hyperhive.deploy.nats = {
|
|
||||||
autoGenerateCallout = lib.mkOption {
|
autoGenerateCallout = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
|
@ -708,7 +713,7 @@ in
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = lib.concatStringsSep " " [
|
ExecStart = lib.concatStringsSep " " [
|
||||||
"${cfg.authPackage}/bin/swarm-nats-auth"
|
"${deployCfg.nats.authPackage}/bin/swarm-nats-auth"
|
||||||
"--nats-url nats://127.0.0.1:${toString cfg.port}"
|
"--nats-url nats://127.0.0.1:${toString cfg.port}"
|
||||||
"--user-seed-file \${CREDENTIALS_DIRECTORY}/callout-user.seed"
|
"--user-seed-file \${CREDENTIALS_DIRECTORY}/callout-user.seed"
|
||||||
"--issuer-seed-file \${CREDENTIALS_DIRECTORY}/issuer.seed"
|
"--issuer-seed-file \${CREDENTIALS_DIRECTORY}/issuer.seed"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.services.hyperhive.swarm.ui;
|
|
||||||
deployCfg = config.services.hyperhive.deploy;
|
deployCfg = config.services.hyperhive.deploy;
|
||||||
gatewayCfg = config.services.hyperhive.gateway;
|
gatewayCfg = config.services.hyperhive.gateway;
|
||||||
autheliaCfg = config.services.hyperhive.swarm.authelia;
|
autheliaCfg = config.services.hyperhive.swarm.authelia;
|
||||||
|
|
@ -22,11 +21,11 @@ let
|
||||||
# this UI was left out of that overlay entirely (an operator with a
|
# this UI was left out of that overlay entirely (an operator with a
|
||||||
# stylix-themed host saw the dashboard in their own colours but this
|
# stylix-themed host saw the dashboard in their own colours but this
|
||||||
# UI still on the default Catppuccin palette), because nothing here
|
# UI still on the default Catppuccin palette), because nothing here
|
||||||
# ever served a themed `colors.css` in place of `cfg.package`'s own.
|
# ever served a themed `colors.css` in place of `deployCfg.swarm-ui.package`'s own.
|
||||||
# Detection + CSS-generation is shared (`./stylix-theme.nix`).
|
# Detection + CSS-generation is shared (`./stylix-theme.nix`).
|
||||||
#
|
#
|
||||||
# No package-copy derivation: this vhost has exactly one location
|
# No package-copy derivation: this vhost has exactly one location
|
||||||
# serving `cfg.package` (unlike hive-c0re's `servedFrontend`, which
|
# serving `deployCfg.swarm-ui.package` (unlike hive-c0re's `servedFrontend`, which
|
||||||
# backs both the dashboard root AND every per-agent gateway route, so
|
# backs both the dashboard root AND every per-agent gateway route, so
|
||||||
# a single swapped tree covers both) — an `= /static/colors.css`
|
# a single swapped tree covers both) — an `= /static/colors.css`
|
||||||
# exact-match location overriding just that one file, same idiom
|
# exact-match location overriding just that one file, same idiom
|
||||||
|
|
@ -79,8 +78,10 @@ in
|
||||||
'')
|
'')
|
||||||
];
|
];
|
||||||
|
|
||||||
options.services.hyperhive.swarm.ui = {
|
# ⚠️ `services.hyperhive.swarm.ui` no longer exists as a namespace. `enable`
|
||||||
package = lib.mkOption {
|
# moved in an earlier slice and `package` in this one, and those were its
|
||||||
|
# only two options — so both paths survive purely as renames in ./deploy.nix.
|
||||||
|
options.services.hyperhive.deploy.swarm-ui.package = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarm-ui";
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swarm-ui";
|
||||||
description = ''
|
description = ''
|
||||||
|
|
@ -89,13 +90,12 @@ in
|
||||||
controller's own API.
|
controller's own API.
|
||||||
|
|
||||||
Wired by default from this flake's own package set (see
|
Wired by default from this flake's own package set (see
|
||||||
`flake.nix`), the same way `swarm.controller.package` is. There
|
`flake.nix`), the same way `deploy.swarm-controller.package` is. There
|
||||||
is deliberately **no overlay** in this project, so a
|
is deliberately **no overlay** in this project, so a
|
||||||
`pkgs.swarm-ui` default here would name an attribute that does
|
`pkgs.swarm-ui` default here would name an attribute that does
|
||||||
not exist on any real deployment.
|
not exist on any real deployment.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf (config.services.hyperhive.enable && deployCfg.swarm-ui.enable) {
|
config = lib.mkIf (config.services.hyperhive.enable && deployCfg.swarm-ui.enable) {
|
||||||
assertions = [
|
assertions = [
|
||||||
|
|
@ -178,7 +178,7 @@ in
|
||||||
extraConfig = gatewayCfg.lib.securityHeaders;
|
extraConfig = gatewayCfg.lib.securityHeaders;
|
||||||
locations = {
|
locations = {
|
||||||
"/" = {
|
"/" = {
|
||||||
root = "${cfg.package}";
|
root = "${deployCfg.swarm-ui.package}";
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
${swarmAuthRequest}
|
${swarmAuthRequest}
|
||||||
# SPA: any path the bundle routes client-side is served the
|
# SPA: any path the bundle routes client-side is served the
|
||||||
|
|
@ -189,7 +189,7 @@ in
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs (stylixThemeColors != null) {
|
// lib.optionalAttrs (stylixThemeColors != null) {
|
||||||
# Stylix theming (see the `let` block above): overrides just
|
# Stylix theming (see the `let` block above): overrides just
|
||||||
# this one file from `cfg.package`'s own static root, rather
|
# this one file from `deployCfg.swarm-ui.package`'s own static root, rather
|
||||||
# than copying the whole tree to change one file inside it —
|
# than copying the whole tree to change one file inside it —
|
||||||
# nginx resolves the more specific `=` exact match over the
|
# nginx resolves the more specific `=` exact match over the
|
||||||
# `/` prefix root above, so this simply doesn't exist (falling
|
# `/` prefix root above, so this simply doesn't exist (falling
|
||||||
|
|
|
||||||
|
|
@ -56,17 +56,11 @@ let
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# What stays here is what the store IS from any hive's point of view: its
|
# What stays here is what the store IS from any hive's point of view: the
|
||||||
# package, the name it answers on, the port. `enable` and `retentionPeriod`
|
# name it answers on and the port. `enable`, `package` and
|
||||||
# are decisions of the host that runs it and live under `deploy.*`.
|
# `retentionPeriod` are decisions of the host that runs it and live under
|
||||||
|
# `deploy.*`.
|
||||||
options.services.hyperhive.swarm.victorialogs = {
|
options.services.hyperhive.swarm.victorialogs = {
|
||||||
package = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
default = pkgs.victorialogs;
|
|
||||||
defaultText = lib.literalExpression "pkgs.victorialogs";
|
|
||||||
description = "VictoriaLogs package to run.";
|
|
||||||
};
|
|
||||||
|
|
||||||
machine = lib.mkOption {
|
machine = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
|
|
@ -116,6 +110,13 @@ in
|
||||||
# and a hive that is a *client* of the log store never consults it. That
|
# and a hive that is a *client* of the log store never consults it. That
|
||||||
# makes it a `deploy.*` value by the same rule as the seal on the secret
|
# makes it a `deploy.*` value by the same rule as the seal on the secret
|
||||||
# store — options on the auto-deployed service itself.
|
# store — options on the auto-deployed service itself.
|
||||||
|
options.services.hyperhive.deploy.victorialogs.package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.victorialogs;
|
||||||
|
defaultText = lib.literalExpression "pkgs.victorialogs";
|
||||||
|
description = "VictoriaLogs package to run.";
|
||||||
|
};
|
||||||
|
|
||||||
options.services.hyperhive.deploy.victorialogs.retentionPeriod = lib.mkOption {
|
options.services.hyperhive.deploy.victorialogs.retentionPeriod = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "30d";
|
default = "30d";
|
||||||
|
|
@ -259,7 +260,7 @@ in
|
||||||
|
|
||||||
services.victorialogs = {
|
services.victorialogs = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = cfg.package;
|
package = deployCfg.victorialogs.package;
|
||||||
|
|
||||||
# ⚠️ PINNED TO LOOPBACK for the same reason the metrics store is,
|
# ⚠️ PINNED TO LOOPBACK for the same reason the metrics store is,
|
||||||
# and it matters more here: upstream's default listens on every
|
# and it matters more here: upstream's default listens on every
|
||||||
|
|
|
||||||
|
|
@ -30,17 +30,11 @@ let
|
||||||
domainBase = if swarmDomain == null then "invalid" else swarmDomain;
|
domainBase = if swarmDomain == null then "invalid" else swarmDomain;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# What stays here is what the store IS from any hive's point of view: its
|
# What stays here is what the store IS from any hive's point of view: the
|
||||||
# package, the name it answers on, the port. `enable` and `retentionPeriod`
|
# name it answers on and the port. `enable`, `package` and
|
||||||
# are decisions of the host that runs it and live under `deploy.*`.
|
# `retentionPeriod` are decisions of the host that runs it and live under
|
||||||
|
# `deploy.*`.
|
||||||
options.services.hyperhive.swarm.victoriametrics = {
|
options.services.hyperhive.swarm.victoriametrics = {
|
||||||
package = lib.mkOption {
|
|
||||||
type = lib.types.package;
|
|
||||||
default = pkgs.victoriametrics;
|
|
||||||
defaultText = lib.literalExpression "pkgs.victoriametrics";
|
|
||||||
description = "VictoriaMetrics package to run.";
|
|
||||||
};
|
|
||||||
|
|
||||||
machine = lib.mkOption {
|
machine = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
|
|
@ -79,6 +73,13 @@ in
|
||||||
# Retention is a property of the store this host runs, not something the
|
# Retention is a property of the store this host runs, not something the
|
||||||
# swarm has to agree on: it is read only where the container is defined,
|
# swarm has to agree on: it is read only where the container is defined,
|
||||||
# and a hive that is a *client* of the metrics store never consults it.
|
# and a hive that is a *client* of the metrics store never consults it.
|
||||||
|
options.services.hyperhive.deploy.victoriametrics.package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.victoriametrics;
|
||||||
|
defaultText = lib.literalExpression "pkgs.victoriametrics";
|
||||||
|
description = "VictoriaMetrics package to run.";
|
||||||
|
};
|
||||||
|
|
||||||
options.services.hyperhive.deploy.victoriametrics.retentionPeriod = lib.mkOption {
|
options.services.hyperhive.deploy.victoriametrics.retentionPeriod = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "5y";
|
default = "5y";
|
||||||
|
|
@ -213,7 +214,7 @@ in
|
||||||
|
|
||||||
services.victoriametrics = {
|
services.victoriametrics = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = cfg.package;
|
package = deployCfg.victoriametrics.package;
|
||||||
retentionPeriod = deployCfg.victoriametrics.retentionPeriod;
|
retentionPeriod = deployCfg.victoriametrics.retentionPeriod;
|
||||||
|
|
||||||
# ⚠️ PINNED TO LOOPBACK, and this is a correction rather than a
|
# ⚠️ PINNED TO LOOPBACK, and this is a correction rather than a
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
#
|
#
|
||||||
# ⚠️ **This evaluates, it does not execute** — a command line, a request or
|
# ⚠️ **This evaluates, it does not execute** — a command line, a request or
|
||||||
# a certificate needs something that *runs* it. A case needing a rendered
|
# a certificate needs something that *runs* it. A case needing a rendered
|
||||||
# file must stub what it drags in (`swarm.ui.package = pkgs.emptyDirectory`).
|
# file must stub what it drags in (`deploy.swarm-ui.package = pkgs.emptyDirectory`).
|
||||||
{
|
{
|
||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
|
|
@ -72,11 +72,12 @@ let
|
||||||
swarm.wireguard.privateKeyFile = "/etc/wireguard/hive.key";
|
swarm.wireguard.privateKeyFile = "/etc/wireguard/hive.key";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Same shape for the forge, which SPLIT rather than moving whole: the five
|
# Same shape for the forge, which SPLIT rather than moving whole: the six
|
||||||
# host-side options are set here through their pre-rename paths while the
|
# host-side options are set here through their pre-rename paths while the
|
||||||
# rest of `swarm.forge` stays put. All five are defined so that dropping any
|
# rest of `swarm.forge` stays put. All six are defined so that dropping any
|
||||||
# single shim entry fails the eval, not just the two the assertion reads.
|
# single shim entry fails the eval, not just the two the assertion reads.
|
||||||
forgeOldPath = hive {
|
forgeOldPath = hive {
|
||||||
|
swarm.forge.package = pkgs.emptyDirectory;
|
||||||
swarm.forge.behindGateway = true;
|
swarm.forge.behindGateway = true;
|
||||||
swarm.forge.openFirewall = true;
|
swarm.forge.openFirewall = true;
|
||||||
swarm.forge.hostSwarmControllerTokenFile = "/etc/forge/sc.token";
|
swarm.forge.hostSwarmControllerTokenFile = "/etc/forge/sc.token";
|
||||||
|
|
@ -89,11 +90,12 @@ let
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# The homeserver's turn to split. All six host-side options are set through
|
# The homeserver's turn to split. All eight host-side options are set through
|
||||||
# their pre-rename paths — including `gui.enable`, whose value is deliberately
|
# their pre-rename paths — including `gui.enable`, whose value is deliberately
|
||||||
# the opposite of its default so the definition has to actually land. All six
|
# the opposite of its default so the definition has to actually land, and both
|
||||||
# so that dropping any single shim entry fails the eval, not just the two the
|
# packages, stubbed to a derivation neither option defaults to for the same
|
||||||
# assertion reads.
|
# reason. All eight so that dropping any single shim entry fails the eval, not
|
||||||
|
# just the ones the assertions read.
|
||||||
matrixOldPath = hive {
|
matrixOldPath = hive {
|
||||||
deploy.matrix.enable = true;
|
deploy.matrix.enable = true;
|
||||||
swarm.matrix.openFirewall = true;
|
swarm.matrix.openFirewall = true;
|
||||||
|
|
@ -101,26 +103,33 @@ let
|
||||||
swarm.matrix.maxRequestSize = 31457280;
|
swarm.matrix.maxRequestSize = 31457280;
|
||||||
swarm.matrix.registrationTokenFile = "/etc/matrix/register.token";
|
swarm.matrix.registrationTokenFile = "/etc/matrix/register.token";
|
||||||
swarm.matrix.gui.enable = false;
|
swarm.matrix.gui.enable = false;
|
||||||
|
swarm.matrix.package = pkgs.emptyDirectory;
|
||||||
|
swarm.matrix.gui.package = pkgs.emptyDirectory;
|
||||||
swarm.matrix.sso.clientSecretFile = "/etc/matrix/oidc.secret";
|
swarm.matrix.sso.clientSecretFile = "/etc/matrix/oidc.secret";
|
||||||
};
|
};
|
||||||
|
|
||||||
# The queue's callout identity, fourth split slice. `autoGenerateCallout` is
|
# The queue's callout identity, fourth split slice. `autoGenerateCallout` is
|
||||||
# left FALSE on purpose: that is what makes the seed paths the thing deciding
|
# left FALSE on purpose: that is what makes the seed paths the thing deciding
|
||||||
# `responderConfigured`, so the assertion below is about the seeds rather
|
# `responderConfigured`, so the assertion below is about the seeds rather
|
||||||
# than about the auto-mint branch. All five old paths are defined, so
|
# than about the auto-mint branch. Every one of the seven old paths is
|
||||||
# dropping any single shim entry fails the eval, not just the arms read.
|
# defined — `enable` included, which is why it is spelled the old way here
|
||||||
|
# while the fixture below uses the new one — so dropping any single nats
|
||||||
|
# shim fails the eval, not just the arms read.
|
||||||
natsOldPath = hive {
|
natsOldPath = hive {
|
||||||
deploy.nats.enable = true;
|
swarm.nats.enable = true;
|
||||||
swarm.nats.autoGenerateCallout = false;
|
swarm.nats.autoGenerateCallout = false;
|
||||||
swarm.nats.calloutUserPublicKey = "UTESTUSERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
swarm.nats.calloutUserPublicKey = "UTESTUSERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||||
swarm.nats.calloutIssuerPublicKey = "ATESTISSUERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
swarm.nats.calloutIssuerPublicKey = "ATESTISSUERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||||
swarm.nats.calloutUserSeedFile = "/run/secrets/nats-user.seed";
|
swarm.nats.calloutUserSeedFile = "/run/secrets/nats-user.seed";
|
||||||
swarm.nats.calloutIssuerSeedFile = "/run/secrets/nats-issuer.seed";
|
swarm.nats.calloutIssuerSeedFile = "/run/secrets/nats-issuer.seed";
|
||||||
|
swarm.nats.authPackage = pkgs.emptyDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Seventh split slice. Only `usersFile` has a rename entry: the other two
|
# Seventh split slice, plus slice 10's two authelia packages. Of slice 7's
|
||||||
# movers are `readOnly`, and a rename module contributes a definition, which
|
# movers only `usersFile` has a rename entry — the other two are `readOnly`,
|
||||||
# a read-only option refuses — see ./host-modules/deploy.nix. So the two arms
|
# and a rename module contributes a definition, which a read-only option
|
||||||
|
# refuses; see ./host-modules/deploy.nix. `package` and `bridgePackage` are
|
||||||
|
# ordinary options, so they do carry one. The two arms
|
||||||
# below have different jobs. `usersFile` tests the rename; the nats one tests
|
# below have different jobs. `usersFile` tests the rename; the nats one tests
|
||||||
# that a reader repointed to the new namespace still renders the derived
|
# that a reader repointed to the new namespace still renders the derived
|
||||||
# path, which is the failure this slice could actually have shipped — seven
|
# path, which is the failure this slice could actually have shipped — seven
|
||||||
|
|
@ -129,6 +138,8 @@ let
|
||||||
deploy.authelia.enable = true;
|
deploy.authelia.enable = true;
|
||||||
deploy.nats.enable = true;
|
deploy.nats.enable = true;
|
||||||
swarm.authelia.usersFile = "/var/lib/test-authelia/users.yml";
|
swarm.authelia.usersFile = "/var/lib/test-authelia/users.yml";
|
||||||
|
swarm.authelia.package = pkgs.emptyDirectory;
|
||||||
|
swarm.authelia.bridgePackage = pkgs.emptyDirectory;
|
||||||
swarm.nats.autoGenerateCallout = false;
|
swarm.nats.autoGenerateCallout = false;
|
||||||
swarm.nats.calloutUserPublicKey = "UTESTUSERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
swarm.nats.calloutUserPublicKey = "UTESTUSERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||||
swarm.nats.calloutIssuerPublicKey = "ATESTISSUERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
swarm.nats.calloutIssuerPublicKey = "ATESTISSUERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||||
|
|
@ -143,20 +154,47 @@ let
|
||||||
deploy.matrix.maxRequestSize = 99000000;
|
deploy.matrix.maxRequestSize = 99000000;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# `enable` is spelled the OLD way like everything else here, so all seven
|
||||||
|
# of the controller's shims are exercised rather than six.
|
||||||
controllerOldPath = hive {
|
controllerOldPath = hive {
|
||||||
deploy.swarm-controller.enable = true;
|
swarm.controller.enable = true;
|
||||||
|
swarm.controller.package = pkgs.emptyDirectory;
|
||||||
|
swarm.controller.swarmctlPackage = pkgs.emptyDirectory;
|
||||||
swarm.controller.socketPath = "/run/test-ctrl/ctrl.sock";
|
swarm.controller.socketPath = "/run/test-ctrl/ctrl.sock";
|
||||||
swarm.controller.forgeTokenFile = "/run/secrets/ctrl-forge.token";
|
swarm.controller.forgeTokenFile = "/run/secrets/ctrl-forge.token";
|
||||||
swarm.controller.authBridgeUrl = "http://127.0.0.1:19097";
|
swarm.controller.authBridgeUrl = "http://127.0.0.1:19097";
|
||||||
swarm.controller.queue.clientSecretFile = "/run/secrets/ctrl-queue.secret";
|
swarm.controller.queue.clientSecretFile = "/run/secrets/ctrl-queue.secret";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# The swarm UI, whose namespace this slice empties: `swarm.ui` had exactly
|
||||||
|
# two options and both have moved, so BOTH old paths are set here and the
|
||||||
|
# whole namespace now lives or dies by its two rename entries.
|
||||||
|
uiOldPath = hive {
|
||||||
|
swarm.ui.enable = true;
|
||||||
|
swarm.ui.package = pkgs.emptyDirectory;
|
||||||
|
};
|
||||||
|
|
||||||
|
# The two stores, which had NO old-path fixture at all until this slice —
|
||||||
|
# their `enable` and `retentionPeriod` shims have been uncovered since they
|
||||||
|
# landed, which is precisely the "a missing shim reads as a clean tree"
|
||||||
|
# failure ./module-eval.nix's wireguard fixture was written to catch. All six
|
||||||
|
# old paths are set, so dropping any single entry fails the eval.
|
||||||
|
storesOldPath = hive {
|
||||||
|
swarm.victoriametrics.enable = true;
|
||||||
|
swarm.victorialogs.enable = true;
|
||||||
|
swarm.victoriametrics.retentionPeriod = "3d";
|
||||||
|
swarm.victorialogs.retentionPeriod = "5d";
|
||||||
|
swarm.victoriametrics.package = pkgs.emptyDirectory;
|
||||||
|
swarm.victorialogs.package = pkgs.emptyDirectory;
|
||||||
|
};
|
||||||
|
|
||||||
grafanaOldPath = hive {
|
grafanaOldPath = hive {
|
||||||
deploy.grafana.enable = true;
|
deploy.grafana.enable = true;
|
||||||
swarm.grafana.socketDir = "/run/test-grafana-sock";
|
swarm.grafana.socketDir = "/run/test-grafana-sock";
|
||||||
swarm.grafana.datasourceUrl = "http://127.0.0.1:19999";
|
swarm.grafana.datasourceUrl = "http://127.0.0.1:19999";
|
||||||
swarm.grafana.logsDatasourceUrl = "http://127.0.0.1:19998";
|
swarm.grafana.logsDatasourceUrl = "http://127.0.0.1:19998";
|
||||||
swarm.grafana.plugins = [ ];
|
swarm.grafana.plugins = [ ];
|
||||||
|
swarm.grafana.package = pkgs.emptyDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
# The first slice to leave options on BOTH sides of the split, so the
|
# The first slice to leave options on BOTH sides of the split, so the
|
||||||
|
|
@ -472,6 +510,43 @@ let
|
||||||
# host-side half depends on: no store here, so no bind mount and no unit.
|
# host-side half depends on: no store here, so no bind mount and no unit.
|
||||||
# Without it a hive that merely names a token would drag the store's
|
# Without it a hive that merely names a token would drag the store's
|
||||||
# container config into its evaluation.
|
# container config into its evaluation.
|
||||||
|
# Reads the vhost's rendered `root`, not the option: the UI is served
|
||||||
|
# straight out of a store path, so a shim that resolves but stops
|
||||||
|
# reaching the module would leave nginx pointing at the default build.
|
||||||
|
name = "a config written against the pre-rename swarm-ui paths still serves the operator's build";
|
||||||
|
#
|
||||||
|
# ⚠️ `unsafeDiscardStringContext` on both sides, load-bearing rather than
|
||||||
|
# tidy: interpolating a derivation carries string *context*, and this
|
||||||
|
# suite renders its results into a `buildCommand` that may not reference
|
||||||
|
# store paths. Comparing the paths as plain text is the intent — the case
|
||||||
|
# asks "does nginx point HERE", not "depend on what it points at".
|
||||||
|
ok =
|
||||||
|
let
|
||||||
|
want = builtins.unsafeDiscardStringContext "${pkgs.emptyDirectory}";
|
||||||
|
# `or ""` is NOT enough: nginx's `locations.<l>.root` is `nullOr`, so
|
||||||
|
# a vhost that HAS the attribute set to null skips the default and
|
||||||
|
# reaches the coercion. Filter nulls, then discard context.
|
||||||
|
roots = map builtins.unsafeDiscardStringContext (
|
||||||
|
lib.filter (r: r != null) (
|
||||||
|
map (v: v.locations."/".root or null) (builtins.attrValues uiOldPath.services.nginx.virtualHosts)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
in
|
||||||
|
builtins.elem want roots;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# Reads the package the CONTAINER renders, not the option: a shim that
|
||||||
|
# resolves but stops reaching the module would leave the store running
|
||||||
|
# nixpkgs' default while the operator's override read back fine.
|
||||||
|
name = "a config written against the pre-rename store paths still picks the operator's package";
|
||||||
|
ok =
|
||||||
|
storesOldPath.containers.swarm-victorialogs.config.services.victorialogs.package
|
||||||
|
== pkgs.emptyDirectory
|
||||||
|
&&
|
||||||
|
storesOldPath.containers.swarm-victoriametrics.config.services.victoriametrics.package
|
||||||
|
== pkgs.emptyDirectory;
|
||||||
|
}
|
||||||
|
{
|
||||||
name = "a bootstrap token on a host that runs no store grants nothing";
|
name = "a bootstrap token on a host that runs no store grants nothing";
|
||||||
ok = !(baoGrantNoStore.systemd.services ? swarm-bao-bootstrap-dir);
|
ok = !(baoGrantNoStore.systemd.services ? swarm-bao-bootstrap-dir);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue