remove the hivectl-only quota verbs and the trollshell status feed
This commit is contained in:
parent
70a8e54038
commit
cf360b74b9
1 changed files with 51 additions and 521 deletions
|
|
@ -384,34 +384,6 @@ pub async fn delete_agent_subvolume(agent_name: &str) -> Result<()> {
|
|||
.await?)
|
||||
}
|
||||
|
||||
/// Enable btrfs qgroup accounting on the agent-state filesystem (operator
|
||||
/// opt-in; prerequisite for usage reads + quotas). Idempotent; no-op off
|
||||
/// btrfs. Via hive-priv (root).
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the hive-priv call fails or `btrfs quota enable`
|
||||
/// reports a non-zero exit.
|
||||
pub async fn ensure_btrfs_quota() -> Result<()> {
|
||||
ok(call(&PrivRequest::EnsureBtrfsQuota).await?)
|
||||
}
|
||||
|
||||
/// Read an agent state subvolume's btrfs qgroup usage, returning
|
||||
/// `(referenced_bytes, exclusive_bytes)`. Via hive-priv (root).
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the hive-priv call fails, `btrfs qgroup show` exits
|
||||
/// non-zero (e.g. quota not enabled — the message propagates so the caller
|
||||
/// can surface it), or the output has no level-0 qgroup row to parse.
|
||||
pub async fn read_subvolume_usage(agent_name: &str) -> Result<(u64, u64)> {
|
||||
let (stdout, _) = check(
|
||||
call(&PrivRequest::ReadSubvolumeUsage {
|
||||
agent_name: agent_name.to_owned(),
|
||||
})
|
||||
.await?,
|
||||
)?;
|
||||
parse_qgroup_usage(&stdout).with_context(|| format!("parse qgroup usage for {agent_name}"))
|
||||
}
|
||||
|
||||
/// How long hive-c0re waits for hive-priv's answer to a disk measurement:
|
||||
/// hive-priv's own bound plus a margin, so a hung hive-priv can't stall the
|
||||
/// caller while a slow walk still arrives as hive-priv's timeout error.
|
||||
|
|
@ -450,20 +422,6 @@ async fn within<T>(
|
|||
.map_err(|_| anyhow::anyhow!("hive-priv did not answer within {}s", limit.as_secs()))?
|
||||
}
|
||||
|
||||
/// Set or clear a btrfs qgroup size limit on an agent's state subvolume.
|
||||
/// `limit_bytes = None` clears it. Requires quota enabled. Via hive-priv.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the hive-priv call fails or `btrfs qgroup limit`
|
||||
/// reports a non-zero exit (e.g. quota not enabled).
|
||||
pub async fn set_subvolume_quota(agent_name: &str, limit_bytes: Option<u64>) -> Result<()> {
|
||||
ok(call(&PrivRequest::SetSubvolumeQuota {
|
||||
agent_name: agent_name.to_owned(),
|
||||
limit_bytes,
|
||||
})
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Convert an existing plain-dir agent state root into a btrfs subvolume in
|
||||
/// place (operator opt-in; via hive-priv as root). The caller must stop the
|
||||
/// agent first (so its state bind-mount is gone) and restart it after.
|
||||
|
|
@ -553,29 +511,6 @@ fn send_snapshot_request(
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse `(referenced, exclusive)` bytes from `btrfs qgroup show -f --raw`
|
||||
/// output (a qgroup row is `<id-with-slash> <rfer> <excl> …`).
|
||||
///
|
||||
/// `-f <path>` already restricts the listing to qgroups impacting that path
|
||||
/// (excluding ancestral qgroups — see btrfs-qgroup-show(8)), so it never
|
||||
/// mixes in other agents' subvolumes. Among the rows it returns we select
|
||||
/// the **level-0** qgroup (`0/<subvolid>`) — the subvolume's own automatic
|
||||
/// usage qgroup — rather than blindly taking the last line. Picking the
|
||||
/// `0/` leaf is unambiguous even if an operator has assigned the subvolume
|
||||
/// to a higher-level aggregate qgroup (`1/<id>`, …) that `-F` would surface.
|
||||
fn parse_qgroup_usage(out: &str) -> Result<(u64, u64)> {
|
||||
for line in out.lines() {
|
||||
let cols: Vec<&str> = line.split_whitespace().collect();
|
||||
if cols.len() >= 3
|
||||
&& cols[0].starts_with("0/")
|
||||
&& let (Ok(rfer), Ok(excl)) = (cols[1].parse::<u64>(), cols[2].parse::<u64>())
|
||||
{
|
||||
return Ok((rfer, excl));
|
||||
}
|
||||
}
|
||||
bail!("no level-0 qgroup data row in `btrfs qgroup show` output: {out:?}")
|
||||
}
|
||||
|
||||
fn check(resp: PrivResponse) -> Result<(String, String)> {
|
||||
if resp.ok {
|
||||
Ok((resp.stdout, resp.stderr))
|
||||
|
|
@ -597,8 +532,8 @@ mod tests {
|
|||
use super::{
|
||||
BindMount, CredentialMount, HiveFacts, NetworkIsolation, NixBuilds, PrivRequest,
|
||||
PrivResponse, PrivStream, call_at, call_streaming_at, check, create_container_request,
|
||||
older_hive_priv_refused, parse_qgroup_usage, resource_limits_request,
|
||||
send_snapshot_request, update_container_request, within, write_nspawn_flags_request,
|
||||
older_hive_priv_refused, resource_limits_request, send_snapshot_request,
|
||||
update_container_request, within, write_nspawn_flags_request,
|
||||
};
|
||||
use anyhow::Context as _;
|
||||
use serde_json::{Value, json};
|
||||
|
|
@ -748,23 +683,6 @@ mod tests {
|
|||
assert_eq!(incremental["snapshot_name"], "snap-2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_level_zero_qgroup_row_gives_the_usage() {
|
||||
let out = "qgroupid rfer excl\n\
|
||||
-------- ---- ----\n\
|
||||
1/100 999 888\n\
|
||||
0/257 4096 2048\n";
|
||||
assert_eq!(parse_qgroup_usage(out).expect("a 0/ row"), (4096, 2048));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_with_no_level_zero_row_is_an_error() {
|
||||
let err = parse_qgroup_usage("qgroupid rfer excl\n1/100 1 2\n").expect_err("no 0/ row");
|
||||
assert!(err.to_string().contains("no level-0 qgroup"), "{err}");
|
||||
// A 0/ row whose columns are not numbers is skipped, not misread.
|
||||
parse_qgroup_usage("0/257 x y\n").expect_err("non-numeric columns");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_refused_response_surfaces_the_error_text() {
|
||||
let refused = PrivResponse {
|
||||
|
|
|
|||
Loading…
Reference in a new issue