feat(#1763): local-file half of btrfs send/receive migration transport

SendAgentSnapshotToFile priv op: btrfs send [-p <parent>] <snapshot> to a
file under MIGRATE_STAGING_ROOT. Standalone-useful as a point-in-time
snapshot export/backup today; the cross-hive ssh-piped leg (auth/trust
design posted on #1763, awaiting mara/damocles steer) is a later,
separate piece this doesn't block on.

- hive-sh4re: PrivRequest::SendAgentSnapshotToFile + MIGRATE_STAGING_ROOT
- hive-priv: validates names, refuses to overwrite an existing export,
  cleans up a partial file on btrfs send failure
- hive-c0re: priv_client::send_agent_snapshot_to_file
- hivectl: `hivectl subvol snapshot send <agent> <label> [--parent <label>] --dest <file>`
This commit is contained in:
atlas 2026-07-14 19:09:44 +02:00 committed by mara
commit 90af0edab0
4 changed files with 201 additions and 2 deletions

View file

@ -474,6 +474,32 @@ pub async fn delete_agent_snapshot(agent_name: &str, snapshot_name: &str) -> Res
.await?)
}
/// Stream a read-only agent snapshot to a local file via `btrfs send`
/// (optionally incremental against `parent_snapshot_name`). Returns the
/// full path of the written file under `MIGRATE_STAGING_ROOT`. Via
/// hive-priv as root. See [`PrivRequest::SendAgentSnapshotToFile`].
///
/// # Errors
/// Returns an error if the hive-priv call fails, the snapshot (or parent)
/// doesn't exist, or the destination file already exists.
pub async fn send_agent_snapshot_to_file(
agent_name: &str,
snapshot_name: &str,
parent_snapshot_name: Option<&str>,
dest_file_name: &str,
) -> Result<String> {
let (stdout, _) = check(
call(&PrivRequest::SendAgentSnapshotToFile {
agent_name: agent_name.to_owned(),
snapshot_name: snapshot_name.to_owned(),
parent_snapshot_name: parent_snapshot_name.map(str::to_owned),
dest_file_name: dest_file_name.to_owned(),
})
.await?,
)?;
Ok(stdout)
}
/// Write `/etc/tmpfiles.d/hyperhive-agents.conf` for `agents` (logical names,
/// e.g. `"atlas"`) and immediately apply it with `systemd-tmpfiles --create`.
/// See [`PrivRequest::SyncAgentTmpfiles`] for the full semantics.