refactor(nix): make all-local a deployment mode, not a default
mara: enableAllLocalDefaults is more of a deployment mode via settings set, less a default setting. That reframing is the change. A mode asserts values; an option declares what it is when nobody asks. Written as default = <flag>, every service option had to name a switch it has no relationship to, and the answer to what does all-local turn on was spread across five files. Two modules now hold the two tiers - local-defaults.nix for the mode and what it asserts directly, swarm-required-services.nix for the services-live-here switch and the per-service enables under it. Each service module keeps its own declaration and loses only the line about when a deployment wants it. mkDefault is the right precedence rather than a compromise: it beats an option default and yields to any explicit definition, so the mode fills in for an operator who has not spoken and never argues with one who has. Evaluated config is unchanged in both directions.
This commit is contained in:
parent
01680ee962
commit
048bdd29a8
8 changed files with 134 additions and 79 deletions
|
|
@ -12,6 +12,7 @@
|
|||
{
|
||||
imports = [
|
||||
./hyperhive.nix
|
||||
./local-defaults.nix
|
||||
./hive-c0re
|
||||
./hive-ci.nix
|
||||
./hive-forge
|
||||
|
|
@ -27,5 +28,6 @@
|
|||
./swarm-snapshot-store.nix
|
||||
./swarm-wireguard.nix
|
||||
./swarm.nix
|
||||
./swarm-required-services.nix
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,19 +99,16 @@ in
|
|||
options.services.hyperhive.swarm.matrix = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = config.services.hyperhive.swarm.enableRequiredServices;
|
||||
defaultText = lib.literalExpression "services.hyperhive.swarm.enableRequiredServices";
|
||||
default = false;
|
||||
description = ''
|
||||
Run hive-matrix — a private matrix-tuwunel homeserver (in a
|
||||
nixos-container) for hyperhive agents.
|
||||
|
||||
Matrix is a swarm-wide service — one homeserver, not one per
|
||||
hive — so this defaults from
|
||||
`services.hyperhive.swarm.enableRequiredServices`, which says
|
||||
the swarm's shared services live on this host. That is off by
|
||||
default, so this is off by default, as before. Set it directly
|
||||
to run the homeserver somewhere other than the host that holds
|
||||
the rest of the swarm's services.
|
||||
hive — so `services.hyperhive.swarm.enableRequiredServices`
|
||||
turns this on as part of saying the swarm's shared services live
|
||||
on this host. Set it here directly to run the homeserver
|
||||
somewhere other than the host that holds the rest of them.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -132,31 +132,9 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
# The one switch for "everything runs on this box". Every autoconf
|
||||
# toggle in the tree defaults from it, so an all-local deployment is a
|
||||
# single line rather than one line per service that grew a toggle.
|
||||
options.services.hyperhive.enableAllLocalDefaults = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Run the whole swarm on this host: the swarm-wide services
|
||||
(`services.hyperhive.swarm.enableRequiredServices`) and the swarm
|
||||
CA (`services.hyperhive.swarm.ca.autoConfigure`) all default from
|
||||
this, and anything autoconfigurable added later should too.
|
||||
|
||||
**Off by default, and that is the load-bearing part.** A swarm's
|
||||
services and its hives can live on different hosts, and a host has
|
||||
no way to tell which ones it is meant to be — so this is an
|
||||
operator saying "this is that box", never something inferred.
|
||||
Turn it on for a dev box or a single-hive swarm and get a working
|
||||
deployment with no further configuration; leave it off and every
|
||||
swarm-level artifact is operator-provided.
|
||||
|
||||
Each derived toggle can still be set explicitly to override this
|
||||
one, so "all local except X" needs no new option.
|
||||
'';
|
||||
};
|
||||
# `enableAllLocalDefaults` is declared in ./local-defaults.nix, with
|
||||
# the values it asserts. It is a deployment mode rather than a setting
|
||||
# this module's options read, so it lives with its consequences.
|
||||
|
||||
# Whether this hive runs "ruthless" — with no root/manager agent at
|
||||
# all. Some hives don't want a root agent — see issue tracker
|
||||
|
|
|
|||
58
nix/host-modules/local-defaults.nix
Normal file
58
nix/host-modules/local-defaults.nix
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# The all-local deployment mode.
|
||||
#
|
||||
# `enableAllLocalDefaults` is a *mode*, not a default other options read:
|
||||
# it says "this box is the whole deployment" and then asserts the values
|
||||
# that follow from that. mara, on the issue: it is "more of a deployment
|
||||
# mode via settings set, less a default setting".
|
||||
#
|
||||
# That distinction is why the derivations live here as `mkDefault` in a
|
||||
# `config` block rather than as `default =` inside each option. An option
|
||||
# declares what IT is and what it is when nobody asks; a mode declares
|
||||
# what a deployment shape implies. Written the other way round, every
|
||||
# service option had to name a flag it has no relationship to, and the
|
||||
# answer to "what does all-local turn on?" was spread across five files.
|
||||
#
|
||||
# Adding an autoconfigurable thing later means one line here — not a
|
||||
# `default =` in the new module pointing back at this flag.
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.hyperhive;
|
||||
in
|
||||
{
|
||||
options.services.hyperhive.enableAllLocalDefaults = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Run the whole swarm on this host. Turning this on asserts the
|
||||
swarm-level toggles that an all-on-one-box deployment implies:
|
||||
the swarm's shared services
|
||||
(`services.hyperhive.swarm.enableRequiredServices`) and the swarm
|
||||
CA (`services.hyperhive.swarm.ca.autoConfigure`).
|
||||
|
||||
**Off by default, and that is the load-bearing part.** A swarm's
|
||||
services and its hives can live on different hosts, and a host has
|
||||
no way to tell which ones it is meant to be — so this is an
|
||||
operator saying "this is that box", never something inferred.
|
||||
Turn it on for a dev box or a single-hive swarm and get a working
|
||||
deployment with no further configuration; leave it off and every
|
||||
swarm-level artifact is operator-provided.
|
||||
|
||||
Each toggle it asserts can still be set explicitly, which wins —
|
||||
so "all local except X" needs no new option.
|
||||
'';
|
||||
};
|
||||
|
||||
# What the mode asserts. `mkDefault` (priority 1000) beats an option's
|
||||
# own `default` (1500) and loses to any explicit definition, which is
|
||||
# exactly the precedence a deployment mode wants: it fills in for an
|
||||
# operator who hasn't spoken, and never argues with one who has.
|
||||
config.services.hyperhive.swarm = {
|
||||
enableRequiredServices = lib.mkDefault cfg.enableAllLocalDefaults;
|
||||
ca.autoConfigure = lib.mkDefault cfg.enableAllLocalDefaults;
|
||||
};
|
||||
}
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
#
|
||||
# - the CLIENT pointer (`url`) exists on every hive, because a hive
|
||||
# that doesn't run authelia still has to know where to send people.
|
||||
# - the CONTAINER only exists where the swarm's shared services live
|
||||
# (`swarm.enableRequiredServices`, itself defaulting from
|
||||
# `enableAllLocalDefaults`). A hive is a client by default.
|
||||
# - the CONTAINER only exists where the swarm's shared services live.
|
||||
# `swarm.enableRequiredServices` asserts this module's `enable`
|
||||
# (see ./swarm-required-services.nix); a hive is a client by default.
|
||||
#
|
||||
# Operator and agents are both subjects of the same provider,
|
||||
# differentiated by roles/claims rather than by mechanism — there is one
|
||||
|
|
@ -31,7 +31,6 @@
|
|||
let
|
||||
cfg = config.services.hyperhive.swarm.authelia;
|
||||
hyperhiveCfg = config.services.hyperhive;
|
||||
swarmCfg = config.services.hyperhive.swarm;
|
||||
hyperhiveDomain = hyperhiveCfg.domain;
|
||||
|
||||
# Upstream's `services.authelia.instances.<name>` derives the unit,
|
||||
|
|
@ -51,14 +50,13 @@ in
|
|||
options.services.hyperhive.swarm.authelia = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = swarmCfg.enableRequiredServices;
|
||||
defaultText = lib.literalExpression "services.hyperhive.swarm.enableRequiredServices";
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Run the swarm's authelia in a `swarm-authelia` container on this
|
||||
host. Defaults from
|
||||
`services.hyperhive.swarm.enableRequiredServices` — a swarm has
|
||||
one SSO provider, and this says it lives here.
|
||||
host. `services.hyperhive.swarm.enableRequiredServices` turns
|
||||
this on — a swarm has one SSO provider, and that says it lives
|
||||
here.
|
||||
|
||||
With it off, this hive is a *client*: `url` below still points
|
||||
at whoever runs it, and no container is created.
|
||||
|
|
|
|||
|
|
@ -52,18 +52,15 @@ in
|
|||
options.services.hyperhive.swarm.ca = {
|
||||
autoConfigure = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = hyperhiveCfg.enableAllLocalDefaults;
|
||||
defaultText = lib.literalExpression "services.hyperhive.enableAllLocalDefaults";
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Run the whole swarm CA on this one host: generate the swarm
|
||||
root when it is missing, and issue this hive's CA under it.
|
||||
|
||||
Defaults from `services.hyperhive.enableAllLocalDefaults`, the
|
||||
all-on-one-box switch — which is off, so this is off, and the
|
||||
paragraph below still describes what a hive does by default.
|
||||
Set it directly to run the CA on a host that is not otherwise
|
||||
all-local.
|
||||
`services.hyperhive.enableAllLocalDefaults` turns this on as
|
||||
part of the all-on-one-box mode. Set it here directly to run the
|
||||
CA on a host that is not otherwise all-local.
|
||||
|
||||
**Off by default, deliberately.** A swarm's services and its
|
||||
hives can live on different hosts, and this host has no way to
|
||||
|
|
|
|||
51
nix/host-modules/swarm-required-services.nix
Normal file
51
nix/host-modules/swarm-required-services.nix
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# "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.
|
||||
#
|
||||
# Only the *optional* services derive: matrix and authelia. The forge has
|
||||
# no `enable` to assert, because it is not optional — it is the canonical
|
||||
# store for the meta flake and every agent's config repo, so it deploys
|
||||
# with hyperhive itself.
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
swarmCfg = config.services.hyperhive.swarm;
|
||||
in
|
||||
{
|
||||
options.services.hyperhive.swarm.enableRequiredServices = 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 and are *optional*
|
||||
— the matrix homeserver, the SSO provider — have their `enable`
|
||||
asserted from this, so a swarm's service host is declared in one
|
||||
place.
|
||||
|
||||
The forge is swarm-wide too but has nothing to assert: it is the
|
||||
canonical store for the meta flake and every agent's config repo,
|
||||
so it deploys with hyperhive itself and is not optional.
|
||||
|
||||
`services.hyperhive.enableAllLocalDefaults` 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.
|
||||
config.services.hyperhive.swarm = {
|
||||
matrix.enable = lib.mkDefault swarmCfg.enableRequiredServices;
|
||||
authelia.enable = lib.mkDefault swarmCfg.enableRequiredServices;
|
||||
};
|
||||
}
|
||||
|
|
@ -126,36 +126,10 @@
|
|||
'';
|
||||
};
|
||||
|
||||
# "The swarm-wide services run HERE." A swarm has one forge, one
|
||||
# matrix, one SSO — this says this host is where they live. The
|
||||
# OPTIONAL ones (matrix, authelia) default their own enable from it,
|
||||
# rather than the operator enabling them one at a time; the forge has
|
||||
# no enable to derive because it is not optional.
|
||||
options.services.hyperhive.swarm.enableRequiredServices = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = config.services.hyperhive.enableAllLocalDefaults;
|
||||
defaultText = lib.literalExpression "services.hyperhive.enableAllLocalDefaults";
|
||||
example = true;
|
||||
description = ''
|
||||
Host the swarm's shared services on this hive. The services that
|
||||
exist once per swarm rather than once per hive and are *optional*
|
||||
— the matrix homeserver, the SSO provider — default their
|
||||
`enable` from this, so a swarm's service host is declared in one
|
||||
place.
|
||||
|
||||
The forge is swarm-wide too but has no `enable` to derive: it is
|
||||
the canonical store for the meta flake and every agent's config
|
||||
repo, so it deploys with hyperhive itself and is not optional.
|
||||
|
||||
Defaults from `services.hyperhive.enableAllLocalDefaults` (off),
|
||||
which is the all-on-one-box switch. 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.
|
||||
'';
|
||||
};
|
||||
# `enableRequiredServices` is declared in ./swarm-required-services.nix
|
||||
# together with the per-service `enable`s it asserts — it is a
|
||||
# deployment-shape switch rather than swarm bookkeeping, so it lives
|
||||
# with its consequences instead of here.
|
||||
|
||||
options.services.hyperhive.swarm.snapshotStore = {
|
||||
address = lib.mkOption {
|
||||
|
|
|
|||
Loading…
Reference in a new issue