hivectl: rename hivectl agents to hivectl agent <name> <verb>
This commit is contained in:
parent
f48ba3ca0d
commit
03afbd1316
19 changed files with 367 additions and 525 deletions
|
|
@ -1,15 +1,18 @@
|
|||
//! `hivectl agents` — everything scoped to a managed agent: container
|
||||
//! lifecycle over the host admin socket
|
||||
//! (list/restart/restart-all/pause/resume/spawn/kill/destroy/rebuild/
|
||||
//! set-parent/set-limits), plus the `quota` and `subvol` groups, whose
|
||||
//! handlers live in their own modules.
|
||||
//! `hivectl agent <name>` — everything scoped to ONE managed agent:
|
||||
//! container lifecycle over the host admin socket (restart/pause/resume/
|
||||
//! spawn/kill/destroy/rebuild/set-parent/set-limits/choom), plus the
|
||||
//! `quota` and `subvol` groups, whose handlers live in their own modules.
|
||||
//! `agents_list` (`hivectl list-agents`) is the one genuinely hive-wide
|
||||
//! read that lives in this module too since it shares the same daemon
|
||||
//! request as everything else here, even though it's dispatched from a
|
||||
//! top-level `Cmd` variant, not `AgentCmd`.
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use hive_host_sock::HostRequest;
|
||||
|
||||
use crate::cli::{AgentsCmd, QuotaCmd};
|
||||
use crate::cli::{AgentCmd, AgentQuotaCmd};
|
||||
use crate::dag_progress::wait_for_dags;
|
||||
use crate::util::render;
|
||||
|
||||
|
|
@ -33,11 +36,11 @@ async fn agents_restart(socket: &Path, name: &str, no_wait: bool) -> Result<()>
|
|||
}
|
||||
}
|
||||
|
||||
/// `hivectl agents list` — fetch the per-agent status roster from the
|
||||
/// `hivectl list-agents` — fetch the per-agent status roster from the
|
||||
/// daemon (`HostRequest::AgentStatus`) and render it as a padded table,
|
||||
/// or the raw JSON rows with `--json`. Reuses the dashboard's
|
||||
/// `ContainerView` aggregation, so the CLI and the web UI never drift.
|
||||
async fn agents_list(socket: &Path, json: bool) -> Result<()> {
|
||||
pub(crate) async fn agents_list(socket: &Path, json: bool) -> Result<()> {
|
||||
let resp = crate::client::request(socket, hive_host_sock::HostRequest::AgentStatus)
|
||||
.await
|
||||
.with_context(|| format!("connect to daemon socket {}", socket.display()))?;
|
||||
|
|
@ -112,28 +115,7 @@ async fn agents_list(socket: &Path, json: bool) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn agents_restart_all(socket: &Path, no_wait: bool) -> Result<()> {
|
||||
let resp = crate::client::request(socket, hive_host_sock::HostRequest::RestartAll)
|
||||
.await
|
||||
.with_context(|| format!("connect to daemon socket {}", socket.display()))?;
|
||||
let agents = resp.agents.as_deref().unwrap_or(&[]);
|
||||
if agents.is_empty() {
|
||||
println!("restart-all: no managed containers found");
|
||||
} else {
|
||||
for a in agents {
|
||||
println!("restart queued: {a}");
|
||||
}
|
||||
}
|
||||
if !resp.ok {
|
||||
bail!(
|
||||
"restart-all: {}",
|
||||
resp.error.as_deref().unwrap_or("unknown error")
|
||||
);
|
||||
}
|
||||
wait_for_dags(socket, resp.queued_dags.unwrap_or_default(), no_wait).await
|
||||
}
|
||||
|
||||
/// `hivectl agents pause|resume` — flip the agent's pause marker. Not a
|
||||
/// `hivectl agent <name> pause|resume` — flip the agent's pause marker. Not a
|
||||
/// DAG, so there's nothing to wait on: the daemon writes the marker and
|
||||
/// the harness picks it up on its next poll.
|
||||
async fn set_paused(socket: &Path, name: &str, paused: bool) -> Result<()> {
|
||||
|
|
@ -159,41 +141,36 @@ async fn set_paused(socket: &Path, name: &str, paused: bool) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Dispatch `hivectl agents <verb>` — container lifecycle over the host
|
||||
/// admin socket.
|
||||
pub(crate) async fn run_agents(socket: &Path, cmd: AgentsCmd) -> Result<()> {
|
||||
/// Dispatch `hivectl agent <name> <verb>` — container lifecycle over the
|
||||
/// host admin socket, all scoped to the single `name` hoisted from the
|
||||
/// parent command.
|
||||
pub(crate) async fn run_agent(socket: &Path, name: &str, cmd: AgentCmd) -> Result<()> {
|
||||
match cmd {
|
||||
AgentsCmd::List { json } => agents_list(socket, json).await,
|
||||
AgentsCmd::Restart { name, no_wait } => agents_restart(socket, &name, no_wait).await,
|
||||
AgentsCmd::RestartAll { no_wait } => agents_restart_all(socket, no_wait).await,
|
||||
AgentsCmd::Pause { name } => set_paused(socket, &name, true).await,
|
||||
AgentsCmd::Resume { name } => set_paused(socket, &name, false).await,
|
||||
AgentsCmd::Spawn { name } => {
|
||||
let name = crate::util::parse_ident(&name)?;
|
||||
AgentCmd::Restart { no_wait } => agents_restart(socket, name, no_wait).await,
|
||||
AgentCmd::Pause => set_paused(socket, name, true).await,
|
||||
AgentCmd::Resume => set_paused(socket, name, false).await,
|
||||
AgentCmd::Spawn => {
|
||||
let name = crate::util::parse_ident(name)?;
|
||||
render(crate::client::request(socket, HostRequest::Spawn { name }).await?)
|
||||
}
|
||||
AgentsCmd::RequestSpawn { name } => {
|
||||
let name = crate::util::parse_ident(&name)?;
|
||||
AgentCmd::RequestSpawn => {
|
||||
let name = crate::util::parse_ident(name)?;
|
||||
render(crate::client::request(socket, HostRequest::RequestSpawn { name }).await?)
|
||||
}
|
||||
AgentsCmd::Kill { name } => {
|
||||
let name = crate::util::parse_ident(&name)?;
|
||||
AgentCmd::Kill => {
|
||||
let name = crate::util::parse_ident(name)?;
|
||||
render(crate::client::request(socket, HostRequest::Kill { name }).await?)
|
||||
}
|
||||
AgentsCmd::Destroy { name, purge } => {
|
||||
let name = crate::util::parse_ident(&name)?;
|
||||
AgentCmd::Destroy { purge } => {
|
||||
let name = crate::util::parse_ident(name)?;
|
||||
render(crate::client::request(socket, HostRequest::Destroy { name, purge }).await?)
|
||||
}
|
||||
AgentsCmd::Rebuild { name } => {
|
||||
let name = crate::util::parse_ident(&name)?;
|
||||
AgentCmd::Rebuild => {
|
||||
let name = crate::util::parse_ident(name)?;
|
||||
render(crate::client::request(socket, HostRequest::Rebuild { name }).await?)
|
||||
}
|
||||
AgentsCmd::SetParent {
|
||||
child,
|
||||
parent,
|
||||
root,
|
||||
} => {
|
||||
let child = crate::util::parse_ident(&child)?;
|
||||
AgentCmd::SetParent { parent, root } => {
|
||||
let child = crate::util::parse_ident(name)?;
|
||||
let new_parent = if root {
|
||||
None
|
||||
} else {
|
||||
|
|
@ -204,16 +181,15 @@ pub(crate) async fn run_agents(socket: &Path, cmd: AgentsCmd) -> Result<()> {
|
|||
.await?,
|
||||
)
|
||||
}
|
||||
AgentsCmd::SetLimits {
|
||||
name,
|
||||
AgentCmd::SetLimits {
|
||||
cpu_quota,
|
||||
memory_max,
|
||||
reset,
|
||||
} => {
|
||||
let name = crate::util::parse_ident(&name)?;
|
||||
let name = crate::util::parse_ident(name)?;
|
||||
// `--reset` is the only way to reach an all-`None` request;
|
||||
// clap rejects a bare `set-limits <name>` with neither flag,
|
||||
// so a forgotten value can't silently clear the overrides.
|
||||
// clap rejects a bare `set-limits` with neither flag, so a
|
||||
// forgotten value can't silently clear the overrides.
|
||||
let (cpu_quota, memory_max) = if reset {
|
||||
(None, None)
|
||||
} else {
|
||||
|
|
@ -231,13 +207,16 @@ pub(crate) async fn run_agents(socket: &Path, cmd: AgentsCmd) -> Result<()> {
|
|||
.await?,
|
||||
)
|
||||
}
|
||||
// `quota` and `subvol` keep their own modules — this arm is just
|
||||
// the reparenting glue that moved them under `agents`.
|
||||
AgentsCmd::Quota { cmd } => match cmd {
|
||||
QuotaCmd::Enable => crate::quota::quota_enable(socket).await,
|
||||
QuotaCmd::Show { name } => crate::quota::quota_show(socket, name.as_deref()).await,
|
||||
QuotaCmd::Set { name, size } => crate::quota::quota_limit(socket, &name, &size).await,
|
||||
AgentCmd::Choom { resume_session } => {
|
||||
crate::choom::choom(socket, name, resume_session.as_deref()).await
|
||||
}
|
||||
// `quota` and `subvol` keep their own modules — these arms are
|
||||
// just the reparenting glue that hoists `name` in from the
|
||||
// parent `agent <name>` command.
|
||||
AgentCmd::Quota { cmd } => match cmd {
|
||||
AgentQuotaCmd::Show => crate::quota::quota_show(socket, name).await,
|
||||
AgentQuotaCmd::Set { size } => crate::quota::quota_limit(socket, name, &size).await,
|
||||
},
|
||||
AgentsCmd::Subvol { cmd } => crate::subvol::dispatch_subvol(socket, cmd).await,
|
||||
AgentCmd::Subvol { cmd } => crate::subvol::dispatch_subvol(socket, name, cmd).await,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue