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:
parent
258c0998ab
commit
ba71e45486
9 changed files with 171 additions and 279 deletions
|
|
@ -638,14 +638,17 @@ pub enum SnapshotCmd {
|
|||
#[arg(long)]
|
||||
dest: String,
|
||||
},
|
||||
/// Stream a snapshot to a peer hive's snapshot store over the
|
||||
/// Stream a snapshot to the swarm's snapshot store over the
|
||||
/// WireGuard mesh — the network half of the migration transport.
|
||||
///
|
||||
/// Nothing is staged locally: `btrfs send` writes straight into the
|
||||
/// connection, so a multi-gigabyte agent needs no scratch space on
|
||||
/// this host. The mesh is the authentication (cryptokey routing
|
||||
/// binds the peer's address to its key), so there is no credential
|
||||
/// binds the sender's address to its key), so there is no credential
|
||||
/// to pass here.
|
||||
///
|
||||
/// There is no destination argument: a swarm has one store, read
|
||||
/// from `services.hyperhive.swarm.snapshotStore`.
|
||||
Push {
|
||||
/// Snapshot label passed to `subvol snapshot create --label`.
|
||||
label: String,
|
||||
|
|
@ -655,10 +658,5 @@ pub enum SnapshotCmd {
|
|||
/// Omit for a full send.
|
||||
#[arg(long)]
|
||||
parent: Option<String>,
|
||||
/// Peer hive domain, as declared in
|
||||
/// `services.hyperhive.swarm.peers`. Its mesh address and
|
||||
/// snapshot-store port are read from there.
|
||||
#[arg(long)]
|
||||
peer: String,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,11 +44,9 @@ pub(crate) async fn dispatch_subvol(socket: &Path, name: &str, cmd: SubvolCmd) -
|
|||
parent,
|
||||
dest,
|
||||
} => subvol_snapshot_send(socket, name, &label, parent.as_deref(), &dest).await,
|
||||
SnapshotCmd::Push {
|
||||
label,
|
||||
parent,
|
||||
peer,
|
||||
} => subvol_snapshot_push(socket, name, &label, parent.as_deref(), &peer).await,
|
||||
SnapshotCmd::Push { label, parent } => {
|
||||
subvol_snapshot_push(socket, name, &label, parent.as_deref()).await
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -223,18 +221,18 @@ async fn subvol_snapshot_send(
|
|||
.await
|
||||
}
|
||||
|
||||
/// `subvol snapshot push <agent> <label> [--parent <label>] --peer <hive>`
|
||||
/// — stream a snapshot to a peer hive's snapshot store over the mesh.
|
||||
/// `subvol snapshot push <agent> <label> [--parent <label>]` — stream a
|
||||
/// snapshot to the swarm's snapshot store over the mesh.
|
||||
///
|
||||
/// The network sibling of `send`. Nothing is staged on this host, so
|
||||
/// there is no path to print: success is silent apart from the
|
||||
/// confirmation below.
|
||||
/// confirmation below. No destination argument — a swarm has one store,
|
||||
/// and the daemon reads its address from the host config.
|
||||
async fn subvol_snapshot_push(
|
||||
socket: &Path,
|
||||
name: &str,
|
||||
label: &str,
|
||||
parent: Option<&str>,
|
||||
peer: &str,
|
||||
) -> Result<()> {
|
||||
daemon_request(
|
||||
socket,
|
||||
|
|
@ -242,14 +240,17 @@ async fn subvol_snapshot_push(
|
|||
name: crate::util::parse_ident(name)?,
|
||||
label: label.to_owned(),
|
||||
parent: parent.map(str::to_owned),
|
||||
peer: peer.to_owned(),
|
||||
},
|
||||
"snapshot push",
|
||||
)
|
||||
.await?;
|
||||
match parent {
|
||||
Some(p) => println!("pushed {name} snapshot {label:?} (incremental from {p:?}) to {peer}"),
|
||||
None => println!("pushed {name} snapshot {label:?} (full) to {peer}"),
|
||||
Some(p) => {
|
||||
println!(
|
||||
"pushed {name} snapshot {label:?} (incremental from {p:?}) to the swarm store"
|
||||
);
|
||||
}
|
||||
None => println!("pushed {name} snapshot {label:?} (full) to the swarm store"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue