Watch
0
0
Fork
You've already forked hyperhive
0

drop option renames and removals older than two weeks

Refs #5379
This commit is contained in:
atlas 2026-10-16 20:28:14 +02:00
commit 8e09f8360a
47 changed files with 98 additions and 1026 deletions

View file

@ -37,7 +37,7 @@ let
m:
lib.any (a: !a.assertion && lib.hasInfix "deploy.builder.enable requires" a.message) m.assertions;
natsHere = shared.natsOldPath;
natsHere = shared.natsQueueOnly;
autheliaHere = hive {
deploy.bao.enable = true;

View file

@ -995,36 +995,6 @@ let
&& bare.services.dnsmasq.enable
&& bare.networking.bridges ? hive-br0;
}
{
# A host config written against either old spelling still runs its hive.
# The builder's own `true` is lowered to `mkDefault false`, so only the
# forwarded definition can turn it on.
name = "the old hive toggles forward to deploy.hive-controller.enable and warn";
ok =
let
renamedFrom =
old: m:
lib.any (
w: lib.hasInfix old w && lib.hasInfix "services.hyperhive.deploy.hive-controller.enable" w
) m.warnings;
viaOld =
extra:
hive (
extra
// {
deploy.hive-controller.enable = lib.mkDefault false;
}
);
oldEnable = viaOld { enable = true; };
oldC0re = viaOld { c0re.enable = true; };
in
oldEnable.services.hyperhive.deploy.hive-controller.enable
&& oldEnable.systemd.services ? hive-c0re
&& renamedFrom "services.hyperhive.enable" oldEnable
&& oldC0re.services.hyperhive.deploy.hive-controller.enable
&& oldC0re.systemd.services ? hive-c0re
&& renamedFrom "services.hyperhive.c0re.enable" oldC0re;
}
{
# Refused wherever something turns the name into an identifier, and only
# there. The store host is the control that the refusal is not the hive's

View file

@ -82,16 +82,6 @@ let
deploy.hive-controller.enable = false;
deploy.forgejo.ci.enable = true;
};
# The older spelling, under the swarm-level forge options.
ciUnderSwarmForge = hive {
swarm.forge.ci.enable = true;
swarm.forge.ci.name = "older-runner";
swarm.forge.ci.concurrency = 2;
swarm.forge.ci.labels = [ "nix:host" ];
swarm.forge.ci.package = pkgs.hello;
deploy.bao.ciRunnerClientCertFile = "/etc/pki/bao-ci-runner.pem";
deploy.bao.ciRunnerClientKeyFile = "/etc/pki/bao-ci-runner-key.pem";
};
runsForge = m: m.services.hyperhive.deploy.forgejo.enable && m.containers ? hive-forge;
@ -299,22 +289,6 @@ let
&& lib.any (lib.hasInfix "services.hyperhive.deploy.forgejo.ci.enable") ciUnderForge.warnings
&& !(lib.any (a: !a.assertion) ciUnderForge.assertions);
}
{
# The control is the container: it only exists if `enable` arrived.
name = "a CI option under swarm.forge sets the same option under deploy.ci-runner";
ok =
let
r = ciUnderSwarmForge.services.hyperhive.deploy.ci-runner;
in
r.enable
&& r.name == "older-runner"
&& r.concurrency == 2
&& r.labels == [ "nix:host" ]
&& r.package == pkgs.hello
&& ciUnderSwarmForge.containers ? swarm-ci-runner
&& lib.any (lib.hasInfix "services.hyperhive.swarm.forge.ci.enable") ciUnderSwarmForge.warnings
&& !(lib.any (a: !a.assertion) ciUnderSwarmForge.assertions);
}
{
# The rename carries `enable` but not the identity: an old config with
# only the old name is refused, and the message says what to set. The

View file

@ -22,12 +22,12 @@ let
runGroup
;
grafanaOldPath = hive {
grafanaHere = hive {
deploy.grafana.enable = true;
swarm.grafana.datasourceUrl = "http://127.0.0.1:19999";
swarm.grafana.logsDatasourceUrl = "http://127.0.0.1:19998";
swarm.grafana.plugins = [ ];
swarm.grafana.package = pkgs.emptyDirectory;
deploy.grafana.datasourceUrl = "http://127.0.0.1:19999";
deploy.grafana.logsDatasourceUrl = "http://127.0.0.1:19998";
deploy.grafana.plugins = [ ];
deploy.grafana.package = pkgs.emptyDirectory;
};
# A host that tries to move the socket directory; reading the option throws.
@ -120,7 +120,7 @@ let
ok =
!(builtins.tryEval grafanaSocketDirSet.services.hyperhive.deploy.grafana.socketDir).success
&&
grafanaOldPath.services.nginx.virtualHosts.${grafanaOldPath.services.hyperhive.swarm.grafana.domain}.locations."= /metrics".proxyPass
grafanaHere.services.nginx.virtualHosts.${grafanaHere.services.hyperhive.swarm.grafana.domain}.locations."= /metrics".proxyPass
== "http://unix:/run/swarm-grafana/grafana.sock:/metrics";
}
{
@ -132,8 +132,8 @@ let
name = "grafana's published vhost serves /metrics only behind the collector's auth subrequest";
ok =
let
g = grafanaOldPath.services.hyperhive.swarm.grafana;
locs = grafanaOldPath.services.nginx.virtualHosts.${g.domain}.locations;
g = grafanaHere.services.hyperhive.swarm.grafana;
locs = grafanaHere.services.nginx.virtualHosts.${g.domain}.locations;
checksOf = l: lib.filter (lib.hasPrefix "auth_request") (lib.splitString "\n" l.extraConfig);
authz = locs."= /__grafana_metrics_authz";
in
@ -143,7 +143,7 @@ let
&& !(lib.hasInfix "error_page" locs."= /metrics".extraConfig)
&& authz.proxyPass == "https://auth.t.local/api/authz/auth-request"
&& lib.hasInfix "internal;" authz.extraConfig
&& !(grafanaOldPath.services.nginx.virtualHosts ? "grafana-metrics")
&& !(grafanaHere.services.nginx.virtualHosts ? "grafana-metrics")
&& lib.hasPrefix "http://unix:" locs."/".proxyPass;
}
{
@ -152,8 +152,7 @@ let
# this host". Its vhost is on the public gateway, so a password box there
# is a way in whatever the topology.
name = "grafana disables its local login form even where authelia is not on this host";
ok =
grafanaOldPath.containers.swarm-grafana.config.services.grafana.settings.auth.disable_login_form;
ok = grafanaHere.containers.swarm-grafana.config.services.grafana.settings.auth.disable_login_form;
}
{
# The absence class this whole file is for, and the reported defect in one
@ -445,7 +444,7 @@ let
ok =
let
sources =
grafanaOldPath.containers.swarm-grafana.config.services.grafana.provision.datasources.settings.datasources;
grafanaHere.containers.swarm-grafana.config.services.grafana.provision.datasources.settings.datasources;
logs = lib.head (lib.filter (d: d.uid == "swarm-victorialogs") sources);
rules = logs.jsonData.logLevelRules or [ ];
# `overwrite_text` makes the stored text the OpenTelemetry short name
@ -473,7 +472,7 @@ let
ok =
let
groups =
grafanaOldPath.containers.swarm-grafana.config.services.grafana.provision.alerting.rules.settings.groups;
grafanaHere.containers.swarm-grafana.config.services.grafana.provision.alerting.rules.settings.groups;
rules = lib.concatMap (g: g.rules) groups;
rule = lib.findFirst (r: r.uid == "hh-agent-turn-failed") null rules;
expr = (lib.head rule.data).model.expr;
@ -517,9 +516,8 @@ let
name = "grafana's vhost is rendered with the gateway's listen set, TLS and security headers";
ok =
let
gw = grafanaOldPath.services.hyperhive.gateway;
v =
grafanaOldPath.services.nginx.virtualHosts.${grafanaOldPath.services.hyperhive.swarm.grafana.domain};
gw = grafanaHere.services.hyperhive.gateway;
v = grafanaHere.services.nginx.virtualHosts.${grafanaHere.services.hyperhive.swarm.grafana.domain};
# nginx's `listen` entries come back with defaults filled in
# (`extraParameters`, `proxyProtocol`), so compare the fields set.
listenOf = map (l: {

View file

@ -103,13 +103,7 @@ let
];
}).config;
# Note `hyperhive`, not `services.hyperhive`: the agent tier's options moved
# under `services.hyperhive.agent`, and ../agent-modules/renamed-options.nix
# keeps the top-level spelling reaching them. ⚠️ That shim covers the
# options that existed when the tier moved and nothing since, so a fixture
# for an option added afterwards has to go through [`agentWith`] and name
# the real path.
agent = extra: agentWith { hyperhive = extra; };
agent = extra: agentWith { services.hyperhive.agent = extra; };
baoNames = machine: machine.services.hyperhive.gateway.localNames;

View file

@ -22,25 +22,18 @@ let
runGroup
;
# The queue's two old `swarm.nats` paths that still rename; dropping either
# shim fails the eval. No store identity, which the first case below relies on.
natsOldPath = shared.natsOldPath;
# No store identity, which the first case below relies on.
natsQueueOnly = shared.natsQueueOnly;
# Seventh split slice, plus slice 10's two authelia packages. Of slice 7's
# movers only `usersFile` has a rename entry — the other two are `readOnly`,
# 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
# that a reader pointed at the `deploy` namespace still renders the derived
# path — seven of those reads go through an alias a path-shaped grep
# cannot see.
autheliaOldPath = hive {
# The IdP and the queue on one host. A reader of authelia's host paths has to
# follow the `deploy` namespace; seven of those reads go through an alias a
# path-shaped grep cannot see.
autheliaAndNats = hive {
deploy.authelia.enable = true;
deploy.nats.enable = true;
swarm.authelia.usersFile = "/var/lib/test-authelia/users.yml";
swarm.authelia.package = pkgs.emptyDirectory;
swarm.authelia.bridgePackage = pkgs.emptyDirectory;
deploy.authelia.usersFile = "/var/lib/test-authelia/users.yml";
deploy.authelia.package = pkgs.emptyDirectory;
deploy.authelia.bridgePackage = pkgs.emptyDirectory;
# Renders the publisher, which reads the host client-secret dir.
deploy.swarm-secret-publisher.baoClientCertFile = "/etc/pki/publisher.pem";
deploy.swarm-secret-publisher.baoClientKeyFile = "/etc/pki/publisher-key.pem";
@ -297,9 +290,9 @@ let
{
name = "authelia and nats declare no scrape target on a host with no collector";
ok =
!(autheliaOldPath.services.hyperhive.deploy.swarm-otel.enable)
&& !(autheliaOldPath.services.hyperhive.swarm.otel.scrapeTargets ? authelia)
&& !(autheliaOldPath.services.hyperhive.swarm.otel.scrapeTargets ? nats);
!(autheliaAndNats.services.hyperhive.deploy.swarm-otel.enable)
&& !(autheliaAndNats.services.hyperhive.swarm.otel.scrapeTargets ? authelia)
&& !(autheliaAndNats.services.hyperhive.swarm.otel.scrapeTargets ? nats);
}
{
# The xkey and the responder's OIDC client secret are read only from
@ -308,7 +301,7 @@ let
# minted one.
name = "a queue with no responder store identity is refused at eval, one with a leaf is not";
ok =
refusedWithoutIdentity natsOldPath
refusedWithoutIdentity natsQueueOnly
&& !(refusedWithoutIdentity natsWithStoreIdentity)
&& !(refusedWithoutIdentity natsOnStoreHost);
}
@ -327,10 +320,10 @@ let
# this key would still evaluate cleanly — the only reader that would
# notice is a publisher whose row exceeds upstream's much smaller
# default, and by then it is a dropped row, not an eval failure.
# Piggybacks on the pre-rename nats fixture above, which already
# Piggybacks on the queue-only fixture above, which already
# renders this container's full config.
name = "the queue's payload ceiling is set, not inherited from the server's default";
ok = natsOldPath.containers.swarm-nats.config.services.nats.settings.max_payload == 8388608;
ok = natsQueueOnly.containers.swarm-nats.config.services.nats.settings.max_payload == 8388608;
}
{
# What keeps a callout request inside one principal: the responder is
@ -351,7 +344,7 @@ let
&& !(settings ? system_account)
)
[
natsOldPath
natsQueueOnly
natsOnStoreHost
];
}
@ -375,7 +368,7 @@ let
&& !(c.services.nats.settings.authorization.auth_callout ? xkey)
)
[
natsOldPath
natsQueueOnly
natsOnStoreHost
];
}
@ -384,7 +377,7 @@ let
# responder with it: the responder requires the server, so a server that
# failed to start left the responder inactive rather than failed.
name = "starting the queue's server starts its responder";
ok = lib.elem "nats.service" (responderOf natsOldPath).wantedBy;
ok = lib.elem "nats.service" (responderOf natsQueueOnly).wantedBy;
}
{
# The keys are created before anything needs them, by the responder's
@ -480,7 +473,7 @@ let
ok =
let
exec =
natsOldPath.containers.swarm-nats.config.systemd.services.swarm-nats-auth.serviceConfig.ExecStart;
natsQueueOnly.containers.swarm-nats.config.systemd.services.swarm-nats-auth.serviceConfig.ExecStart;
in
!(lib.hasInfix "--agent-publish-subject " exec);
}
@ -491,7 +484,7 @@ let
name = "the responder grants a verified agent its own hive-free subjects";
ok =
let
exec = (responderOf natsOldPath).serviceConfig.ExecStart;
exec = (responderOf natsQueueOnly).serviceConfig.ExecStart;
in
lib.hasInfix "--agent-token-publish-subject '$$SWARM.term.{agent}'" exec
&& lib.hasInfix "--agent-token-publish-subject '$$SWARM.agent-state.{agent}'" exec
@ -503,7 +496,7 @@ let
name = "the responder grants a verified agent its own icon key";
ok =
let
exec = (responderOf natsOldPath).serviceConfig.ExecStart;
exec = (responderOf natsQueueOnly).serviceConfig.ExecStart;
in
lib.hasInfix "--agent-token-publish-subject '$$KV.agent-icons.{agent}'" exec;
}
@ -514,7 +507,7 @@ let
name = "a verified agent's grant is exactly its own subjects, and its JetStream API subjects read its own schedule, inference and permissions keys";
ok =
let
args = lib.splitString " " (responderOf natsOldPath).serviceConfig.ExecStart;
args = lib.splitString " " (responderOf natsQueueOnly).serviceConfig.ExecStart;
granted = lib.concatLists (
lib.imap0 (
i: a:
@ -685,7 +678,7 @@ let
# through an `autheliaCfg` alias, where a path-shaped grep does not see it.
name = "a consumer of authelia's host client-secret dir renders it from the deploy namespace";
ok =
autheliaOldPath.systemd.paths.swarm-secret-publish.pathConfig.PathChanged
autheliaAndNats.systemd.paths.swarm-secret-publish.pathConfig.PathChanged
== "/var/lib/nixos-containers/swarm-authelia/var/lib/authelia-swarm/oidc-clients";
}
{

View file

@ -55,11 +55,10 @@ in
# shape that hives elsewhere join.
swarmServicesWithController = hiveWithController { deploy.allSwarmServices = true; };
# The queue's two old `swarm.nats` paths that still rename, `enable` and
# `authPackage`, with no store identity.
natsOldPath = hive {
swarm.nats.enable = true;
swarm.nats.authPackage = pkgs.emptyDirectory;
# The queue with no store identity.
natsQueueOnly = hive {
deploy.nats.enable = true;
deploy.nats.authPackage = pkgs.emptyDirectory;
};
controllerAlone = hive { deploy.swarm-controller.enable = true; };

View file

@ -61,11 +61,6 @@ let
# authelia somewhere else, the credential delivered by hand. Whether this
# collector authenticates must follow the credential, never another
# service's placement.
#
# The `swarm.otel.clientSecretFile` below is the PRE-RENAME path. It predates
# the split and is deliberately left spelled that way: it makes this fixture
# the old-path case for that option too, so dropping its rename entry fails
# the eval here rather than only in a real operator's config.
otelRemoteAuthelia = hive {
deploy.swarm-otel.enable = true;
deploy.authelia.enable = false;
@ -74,7 +69,7 @@ let
# `token_url`, so a hive with a secret and no URL has a credential it can
# present nowhere.
swarm.authelia.url = "https://auth.example.invalid";
swarm.otel.clientSecretFile = "/var/lib/swarm-otel-oidc/by-hand.secret";
deploy.swarm-otel.clientSecretFile = "/var/lib/swarm-otel-oidc/by-hand.secret";
};
# A collector whose ONLY scrape work is published: loopback targets forced
@ -148,10 +143,8 @@ let
{
# The collector's half of the same split, and a different arm from the
# authenticator case below: this one reads the PATH the unit loads, so a
# reader left on a source that is non-null but wrong still fails. The
# fixture spells the option its pre-rename way, so it covers the rename
# entry at the same time.
name = "a config written against the pre-rename otel secret path still loads it as a credential";
# reader left on a source that is non-null but wrong still fails.
name = "a by-hand otel secret path is the one the collector loads as a credential";
ok =
lib.any (c: lib.hasInfix "/var/lib/swarm-otel-oidc/by-hand.secret" c)
otelRemoteAuthelia.containers.swarm-otel.config.systemd.services.opentelemetry-collector.serviceConfig.LoadCredential;

View file

@ -124,7 +124,7 @@ let
deploy.forgejo.enable = true;
deploy.forgejo.mirrors = [ aMirror ];
deploy.forgejo.actionsFromSelf = false;
c0re.orgAvatarPng = "/etc/marker-avatar.png";
deploy.swarm-controller.configOrgAvatarPng = "/etc/marker-avatar.png";
};
mirrorsNoController = hive {
deploy.forgejo.enable = true;
@ -796,7 +796,7 @@ let
&& lib.elem "actions/checkout" (map (m: m.dest) (mirrorsOf forgeWithController));
}
{
name = "the old c0re org-avatar option lands on the controller's unit";
name = "the org avatar lands on the controller's unit, not hive-c0re's";
ok =
controllerWithMirrors.systemd.services.swarm-controller.environment.SWARM_CONTROLLER_CONFIG_ORG_AVATAR_PNG
== "/etc/marker-avatar.png"