Watch
0
0
Fork
You've already forked hyperhive
0

remove the old snapshot store; tombstone its options

This commit is contained in:
atlas 2026-11-09 23:13:18 +01:00 • committed by mara
commit 20d286f06a
2 changed files with 97 additions and 1308 deletions

View file

@ -2049,6 +2049,43 @@ let
})
&& !(refused allLocal);
}
{
# One host defining all five removed paths. Each message names its own
# path (`services.hyperhive.swarm.snapshotStore.port` does not contain
# `services.hyperhive.snapshotStore.port`), so each lookup finds only
# its option. The control is a host that defines none.
name = "a definition of a removed snapshot store option fails evaluation, naming the option and swarm-archive";
ok =
let
paths = [
"swarm.snapshotStore.address"
"swarm.snapshotStore.port"
"snapshotStore.enable"
"snapshotStore.path"
"snapshotStore.port"
];
refused =
m: path:
lib.any (
a:
!a.assertion
&& lib.hasInfix "services.hyperhive.${path}" a.message
&& lib.hasInfix "agent-state backups are being rebuilt as swarm-archive" a.message
) m.assertions;
old = hive {
swarm.snapshotStore = {
address = "10.100.0.1";
port = 51821;
};
snapshotStore = {
enable = true;
path = "/var/lib/hyperhive-snapshots";
port = 51821;
};
};
in
lib.all (path: refused old path) paths && !(lib.any (path: refused bare path) paths);
}
{
# Refused wherever any hyperhive service runs, the hive or a swarm
# service alone. The host enabling nothing is the control that it is

View file

@ -1,102 +0,0 @@
# `checks.module-eval-snapshot-store` — see ./lib.nix for the shared
# rationale (why this suite exists, naming convention, "evaluates not
# executes").
#
# The snapshot store's receiver socket: where it listens, that it can bind
# before the mesh interface is up, that it refuses a wildcard, and that a
# silent or stalled transfer is bounded.
{
pkgs,
lib,
self,
nixosSystem,
}:
let
inherit
(import ./lib.nix {
inherit
pkgs
lib
self
nixosSystem
;
})
hive
runGroup
;
# Bare hive: the store and the mesh it needs, nothing else.
store = hive {
deploy.wireguard.enable = true;
deploy.wireguard.address = "10.100.0.1/24";
snapshotStore.enable = true;
snapshotStore.port = 51822;
};
# The same with a wildcard where the mesh address goes.
storeOnWildcard = hive {
deploy.wireguard.enable = true;
deploy.wireguard.address = "0.0.0.0/24";
snapshotStore.enable = true;
};
# The IPv6 wildcard.
storeOnWildcardV6 = hive {
deploy.wireguard.enable = true;
deploy.wireguard.address = "::/64";
snapshotStore.enable = true;
};
unit = store.systemd.services."swarm-snapshot-store@";
moduleSource = builtins.readFile ../host-modules/swarm-snapshot-store.nix;
socket = store.systemd.sockets.swarm-snapshot-store.socketConfig;
refusedAsWildcard =
m:
lib.any (
a: !a.assertion && lib.hasInfix "refuses a wildcard listen address" a.message
) m.assertions;
cases = [
{
# The wg-hive address does not exist when sockets.target binds, so
# without FreeBind the bind fails with EADDRNOTAVAIL and the receiver
# never listens. The unit still renders and evaluates either way, which
# is why only a rendered-config check can see it.
name = "the receiver socket may bind before the mesh interface has its address";
ok = socket.FreeBind or false == true;
}
{
# The bare IP and the configured port: the prefix length on
# `deploy.wireguard.address` must not leak into the listen address.
name = "the receiver socket listens on the mesh address and the configured port";
ok = socket.ListenStream == "10.100.0.1:51822";
}
{
# The control for the case below: it is the wildcard that trips the
# assertion, not the store being on.
name = "a mesh address on the store raises no wildcard refusal";
ok = !(refusedAsWildcard store);
}
{
# A wildcard bind is an unauthenticated remote write into agent state.
name = "a wildcard mesh address, IPv4 or IPv6, is refused";
ok = refusedAsWildcard storeOnWildcard && refusedAsWildcard storeOnWildcardV6;
}
{
# Without it a stalled `btrfs receive` holds a root instance forever.
name = "the receiver unit has a runtime ceiling";
ok = unit.serviceConfig.RuntimeMaxSec or null == "6h";
}
{
# The script is a store path, so its text is not evaluable without
# building it; the module source is the nearest thing to read. A
# silent peer must not hold the root instance past the header read.
name = "the receiver script bounds its header read";
ok = lib.hasInfix "read -r -t \${toString headerTimeoutSeconds} keyword agent" moduleSource;
}
];
in
runGroup "snapshot-store" cases