use std::path::PathBuf;
use clap::{Args, Subcommand};
use net_sdk::deck::{MeshOsSnapshot, StatusSummary};
use serde::Serialize;
use crate::context::{resolve_profile, CliContext};
use crate::error::{generic, CliError};
use crate::prelude::{emit_value, OutputFormat};
#[derive(Subcommand, Debug)]
pub enum SnapshotCommand {
Get(GetArgs),
Status(StatusArgs),
}
#[derive(Args, Debug)]
pub struct GetArgs {
#[arg(long)]
pub identity: Option<PathBuf>,
#[arg(long, default_value_t = crate::prelude::DEFAULT_SUPERVISOR_NODE)]
pub node: u64,
}
#[derive(Args, Debug)]
pub struct StatusArgs {
#[arg(long)]
pub identity: Option<PathBuf>,
#[arg(long, default_value_t = crate::prelude::DEFAULT_SUPERVISOR_NODE)]
pub node: u64,
}
pub async fn run(
cmd: SnapshotCommand,
output: Option<OutputFormat>,
config_path: Option<&std::path::Path>,
profile_name: &str,
) -> Result<(), CliError> {
match cmd {
SnapshotCommand::Get(args) => {
let profile = resolve_profile(config_path, profile_name).await?;
let ctx =
CliContext::build(&profile, args.identity.as_deref(), args.node, false).await?;
let snapshot: MeshOsSnapshot = ctx.deck().status();
emit_value(OutputFormat::resolve_oneshot(output), &snapshot)
.map_err(|e| generic(format!("write snapshot: {e}")))?;
}
SnapshotCommand::Status(args) => {
let profile = resolve_profile(config_path, profile_name).await?;
let ctx =
CliContext::build(&profile, args.identity.as_deref(), args.node, false).await?;
let summary: StatusSummary = ctx.deck().status_summary();
let mirror = StatusSummaryMirror::from(&summary);
emit_value(OutputFormat::resolve_oneshot(output), &mirror)
.map_err(|e| generic(format!("write status: {e}")))?;
}
}
Ok(())
}
#[derive(Serialize)]
struct StatusSummaryMirror {
peers: PeerCountsMirror,
daemons: DaemonCountsMirror,
replica_chains: u64,
avoid_list_entries: u64,
recently_emitted_count: u64,
recent_failure_count: u64,
admin_audit_ring_depth: u64,
freeze_remaining_ms: Option<u64>,
local_maintenance_active: bool,
}
#[derive(Serialize)]
struct PeerCountsMirror {
healthy: u64,
degraded: u64,
unreachable: u64,
unknown: u64,
}
#[derive(Serialize)]
struct DaemonCountsMirror {
running: u64,
starting: u64,
stopping: u64,
stopped: u64,
backing_off: u64,
crash_looping: u64,
}
impl From<&StatusSummary> for StatusSummaryMirror {
fn from(s: &StatusSummary) -> Self {
Self {
peers: PeerCountsMirror {
healthy: s.peers.healthy as u64,
degraded: s.peers.degraded as u64,
unreachable: s.peers.unreachable as u64,
unknown: s.peers.unknown as u64,
},
daemons: DaemonCountsMirror {
running: s.daemons.running as u64,
starting: s.daemons.starting as u64,
stopping: s.daemons.stopping as u64,
stopped: s.daemons.stopped as u64,
backing_off: s.daemons.backing_off as u64,
crash_looping: s.daemons.crash_looping as u64,
},
replica_chains: s.replica_chains as u64,
avoid_list_entries: s.avoid_list_entries as u64,
recently_emitted_count: s.recently_emitted_count as u64,
recent_failure_count: s.recent_failure_count as u64,
admin_audit_ring_depth: s.admin_audit_ring_depth as u64,
freeze_remaining_ms: s.freeze_remaining_ms,
local_maintenance_active: s.local_maintenance_active,
}
}
}