argus's review on #5177: the git credential helper answered every `get`, so a config PR's own flake inputs could have git send the builder's forge token to any host. The helper is now configured under `credential.<forge-url>.helper` and itself answers only an https request whose host is the forge's; a test runs it as git does and checks that other hosts, http and non-get operations get nothing. Builds are bounded: every `build_agent` node needs the one `builder` jobq resource, so one runs at a time and the rest wait pending, and a newer head cancels its PR's pending build (a running one finishes and writes on its own commit). The builder also holds a one-permit semaphore around each build. `builder` and `review-classifier`, the forge logins swarm-controller owns, join nix/reserved-names.nix, with a test tying the list to both constants. The builder is now opt-in like the CI runner: `allSwarmServices` no longer turns it on, since it runs unreviewed config PRs through the host's nix daemon. mara had not answered atlas's question on the PR.
120 lines
5.8 KiB
Nix
120 lines
5.8 KiB
Nix
# "The swarm-wide services run HERE."
|
|
#
|
|
# A swarm has one forge, one matrix, one SSO. This says this host is
|
|
# where they live, and asserts the per-service `enable`s that follow —
|
|
# the same mode-not-default shape as ./local-defaults.nix, one tier down.
|
|
#
|
|
# The forge derives from here like the rest: every swarm needs one, but
|
|
# only one host in it runs it.
|
|
{
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
deployCfg = config.services.hyperhive.deploy;
|
|
in
|
|
{
|
|
options.services.hyperhive.deploy.allSwarmServices = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
example = true;
|
|
description = ''
|
|
Host the swarm's shared services on this hive. The services that
|
|
exist once per swarm rather than once per hive — the forge, the
|
|
matrix homeserver, the SSO provider, the queue, the metrics and log
|
|
stores — have their toggle asserted from this, so a swarm's service
|
|
host is declared in one place.
|
|
|
|
Every toggle it asserts is a {option}`services.hyperhive.deploy.*`
|
|
one, because "does THIS host run it" is a per-host decision — which
|
|
is the same reason this option is a `deploy.*` one itself. See
|
|
./deploy.nix.
|
|
|
|
`services.hyperhive.deploy.singleHostSwarm` turns this on as part
|
|
of the all-on-one-box mode. Set it directly to run the swarm's
|
|
services on a host that is not otherwise all-local — a dedicated
|
|
services box with hives elsewhere is exactly that shape.
|
|
|
|
With it off, this hive is a *client* of those services: it still
|
|
configures how to reach them, it just doesn't run them.
|
|
'';
|
|
};
|
|
|
|
# Same precedence reasoning as ./local-defaults.nix: fills in for an
|
|
# operator who hasn't spoken, yields to one who has.
|
|
#
|
|
# Everything derives under `deploy.*` now, because "does THIS host run
|
|
# it" is a per-host decision and `swarm.*` has to be identical on every
|
|
# host. Same switch, same rule, one attribute path.
|
|
config.services.hyperhive.deploy.matrix.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The collector that feeds the pair above (note: no `swarm.` prefix,
|
|
# this is ./otel.nix's existing per-hive option).
|
|
config.services.hyperhive.otel.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The rest of the shared services, from the same switch and for the same
|
|
# reason.
|
|
#
|
|
# authelia: a swarm has one SSO provider, and this says it lives here.
|
|
# With it off the hive is a *client* — `swarm.authelia.url` still points
|
|
# at whoever runs it.
|
|
config.services.hyperhive.deploy.authelia.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The queue. Same rule: once per swarm, optional.
|
|
config.services.hyperhive.deploy.nats.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The swarm collector that feeds the metrics pair, and the only tier
|
|
# holding the upstream credential. ⚠️ NOT the per-hive collector below,
|
|
# which every hive runs.
|
|
config.services.hyperhive.deploy.swarm-otel.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The metrics pair, deriving together on purpose: 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 this switch. An
|
|
# operator who wants exactly one still sets it directly, which
|
|
# `mkDefault` allows.
|
|
config.services.hyperhive.deploy.victoriametrics.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
config.services.hyperhive.deploy.grafana.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The log store, from the same switch for the same reason as the rest: a
|
|
# hive that is not the service host is a *client* of it, not a second one.
|
|
config.services.hyperhive.deploy.victorialogs.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The plumbing those services are reached over: every one of them is
|
|
# fronted by the gateway, resolved through the hive's dnsmasq, and runs
|
|
# in a container hanging off the bridge. Written as `mkIf … mkDefault`
|
|
# rather than `mkDefault allSwarmServices` because the modules that need
|
|
# these also assert them — a `false` from here would collide with their
|
|
# `true` instead of losing to it.
|
|
config.services.hyperhive.gateway.enable = lib.mkIf deployCfg.allSwarmServices (lib.mkDefault true);
|
|
config.services.hyperhive.gateway.dns.enable = lib.mkIf deployCfg.allSwarmServices (
|
|
lib.mkDefault true
|
|
);
|
|
config.services.hyperhive.network.enable = lib.mkIf deployCfg.allSwarmServices (lib.mkDefault true);
|
|
|
|
# The secret store. Once per swarm and optional, so it belongs to the
|
|
# same switch: a hive that does not run it is a *client*, reading its
|
|
# own secrets from whoever does. `mkDefault` is what keeps the store
|
|
# placeable on a host of its own — it can be set directly here and
|
|
# turned off wherever this switch happens to be on.
|
|
config.services.hyperhive.deploy.bao.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The forge. Every swarm needs it, but one host runs it: a hive that does
|
|
# not is a *client*, reaching it at `swarm.forge.domain`. Without this a
|
|
# `singleHostSwarm` box, which gets here through `allSwarmServices`, would
|
|
# have no forge at all.
|
|
config.services.hyperhive.deploy.forgejo.enable = lib.mkDefault deployCfg.allSwarmServices;
|
|
|
|
# The review classifier. Its module asserts a store identity, which
|
|
# glue-bao-tls.nix mints only on the host that runs the store; with the store
|
|
# placed elsewhere both files stay null and an unconditional `true` here would
|
|
# fail that host's eval. So the default follows the identity, and a host
|
|
# holding a copy of the pair (`deploy.bao.reviewClassifierClient{Cert,Key}File`)
|
|
# gets the classifier too.
|
|
config.services.hyperhive.deploy.review-classifier.enable = lib.mkDefault (
|
|
deployCfg.allSwarmServices
|
|
&& deployCfg.bao.reviewClassifierClientCertFile != null
|
|
&& deployCfg.bao.reviewClassifierClientKeyFile != null
|
|
);
|
|
}
|