refactor(#2352): quota show via daemon wire command
This commit is contained in:
parent
e7f8254788
commit
3797177e7f
3 changed files with 116 additions and 30 deletions
|
|
@ -20,7 +20,6 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use hive_c0re::coordinator::Coordinator;
|
||||
|
||||
/// Rebuild-queue DAG progress rendering (`wait_for_dags` + the spinner /
|
||||
/// plain renderers), split out to keep this file manageable. `#[path]` keeps
|
||||
|
|
@ -760,7 +759,7 @@ async fn main() -> Result<()> {
|
|||
} => choom(&name, resume_session.as_deref()),
|
||||
Cmd::Quota { cmd } => match cmd {
|
||||
QuotaCmd::Enable => quota_enable(&socket).await,
|
||||
QuotaCmd::Show { name } => quota_show(name.as_deref()).await,
|
||||
QuotaCmd::Show { name } => quota_show(&socket, name.as_deref()).await,
|
||||
QuotaCmd::Limit { name, size } => quota_limit(&socket, &name, &size).await,
|
||||
},
|
||||
Cmd::MarkdownDocs => {
|
||||
|
|
@ -1046,37 +1045,41 @@ async fn quota_enable(socket: &Path) -> Result<()> {
|
|||
}
|
||||
|
||||
/// `quota show [name]` — report per-agent disk usage from btrfs qgroups.
|
||||
async fn quota_show(name: Option<&str>) -> Result<()> {
|
||||
let agents: Vec<String> = match name {
|
||||
Some(n) => vec![n.to_owned()],
|
||||
None => Coordinator::kept_state_names(),
|
||||
};
|
||||
if agents.is_empty() {
|
||||
/// The daemon resolves the agent set + reads each subvolume's usage (it
|
||||
/// holds the privileged helper); the client just formats the returned rows.
|
||||
async fn quota_show(socket: &Path, name: Option<&str>) -> Result<()> {
|
||||
let resp = hive_c0re::client::request(
|
||||
socket,
|
||||
hive_host_sock::HostRequest::QuotaShow {
|
||||
name: name.map(str::to_owned),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.with_context(|| format!("connect to daemon socket {}", socket.display()))?;
|
||||
if !resp.ok {
|
||||
// Carries the "btrfs quota not enabled — run `hivectl quota enable`
|
||||
// first" hint when qgroups are off.
|
||||
bail!("{}", resp.error.as_deref().unwrap_or("quota show failed"));
|
||||
}
|
||||
let rows = resp.quota.unwrap_or_default();
|
||||
if rows.is_empty() {
|
||||
println!("no agents with a state dir found");
|
||||
return Ok(());
|
||||
}
|
||||
for agent in &agents {
|
||||
match hive_c0re::priv_client::read_subvolume_usage(agent).await {
|
||||
Ok((rfer, excl)) => {
|
||||
println!(
|
||||
"{agent:<12} referenced {:>10} exclusive {:>10}",
|
||||
human_bytes(rfer),
|
||||
human_bytes(excl)
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
let msg = format!("{e:#}");
|
||||
// btrfs-progs prints "ERROR: ... quota not enabled" to stderr
|
||||
// when qgroups are off; match the stable fragment case-
|
||||
// insensitively rather than an exact line (the surrounding
|
||||
// wording varies across btrfs-progs versions).
|
||||
if msg.to_ascii_lowercase().contains("quota not enabled") {
|
||||
bail!("btrfs quota not enabled — run `hivectl quota enable` first");
|
||||
}
|
||||
// A plain-dir agent (no subvolume) has no qgroup; report it
|
||||
// inline and keep going rather than aborting the whole sweep.
|
||||
println!("{agent:<12} (no qgroup data — plain dir or: {msg})");
|
||||
}
|
||||
for row in &rows {
|
||||
match (row.referenced, row.exclusive) {
|
||||
(Some(rfer), Some(excl)) => println!(
|
||||
"{:<12} referenced {:>10} exclusive {:>10}",
|
||||
row.agent,
|
||||
human_bytes(rfer),
|
||||
human_bytes(excl)
|
||||
),
|
||||
// Plain-dir agent (no qgroup) — the daemon set an explanatory note.
|
||||
_ => println!(
|
||||
"{:<12} ({})",
|
||||
row.agent,
|
||||
row.note.as_deref().unwrap_or("no qgroup data")
|
||||
),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Reference in a new issue