refactor(#2862): one snapshot store per swarm, not one per peer

The push side modelled a store per peer hive: a --peer argument, a
swarm.peers.<domain>.snapshotStorePort option, and a swarm_peers module
whose entire job was answering "which peer". A swarm has exactly one
store, so none of that had anything to select between.

The receiver already proved it. It keys destination directories by
agent, not by sending hive, precisely so an agent that migrates keeps
one unbroken incremental chain -- which only makes sense if every hive
pushes to the same place. Per-hive stores would split the chain in two,
the case that keying exists to prevent.

So the destination moves to services.hyperhive.swarm.snapshotStore,
rendered into HYPERHIVE_SNAPSHOT_STORE, and swarm_peers is deleted
rather than adapted. address has no default because it is a
deployment fact this host cannot derive; port defaults because it is a
convention both ends read from the same option docs. An unset or empty
address fails naming the option instead of connecting somewhere
arbitrary, and a test asserts the message suggests no value.
This commit is contained in:
atlas 2026-07-31 22:00:59 +02:00 committed by mara
commit ba71e45486
9 changed files with 171 additions and 279 deletions

View file

@ -375,22 +375,22 @@ pub enum HostRequest {
parent: Option<String>,
dest: String,
},
/// Push a snapshot to a peer hive's snapshot store over the
/// WireGuard mesh (`hivectl agent <name> subvol snapshot push`).
/// The network sibling of [`HostRequest::SendSnapshot`]: same
/// snapshot and optional incremental `parent`, but the stream goes
/// to `peer`'s receiver instead of a local file.
/// Push a snapshot to the swarm's snapshot store over the WireGuard
/// mesh (`hivectl agent <name> subvol snapshot push`). The network
/// sibling of [`HostRequest::SendSnapshot`]: same snapshot and
/// optional incremental `parent`, but the stream goes to the store's
/// receiver instead of a local file.
///
/// `peer` is a domain from `services.hyperhive.swarm.peers`; the
/// daemon resolves its mesh address and store port from there and
/// fails if the peer declares neither. Bare success — nothing is
/// written on this host to report a path for.
/// There is no destination field: a swarm has exactly one store, and
/// the daemon reads its address from
/// `services.hyperhive.swarm.snapshotStore`, failing if none is
/// configured. Bare success — nothing is written on this host to
/// report a path for.
PushSnapshot {
name: Ident,
label: String,
#[serde(default)]
parent: Option<String>,
peer: String,
},
}