split hivectl main.rs into per-domain modules (#2509)
This commit is contained in:
parent
673aea4e50
commit
fc7720572b
16 changed files with 1922 additions and 1771 deletions
591
hivectl/src/cli.rs
Normal file
591
hivectl/src/cli.rs
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
//! hivectl clap command tree: the `Cli` root, the top-level `Cmd`
|
||||
//! verb enum, and every subcommand enum + shared args struct.
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(
|
||||
name = "hivectl",
|
||||
about = "hyperhive host CLI — operator-facing administration",
|
||||
long_about = "\
|
||||
Sibling to the `hive-c0re` daemon binary. Covers host-side admin \
|
||||
operations that don't go through the broker — manual user \
|
||||
provisioning on the bundled forge + matrix containers, plus future \
|
||||
recovery / debugging verbs.\
|
||||
"
|
||||
)]
|
||||
pub struct Cli {
|
||||
/// Path to the hive-c0re host admin socket, used by the daemon-assisted
|
||||
/// verbs (`agents`, `stop`, `start`). Global: accepted before or after
|
||||
/// the subcommand. Verbs that don't talk to the daemon ignore it.
|
||||
#[arg(long, global = true, default_value = DEFAULT_HOST_SOCKET)]
|
||||
pub(crate) socket: PathBuf,
|
||||
#[command(subcommand)]
|
||||
pub(crate) cmd: Cmd,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Cmd {
|
||||
/// Forgejo user provisioning.
|
||||
///
|
||||
/// Manual entry point to the same idempotent provisioning c0re runs at
|
||||
/// boot — for recovery, ad-hoc reprovisioning, or fixing one agent
|
||||
/// without bouncing the daemon.
|
||||
Forge {
|
||||
#[command(subcommand)]
|
||||
cmd: ForgeCmd,
|
||||
},
|
||||
/// matrix-tuwunel user provisioning.
|
||||
///
|
||||
/// Manual entry point to the same idempotent provisioning c0re runs at
|
||||
/// boot — for re-registering an agent the boot sweep skipped, or after
|
||||
/// wiping a token file.
|
||||
Matrix {
|
||||
#[command(subcommand)]
|
||||
cmd: MatrixCmd,
|
||||
},
|
||||
/// GitHub account provisioning.
|
||||
///
|
||||
/// Store an operator-supplied personal access token (PAT) for an agent
|
||||
/// so its `gh` and git can authenticate. No account is created — the
|
||||
/// PAT is for an existing GitHub account.
|
||||
Github {
|
||||
#[command(subcommand)]
|
||||
cmd: GithubCmd,
|
||||
},
|
||||
/// Gateway htpasswd user management.
|
||||
///
|
||||
/// Add, remove, or list users for the gateway's HTTP Basic auth.
|
||||
Gateway {
|
||||
#[command(subcommand)]
|
||||
cmd: GatewayCmd,
|
||||
},
|
||||
/// Agent container management.
|
||||
///
|
||||
/// Lifecycle actions on managed agent containers. Needs the hive-c0re
|
||||
/// daemon running.
|
||||
Agents {
|
||||
#[command(subcommand)]
|
||||
cmd: AgentsCmd,
|
||||
},
|
||||
/// Operator approval queue: list, approve, or deny pending requests.
|
||||
///
|
||||
/// Needs the hive-c0re daemon running.
|
||||
Approvals {
|
||||
#[command(subcommand)]
|
||||
cmd: ApprovalsCmd,
|
||||
},
|
||||
/// WireGuard inter-hive mesh setup helpers.
|
||||
///
|
||||
/// Generate this hive's mesh key and print the nix to enable the mesh,
|
||||
/// add a peer, or inspect live interface state.
|
||||
Wg {
|
||||
#[command(subcommand)]
|
||||
cmd: WgCmd,
|
||||
},
|
||||
/// Generate the federation peer-config block for THIS hive.
|
||||
///
|
||||
/// Prints the nix a peer operator pastes into their swarm config to
|
||||
/// trust and reach this hive.
|
||||
PeerConfig {
|
||||
/// This hive's WireGuard mesh address (e.g. `10.42.0.1/32`),
|
||||
/// emitted as `wireguardAddress`. Omit when not running the mesh.
|
||||
#[arg(long)]
|
||||
wg_address: Option<String>,
|
||||
/// This hive's public WireGuard endpoint (`host:port`), emitted as
|
||||
/// `wireguardEndpoint`. Omit when peers dial in / no mesh.
|
||||
#[arg(long)]
|
||||
wg_endpoint: Option<String>,
|
||||
},
|
||||
/// Open an interactive Claude session inside an agent container.
|
||||
///
|
||||
/// A fresh session by default, or resume a prior one. Requires root
|
||||
/// and a running container.
|
||||
Choom {
|
||||
/// Agent name (e.g. `damocles`, `iris`).
|
||||
name: String,
|
||||
/// Resume a prior claude session by its session id, passed
|
||||
/// through as `claude --resume <value>` (claude's `--continue`
|
||||
/// takes no value — it resumes the cwd's latest session, which
|
||||
/// is the harness's, so choom never uses it; this flag matches
|
||||
/// the claude flag it maps to). Omit for a fresh blank session.
|
||||
/// A value is required when the flag is given.
|
||||
#[arg(long = "resume", value_name = "SESSION")]
|
||||
resume_session: Option<String>,
|
||||
},
|
||||
/// Stop containers hive-wide in one operator action.
|
||||
///
|
||||
/// Bare `hivectl stop` stops everything; scope flags narrow it to
|
||||
/// specific sub-agents or infra containers.
|
||||
Stop {
|
||||
#[command(flatten)]
|
||||
scope: ScopeArgs,
|
||||
/// Gracefully quiesce each agent before stopping, instead of a
|
||||
/// hard stop. Each agent gets a graceful-stop DAG on the job
|
||||
/// queue: the harness is signalled, runs one stop-checkpoint
|
||||
/// turn to flush durable `/state`, drains, then the container
|
||||
/// is stopped (bounded by a 3-min timeout that falls back to a
|
||||
/// hard stop). All drains overlap. Applies to agents only.
|
||||
#[arg(long)]
|
||||
graceful: bool,
|
||||
/// Return immediately after the stop DAGs are queued instead of
|
||||
/// waiting for them with live per-node progress.
|
||||
#[arg(long)]
|
||||
no_wait: bool,
|
||||
},
|
||||
/// Start containers hive-wide — the inverse of `hivectl stop`.
|
||||
///
|
||||
/// Bare `hivectl start` restores the agents stopped by the last
|
||||
/// broad-scope `stop` (or starts everything if none); scope flags
|
||||
/// narrow it.
|
||||
Start {
|
||||
#[command(flatten)]
|
||||
scope: ScopeArgs,
|
||||
/// Return immediately after the start DAGs are queued instead
|
||||
/// of waiting for them with live per-node progress.
|
||||
#[arg(long)]
|
||||
no_wait: bool,
|
||||
},
|
||||
/// Restart containers hive-wide — `stop` then `start` over one scope.
|
||||
///
|
||||
/// Bare `hivectl restart` restarts everything; scope flags narrow it.
|
||||
Restart {
|
||||
#[command(flatten)]
|
||||
scope: ScopeArgs,
|
||||
/// Gracefully quiesce each agent on the stop half (see
|
||||
/// `stop --graceful`). Applies to agents only.
|
||||
#[arg(long)]
|
||||
graceful: bool,
|
||||
},
|
||||
/// Per-agent disk accounting + optional quotas via btrfs qgroups.
|
||||
///
|
||||
/// Opt-in: enable qgroup accounting, then report per-agent usage or
|
||||
/// cap an agent. No-op on non-btrfs hosts.
|
||||
Quota {
|
||||
#[command(subcommand)]
|
||||
cmd: QuotaCmd,
|
||||
},
|
||||
/// btrfs subvolume management for agent state dirs.
|
||||
///
|
||||
/// Upgrade an existing plain-dir agent's state into a btrfs subvolume
|
||||
/// so it gains snapshots and per-subvol usage/quota.
|
||||
Subvol {
|
||||
#[command(subcommand)]
|
||||
cmd: SubvolCmd,
|
||||
},
|
||||
/// Print (and best-effort open in a browser) a hive web surface URL.
|
||||
///
|
||||
/// Resolves the URL from the running daemon so custom forge / matrix
|
||||
/// domains work. Bare `hivectl open` opens the operator dashboard.
|
||||
Open {
|
||||
/// Which surface to open. Defaults to the operator dashboard.
|
||||
#[arg(value_enum, default_value_t = OpenTarget::Home)]
|
||||
target: OpenTarget,
|
||||
},
|
||||
/// Emit the full CLI reference as `CommonMark` to stdout.
|
||||
///
|
||||
/// Hidden tooling command used by the docs build to keep the published
|
||||
/// `hivectl` reference in lockstep with the code.
|
||||
#[command(hide = true)]
|
||||
MarkdownDocs,
|
||||
/// Generate a shell completion script for `hivectl` and print it to
|
||||
/// stdout.
|
||||
///
|
||||
/// Supports bash, zsh, fish, elvish, and powershell. The NixOS module
|
||||
/// already installs the zsh script system-wide; this is for ad-hoc or
|
||||
/// other-shell use.
|
||||
Completions {
|
||||
/// Shell to emit completions for.
|
||||
shell: clap_complete::Shell,
|
||||
},
|
||||
}
|
||||
|
||||
/// Which hive web surface `hivectl open` targets.
|
||||
#[derive(Copy, Clone, Debug, clap::ValueEnum)]
|
||||
pub enum OpenTarget {
|
||||
/// The operator dashboard (`https://<domain>/`).
|
||||
Home,
|
||||
/// The forge (Forgejo) web UI.
|
||||
Forge,
|
||||
/// The matrix GUI (fluffychat).
|
||||
Matrix,
|
||||
}
|
||||
|
||||
/// Shared scope flags for `hivectl stop` / `hivectl start`. With no flag
|
||||
/// set the verb targets **everything** (all sub-agents + every controllable
|
||||
/// infra container). Setting any flag restricts to the selected classes,
|
||||
/// additively.
|
||||
// One bool per selectable container class, each mapping 1:1 to a clap flag;
|
||||
// orthogonal toggles, not a state machine — hence the bools allow (mirrors
|
||||
// `hive_host_sock::LifecycleScope`).
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Args)]
|
||||
pub struct ScopeArgs {
|
||||
/// All sub-agent containers.
|
||||
#[arg(long)]
|
||||
agents: bool,
|
||||
/// A specific sub-agent by name. Repeatable: `--agent a --agent b`.
|
||||
#[arg(long = "agent", value_name = "NAME")]
|
||||
agent: Vec<String>,
|
||||
/// The CI runner container (`hive-ci`).
|
||||
#[arg(long)]
|
||||
ci: bool,
|
||||
/// The forge container (`hive-forge`).
|
||||
#[arg(long)]
|
||||
forge: bool,
|
||||
/// The gateway container (`hive-gateway`).
|
||||
#[arg(long)]
|
||||
gateway: bool,
|
||||
/// The matrix container (`hive-matrix`).
|
||||
#[arg(long)]
|
||||
matrix: bool,
|
||||
}
|
||||
|
||||
impl ScopeArgs {
|
||||
pub(crate) fn to_scope(&self) -> hive_host_sock::LifecycleScope {
|
||||
hive_host_sock::LifecycleScope {
|
||||
agents: self.agents,
|
||||
agent_names: self.agent.clone(),
|
||||
ci: self.ci,
|
||||
forge: self.forge,
|
||||
gateway: self.gateway,
|
||||
matrix: self.matrix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum ForgeCmd {
|
||||
/// Create or refresh the Forgejo account + token for `<name>`.
|
||||
///
|
||||
/// For an existing agent, persists the token to its state dir; for a
|
||||
/// human/other account, prints the token to stdout. Set a password to
|
||||
/// enable forge web-UI login (a random throwaway is used otherwise).
|
||||
CreateUser {
|
||||
/// Forgejo username. For agents: the container/agent name
|
||||
/// (`<n>` in `h-<n>`; manager uses the literal `manager`).
|
||||
/// For humans: any forgejo username — `mara`, `damocles`, etc.
|
||||
name: String,
|
||||
/// Set the account password to this string instead of a random
|
||||
/// throwaway. Use this for operator accounts that need to log
|
||||
/// into the forge web UI. Mutually exclusive with
|
||||
/// `--password-stdin`. WARNING: the password is visible in
|
||||
/// shell history + process listings; prefer `--password-stdin`
|
||||
/// for anything sensitive.
|
||||
#[arg(long)]
|
||||
password: Option<String>,
|
||||
/// Read the password from stdin (single line, trailing newline
|
||||
/// stripped) instead of an inline flag. Mutually exclusive with
|
||||
/// `--password`.
|
||||
#[arg(long, conflicts_with = "password")]
|
||||
password_stdin: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum MatrixCmd {
|
||||
/// Create or refresh the matrix account + access token for `<name>`.
|
||||
///
|
||||
/// For an existing agent, persists the token to its state dir; for a
|
||||
/// human/other account, prints the access token to stdout. Set a
|
||||
/// password to enable matrix web-client login (a random throwaway is
|
||||
/// used otherwise).
|
||||
CreateUser {
|
||||
/// Matrix localpart. For agents: the container/agent name.
|
||||
/// For humans: any matrix localpart — `mara`, `damocles`, etc.
|
||||
name: String,
|
||||
/// Set the account password to this string instead of a random
|
||||
/// throwaway. Use this for operator accounts that need to log
|
||||
/// into matrix web clients via `m.login.password`. Mutually
|
||||
/// exclusive with `--password-stdin`. WARNING: the
|
||||
/// password is visible in shell history + process listings;
|
||||
/// prefer `--password-stdin` for anything sensitive.
|
||||
#[arg(long)]
|
||||
password: Option<String>,
|
||||
/// Read the password from stdin (single line, trailing newline
|
||||
/// stripped) instead of an inline flag. Mutually exclusive with
|
||||
/// `--password`.
|
||||
#[arg(long, conflicts_with = "password")]
|
||||
password_stdin: bool,
|
||||
},
|
||||
/// Provision (or re-provision) the hive system admin matrix account.
|
||||
///
|
||||
/// Runs automatically on startup; run manually to recover a missing
|
||||
/// admin token.
|
||||
SyncAdmin,
|
||||
/// Promote a matrix user to homeserver admin.
|
||||
PromoteUser {
|
||||
/// Matrix localpart of the user to promote (e.g. `argus`).
|
||||
name: String,
|
||||
},
|
||||
/// Reset a matrix user's password via the admin API.
|
||||
///
|
||||
/// Persists the new password so a later `create-user` can re-login.
|
||||
ResetPassword {
|
||||
/// Matrix localpart of the account to reset (e.g. `argus`).
|
||||
name: String,
|
||||
},
|
||||
/// Invite a matrix user to the hive Space, or a specific room with
|
||||
/// `--room`. Idempotent.
|
||||
Invite {
|
||||
/// User to invite: a full id (`@mara:server`) or a bare
|
||||
/// localpart (qualified with the homeserver's `server_name`).
|
||||
user: String,
|
||||
/// Target room id (`!abc:server`) or alias (`#name:server`).
|
||||
/// Omit to invite to the hive Space.
|
||||
#[arg(long)]
|
||||
room: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum GithubCmd {
|
||||
/// Store a GitHub PAT for `<agent>` so its `gh` and git can
|
||||
/// authenticate.
|
||||
///
|
||||
/// Prefer `--token-stdin` — an inline `--token` is visible in shell
|
||||
/// history.
|
||||
SetToken {
|
||||
/// Logical agent name (the container/agent name).
|
||||
agent: String,
|
||||
/// The PAT value inline. Mutually exclusive with `--token-stdin`.
|
||||
#[arg(long)]
|
||||
token: Option<String>,
|
||||
/// Read the PAT from stdin (trailing newline stripped). Mutually
|
||||
/// exclusive with `--token`.
|
||||
#[arg(long, conflicts_with = "token")]
|
||||
token_stdin: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum GatewayCmd {
|
||||
/// Add a user or update an existing user's password in the gateway
|
||||
/// htpasswd.
|
||||
///
|
||||
/// Use `--password-stdin` to keep the password out of shell history.
|
||||
CreateUser {
|
||||
/// Username to add or update.
|
||||
username: String,
|
||||
/// Set the password inline. WARNING: visible in shell history and
|
||||
/// process listings — prefer `--password-stdin` for sensitive input.
|
||||
/// Mutually exclusive with `--password-stdin`.
|
||||
#[arg(long, conflicts_with = "password_stdin")]
|
||||
password: Option<String>,
|
||||
/// Read the password from stdin (single line, trailing newline
|
||||
/// stripped). Mutually exclusive with `--password`.
|
||||
#[arg(long)]
|
||||
password_stdin: bool,
|
||||
},
|
||||
/// Remove a user from the gateway htpasswd.
|
||||
DeleteUser {
|
||||
/// Username to remove.
|
||||
username: String,
|
||||
},
|
||||
/// List all gateway htpasswd usernames, one per line.
|
||||
ListUsers,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum WgCmd {
|
||||
/// Generate this hive's WireGuard key (if absent) and print its public
|
||||
/// key plus the nix to enable the mesh.
|
||||
Init {
|
||||
/// This hive's mesh address (e.g. `10.42.0.1/32`) to bake into the
|
||||
/// printed snippet. Omit to get a placeholder you fill in.
|
||||
#[arg(long)]
|
||||
address: Option<String>,
|
||||
},
|
||||
/// Print the nix to add a peer hive to the mesh.
|
||||
Peer {
|
||||
/// Peer hive's DNS domain (the `swarm.peers` attrset key).
|
||||
domain: String,
|
||||
/// Peer's WireGuard public key (from its `hivectl wg init`).
|
||||
#[arg(long)]
|
||||
pubkey: String,
|
||||
/// Peer's mesh address (e.g. `10.42.0.2/32`).
|
||||
#[arg(long)]
|
||||
address: String,
|
||||
/// Peer's `host:port` endpoint (omit for a peer that only dials out,
|
||||
/// e.g. one behind NAT — it must set an endpoint pointing back here).
|
||||
#[arg(long)]
|
||||
endpoint: Option<String>,
|
||||
},
|
||||
/// Show the live mesh interface state.
|
||||
Status,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum QuotaCmd {
|
||||
/// Enable btrfs qgroup accounting on the agent-state filesystem.
|
||||
///
|
||||
/// Run once before `show` / `limit`. No-op on non-btrfs hosts.
|
||||
Enable,
|
||||
/// Report per-agent disk usage from btrfs qgroups (all agents, or one
|
||||
/// by name).
|
||||
Show {
|
||||
/// Agent to show (omit for all agents with a state subvolume).
|
||||
name: Option<String>,
|
||||
},
|
||||
/// Set or clear an agent's disk-usage quota.
|
||||
Limit {
|
||||
/// Agent whose state subvolume to limit.
|
||||
name: String,
|
||||
/// Size cap (`5G`, `500M`, `1073741824`) or `none` to clear.
|
||||
size: String,
|
||||
},
|
||||
}
|
||||
|
||||
// Default host admin socket path. Shared with `hive-c0re`'s `main.rs`
|
||||
// default via `hive_host_sock::HOST_SOCKET` — the daemon binds there
|
||||
// and `hivectl agents` connects to it.
|
||||
pub(crate) use hive_host_sock::HOST_SOCKET as DEFAULT_HOST_SOCKET;
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum AgentsCmd {
|
||||
/// Show all managed agents with their status and technical state.
|
||||
List {
|
||||
/// Emit the raw JSON rows instead of the padded table (for
|
||||
/// scripting). The table is the default human-readable shape.
|
||||
#[arg(long)]
|
||||
json: bool,
|
||||
},
|
||||
/// Stop and start a single agent container without rebuilding config.
|
||||
Restart {
|
||||
/// Agent name (e.g. `damocles`, `ruth`).
|
||||
name: String,
|
||||
/// Return immediately after the restart DAG is queued.
|
||||
#[arg(long)]
|
||||
no_wait: bool,
|
||||
},
|
||||
/// Restart all managed agent containers.
|
||||
RestartAll {
|
||||
/// Return immediately after the restart DAGs are queued.
|
||||
#[arg(long)]
|
||||
no_wait: bool,
|
||||
},
|
||||
/// Spawn a new agent container directly, bypassing the approval queue.
|
||||
///
|
||||
/// Operator-on-the-host only; use `request-spawn` for an approval-gated
|
||||
/// spawn.
|
||||
Spawn {
|
||||
/// Agent name (e.g. `iris`).
|
||||
name: String,
|
||||
},
|
||||
/// Queue a spawn request for operator approval.
|
||||
RequestSpawn {
|
||||
/// Agent name.
|
||||
name: String,
|
||||
},
|
||||
/// Stop a managed container (graceful).
|
||||
Kill {
|
||||
/// Agent name.
|
||||
name: String,
|
||||
},
|
||||
/// Tear down a sub-agent container, keeping its state by default. No
|
||||
/// undo.
|
||||
Destroy {
|
||||
/// Agent name.
|
||||
name: String,
|
||||
/// Also wipe the agent's state dirs (config + creds + notes).
|
||||
#[arg(long)]
|
||||
purge: bool,
|
||||
},
|
||||
/// Apply pending config to a managed container.
|
||||
Rebuild {
|
||||
/// Agent name.
|
||||
name: String,
|
||||
},
|
||||
/// Move an agent in the topology tree — under a new parent, or to root.
|
||||
SetParent {
|
||||
/// Agent to move.
|
||||
child: String,
|
||||
/// New parent agent name. Mutually exclusive with `--root`.
|
||||
#[arg(long, conflicts_with = "root", required_unless_present = "root")]
|
||||
parent: Option<String>,
|
||||
/// Promote `child` to root (no parent).
|
||||
#[arg(long)]
|
||||
root: bool,
|
||||
},
|
||||
}
|
||||
|
||||
/// Operator approval queue: list, approve, or deny pending requests.
|
||||
#[derive(Subcommand)]
|
||||
pub enum ApprovalsCmd {
|
||||
/// List pending approval requests submitted by agents.
|
||||
Pending,
|
||||
/// Approve a pending request by id; the action runs immediately.
|
||||
Approve {
|
||||
/// Approval id (from `hivectl approvals pending`).
|
||||
id: i64,
|
||||
},
|
||||
/// Deny a pending request by id.
|
||||
Deny {
|
||||
/// Approval id.
|
||||
id: i64,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum SubvolCmd {
|
||||
/// Convert a plain-dir agent state root into a btrfs subvolume in
|
||||
/// place, so it gains snapshots and per-subvol usage/quota.
|
||||
///
|
||||
/// Bounces the agent to migrate its state, so it requires `--yes`.
|
||||
Upgrade {
|
||||
/// Agent name (e.g. `damocles`, `iris`).
|
||||
name: String,
|
||||
/// Confirm: this stops the agent, migrates its state dir, and
|
||||
/// restarts it. Required — the command refuses without it.
|
||||
#[arg(long)]
|
||||
yes: bool,
|
||||
},
|
||||
/// Read-only snapshots of an agent's state subvolume.
|
||||
Snapshot {
|
||||
#[command(subcommand)]
|
||||
cmd: SnapshotCmd,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum SnapshotCmd {
|
||||
/// Create a read-only snapshot (agent must already be a subvolume).
|
||||
Create {
|
||||
/// Agent name (e.g. `damocles`, `iris`).
|
||||
name: String,
|
||||
/// Snapshot label. Mandatory, and must start with `hive-` — the
|
||||
/// prefix doubles as an allow-list hive-priv checks so only
|
||||
/// hivectl-issued snapshot names can reach the `btrfs subvolume
|
||||
/// snapshot` shellout.
|
||||
#[arg(long)]
|
||||
label: String,
|
||||
},
|
||||
/// Delete a snapshot created by `subvol snapshot create`.
|
||||
Delete {
|
||||
/// Agent name the snapshot belongs to.
|
||||
name: String,
|
||||
/// Snapshot label passed to `subvol snapshot create --label`.
|
||||
label: String,
|
||||
},
|
||||
/// Export a snapshot to a local file via `btrfs send` (the local-file
|
||||
/// half of inter-hive migration transport; the cross-hive `ssh ...
|
||||
/// btrfs receive` leg isn't wired up yet). Also useful standalone as a
|
||||
/// point-in-time backup: a full send with no `--parent` produces a
|
||||
/// self-contained archive of the snapshot.
|
||||
Send {
|
||||
/// Agent name the snapshot belongs to.
|
||||
name: String,
|
||||
/// Snapshot label passed to `subvol snapshot create --label`.
|
||||
label: String,
|
||||
/// Optional parent snapshot label for an incremental send
|
||||
/// (`btrfs send -p`) — must be an existing, older snapshot of the
|
||||
/// same agent. Omit for a full send.
|
||||
#[arg(long)]
|
||||
parent: Option<String>,
|
||||
/// Destination filename (not a path) under the migrate-staging
|
||||
/// dir. Refused if it already exists.
|
||||
#[arg(long)]
|
||||
dest: String,
|
||||
},
|
||||
}
|
||||
Loading…
Reference in a new issue