Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/host-modules/deploy.nix
atlas 4bd5c51e2e deploy: drop the per-option restatement of what allSwarmServices asserts
mara: "deploy.nix still says it everywhere". Seven option descriptions
each told the reader that this service derives from the swarm-services
switch — the same duplication just removed from docs/swarm/services.md,
one layer over, and rendered into the generated options doc.

Each keeps only what is true of that service and nothing else: the
metrics store is paired with grafana, the log store has clients rather
than second instances, the homeserver can be placed on its own host, a
swarm has one SSO provider. The store's paragraph about where it runs
being a separate question from that it runs survives, because that is
about the store, not about the switch.

swarm-ui keeps its positive derivation (the controller) and loses only
the "rather than from allSwarmServices" half.

Deliberately not touched, as a different question rather than an
oversight: the *mode* option's description in local-defaults.nix, whose
whole job is to name what it asserts; the module comments in
swarm-authelia.nix / swarm.nix, which are read by someone editing that
module rather than by an operator picking an option; and ui.md's
contrast, which she has not ruled on.
2026-08-30 20:12:16 +02:00

297 lines
12 KiB
Nix

# "What does THIS host deploy?"
#
# Separated from `services.hyperhive.swarm.*` because those are two
# different kinds of fact and only one of them varies per machine:
#
# swarm.* — swarm-wide truth. The swarm's name, domain, hives, peers,
# CA, and where each service lives. **Identical on every
# host**, byte for byte; a hive needs all of it to be a
# *client* of the swarm.
# deploy.* — this machine's deployment decisions. Necessarily different
# on every host, because that is what a deployment is.
#
# The `enable` toggles live here rather than under `swarm.*` so the
# namespace that is identical everywhere does not carry the one thing
# that must differ per host.
#
# Flat and named for the thing deployed — `deploy.forgejo`, not
# `deploy.swarmServices.forgejo`: grouping by "swarm service" re-encodes
# the service-side taxonomy into a layer that does not care about it.
#
# ⚠️ Each entry is an attrset with an `enable`, not a bare bool, so a
# service that grows a second *deployment* decision has somewhere to put
# it — `deploy.forgejo = { enable; ci; }` is then an ordinary addition
# rather than a migration. `ci` ("does this host run the runner too") is
# exactly that shape, and a bare bool leaves it unrepresentable.
#
# ⚠️ The renames below are deliberately in this one file rather than
# spread across the service modules, so the whole move has a single home
# and a single file to delete when the deprecation window closes — the
# shape ./swarm-peers-removed.nix already uses.
{ lib, config, ... }:
let
deployCfg = config.services.hyperhive.deploy;
in
{
imports = [
# Same type, same meaning, new path — so a rename carries it exactly
# and existing configs keep evaluating with one warning naming both
# paths. Precedent: ./hive-forge/default.nix, ./hive-matrix.nix.
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "grafana" "enable" ]
[ "services" "hyperhive" "deploy" "grafana" "enable" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "victoriametrics" "enable" ]
[ "services" "hyperhive" "deploy" "victoriametrics" "enable" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "victorialogs" "enable" ]
[ "services" "hyperhive" "deploy" "victorialogs" "enable" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "controller" "enable" ]
[ "services" "hyperhive" "deploy" "swarm-controller" "enable" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "ui" "enable" ]
[ "services" "hyperhive" "deploy" "swarm-ui" "enable" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "authelia" "enable" ]
[ "services" "hyperhive" "deploy" "authelia" "enable" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "nats" "enable" ]
[ "services" "hyperhive" "deploy" "nats" "enable" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "otel" "enable" ]
[ "services" "hyperhive" "deploy" "swarm-otel" "enable" ]
)
# The CI runner, and the only entry here that renames more than an
# `enable`: every knob under it describes the runner THIS host would run,
# so leaving `name`/`concurrency`/`labels`/`package` in the namespace that
# must be identical swarm-wide would keep the original defect for four
# more options. Renamed one by one because `ci` is a plain attrset of
# options rather than a submodule type, so there is no parent path to
# rename in a single entry.
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "forge" "ci" "enable" ]
[ "services" "hyperhive" "deploy" "forgejo" "ci" "enable" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "forge" "ci" "name" ]
[ "services" "hyperhive" "deploy" "forgejo" "ci" "name" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "forge" "ci" "concurrency" ]
[ "services" "hyperhive" "deploy" "forgejo" "ci" "concurrency" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "forge" "ci" "labels" ]
[ "services" "hyperhive" "deploy" "forgejo" "ci" "labels" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "forge" "ci" "package" ]
[ "services" "hyperhive" "deploy" "forgejo" "ci" "package" ]
)
# 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
# agrees on. The two stores keep everything else — package, domain, port
# — in `swarm.*`, because a client hive needs those to reach them.
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "victoriametrics" "retentionPeriod" ]
[ "services" "hyperhive" "deploy" "victoriametrics" "retentionPeriod" ]
)
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "victorialogs" "retentionPeriod" ]
[ "services" "hyperhive" "deploy" "victorialogs" "retentionPeriod" ]
)
# The switch over all of the above, and the name changes with the path
# because the old one described the wrong subject: those services are
# required of the SWARM, while the option says whether THIS host runs
# them. `allSwarmServices` is mara's own phrasing of what it means.
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "enableRequiredServices" ]
[ "services" "hyperhive" "deploy" "allSwarmServices" ]
)
# The mode above that one. It sat at the TOP of `services.hyperhive`,
# which is the same defect one tier up: that namespace is everything
# about hyperhive, not the settings of a single hive. The new name says
# what the mode asserts — the whole swarm runs on this host — instead of
# naming its mechanism.
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "enableAllLocalDefaults" ]
[ "services" "hyperhive" "deploy" "singleHostSwarm" ]
)
];
# ⚠️ `deploy.forgejo` is declared in ./hive-ci.nix, not here, and it is the
# one entry with no `enable`: the forge is not optional — it is the canonical
# store for the meta flake and every agent's config repo, so it deploys with
# hyperhive itself. Running the CI runner is the only *deployment* decision
# it has, which is exactly the `{ enable; ci; }` shape the header describes,
# minus the half that does not apply. The knobs live with the module that
# reads them; this file stays the registry of toggles.
options.services.hyperhive.deploy = {
grafana.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Run the swarm's metrics UI on this host.
Off by default and not derived from
{option}`services.hyperhive.enable`: a swarm has one Grafana, so
running it is a decision about this host rather than about
whether hyperhive is installed.
'';
};
victoriametrics.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Run the swarm's metrics store on this host.
Paired with
{option}`services.hyperhive.deploy.grafana.enable`: a store
with no UI is unreadable and a UI with no store is empty, so there
is no sensible deployment that takes one and not the other from
that switch. Set either directly to run exactly one.
'';
};
victorialogs.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Run the swarm's log store on this host.
A hive that is not the service host is a *client* of this store,
not a second one.
'';
};
bao.enable = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Run the swarm's secret store in a `swarm-bao` container on this
host. A swarm has one store and it has to exist somewhere.
*Where* it runs is a separate question from *that* it runs: set
this directly to put the store on a host of its own, and clients
still reach it by name at
{option}`services.hyperhive.swarm.bao.domain` rather than at a
local address.
With it off, this hive is a *client*: it still reads its own
secrets from whoever runs the store, authenticating with its own
client certificate. Every hive needs the client half; only one
runs the server half, which is why the two live in different
namespaces.
'';
};
authelia.enable = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Run the swarm's authelia in a `swarm-authelia` container on this
host. A swarm has one SSO provider, and this says it lives here.
With it off, this hive is a *client*:
{option}`services.hyperhive.swarm.authelia.url` still points at
whoever runs it, and no container is created. That asymmetry is
why the two live in different namespaces — every hive needs the
client half, only one runs the server half.
'';
};
swarm-otel.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Run the **swarm's** telemetry collector on this host.
A swarm has one of these, and it belongs wherever the shared
services live rather than on every hive.
Named `swarm-otel` rather than `otel` because there are two
collectors and the tier is the whole distinction:
{option}`services.hyperhive.otel.enable` is the **hive-tier** one,
which every hive runs. A bare `deploy.otel` would not say which
it meant. A hive that does not run the swarm collector still runs
its own, and reaches this one by name at
{option}`services.hyperhive.swarm.otel.domain`.
'';
};
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.
Set it directly to put the homeserver somewhere other than the
host holding the rest of the swarm's services.
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 {
type = lib.types.bool;
default = false;
description = ''
Run the swarm's message queue in a `swarm-nats` container on this
host. A swarm has one queue, so at most one host turns this on —
but *which* host is its own decision, not necessarily the one
running the swarm's other shared services.
Off by default, and off means *absent*: no container is created
and nothing else in the evaluated config changes.
'';
};
swarm-controller.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Run the swarm-controller daemon on this host.
Off by default and deliberately not derived from
{option}`services.hyperhive.enable`: a swarm has one controller,
so running it is a decision about this host rather than about
whether hyperhive is installed.
'';
};
swarm-ui.enable = lib.mkOption {
type = lib.types.bool;
default = deployCfg.swarm-controller.enable;
defaultText = lib.literalExpression "services.hyperhive.deploy.swarm-controller.enable";
example = true;
description = ''
Serve the swarm UI from this host.
Derived from
{option}`services.hyperhive.deploy.swarm-controller.enable`: the
UI is a view onto the controller's state and reaches it over that
daemon's unix socket, so the host that runs the controller is the
host that can serve the UI. A hive that merely *uses* a swarm has
nothing to serve here.
'';
};
};
}