feat(#2862): push a snapshot to a peer hive's store over the mesh
Adds the caller the fd-passing machinery existed for: hivectl agent <name> subvol snapshot push --peer <hive> resolves the peer, connects to its snapshot store, writes the agent header, and hands the connected socket to hive-priv, which runs btrfs send straight into it. The split keeps the root helper ignorant. Everything that involves knowing where a peer is, what the wire protocol looks like, and which hive to trust happens in the unprivileged daemon; hive-priv only ever receives an already-open descriptor. Once btrfs send starts, neither process is in the data path, so a multi-gigabyte transfer costs no per-byte work and survives a hive-c0re restart. call_with_fd takes the descriptor by value and closes it as soon as the kernel has it. A socket stays open until every copy closes, so holding one back would leave the receiver waiting for an EOF that never comes: btrfs receive blocks and this side reports success for a transfer the peer never committed. Ownership makes that unrepresentable. The peer's store port is a new swarm.peers.<domain>.snapshotStorePort option rather than a constant matching the module default. A pushing hive cannot read the receiver's configuration, so assuming 51821 would push at a port nobody promised to listen on; absent, the push fails naming the option. swarm_peers parses the mesh address the host module has always rendered into HYPERHIVE_PEERS but nothing read.
This commit is contained in:
parent
51f352f0ca
commit
282bbc3709
10 changed files with 546 additions and 9 deletions
|
|
@ -264,6 +264,12 @@ async fn dispatch(req: &HostRequest, coord: Arc<Coordinator>) -> HostResponse {
|
|||
parent,
|
||||
dest,
|
||||
} => handle_send_snapshot(name.as_str(), label, parent.as_deref(), dest).await?,
|
||||
HostRequest::PushSnapshot {
|
||||
name,
|
||||
label,
|
||||
parent,
|
||||
peer,
|
||||
} => handle_push_snapshot(name.as_str(), label, parent.as_deref(), peer).await?,
|
||||
})
|
||||
}
|
||||
.await;
|
||||
|
|
@ -661,6 +667,21 @@ async fn handle_send_snapshot(
|
|||
Ok(HostResponse::messages(vec![path]))
|
||||
}
|
||||
|
||||
/// Push a snapshot to a peer hive's store. The network sibling of
|
||||
/// [`handle_send_snapshot`]: nothing lands on this host, so success is
|
||||
/// bare rather than a path.
|
||||
async fn handle_push_snapshot(
|
||||
name: &str,
|
||||
label: &str,
|
||||
parent: Option<&str>,
|
||||
peer: &str,
|
||||
) -> Result<HostResponse> {
|
||||
crate::snapshot_push::push_agent_snapshot(name, label, parent, peer)
|
||||
.await
|
||||
.with_context(|| format!("push {name} snapshot (label {label:?}) to peer {peer:?}"))?;
|
||||
Ok(HostResponse::success())
|
||||
}
|
||||
|
||||
async fn handle_matrix_sync_admin() -> Result<HostResponse> {
|
||||
require_matrix_present().await?;
|
||||
let register_token =
|
||||
|
|
|
|||
Loading…
Reference in a new issue