fix(hivectl): ask the daemon whether an agent exists
The agents root is 0700 and owned by the daemon's user, so hivectl's client-side existence guard hit EACCES on traversal for anyone not root. It reported that as "this command needs root; re-run with sudo", which turned three verbs' pre-flight check into a permission error about the wrong thing: `choom`, `subvol upgrade` and `subvol snapshot create` all failed at the guard rather than at whatever they actually needed. The daemon runs as the owning user and already answers this question for its own provisioning paths, so expose it on the host socket as `AgentExists` and have hivectl ask. Operators reach that socket through the `hive-admin` group, so the guard now works without sudo. `choom` still needs root for `machinectl shell` — we ship no polkit rule granting those actions — so it now checks the effective uid and says so directly instead of failing later inside systemd's authorisation.
This commit is contained in:
parent
1bbc09e9dd
commit
170fd817ea
9 changed files with 119 additions and 36 deletions
|
|
@ -136,6 +136,19 @@ pub enum HostRequest {
|
|||
Rebuild { name: Ident },
|
||||
/// List managed containers.
|
||||
List,
|
||||
/// Report whether `name` is a managed agent, i.e. whether it has a
|
||||
/// persistent state dir under the agents root. Answered daemon-side
|
||||
/// because that root is `0700 hive-core`: a client stat-ing it
|
||||
/// without root gets EACCES, so the pre-flight "does this agent
|
||||
/// exist?" guard in front of `hivectl choom` / `agents subvol` used
|
||||
/// to fail with a permission error instead of an answer. The daemon
|
||||
/// already runs as the owning user and does the same check for its
|
||||
/// own provisioning paths. Result: [`HostResponse::agent_exists`].
|
||||
///
|
||||
/// State dir, not the live container list — a destroyed-but-kept
|
||||
/// agent is still an agent, and re-provisioning one should drop its
|
||||
/// credentials into the existing state tree.
|
||||
AgentExists { name: Ident },
|
||||
/// List managed agents with their full status + technical state
|
||||
/// (running / needs-login / needs-update / deployed sha / parent /
|
||||
/// pending reminders) — the `hivectl agents list` roster view.
|
||||
|
|
@ -441,6 +454,13 @@ pub struct HostResponse {
|
|||
/// request kind.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub agent_statuses: Option<Vec<AgentStatusRow>>,
|
||||
/// `AgentExists` result — whether the named agent has a state dir
|
||||
/// under the agents root. `None` for every other request kind, which
|
||||
/// is why it's an `Option<bool>` and not a bare `bool`: a client must
|
||||
/// be able to tell "the daemon said no" from "the daemon answered a
|
||||
/// different question".
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub agent_exists: Option<bool>,
|
||||
/// Ids of the job-queue DAGs this request submitted (rebuild /
|
||||
/// restart / power ops). Clients poll them via
|
||||
/// [`HostRequest::QueueDag`]; `None` for non-submitting requests.
|
||||
|
|
@ -520,6 +540,16 @@ impl HostResponse {
|
|||
}
|
||||
}
|
||||
|
||||
/// `AgentExists` result — whether the named agent has a state dir.
|
||||
#[must_use]
|
||||
pub fn agent_exists(exists: bool) -> Self {
|
||||
Self {
|
||||
ok: true,
|
||||
agent_exists: Some(exists),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// A request that submitted job-queue DAGs — carries their ids for
|
||||
/// the client's wait/progress loop.
|
||||
#[must_use]
|
||||
|
|
|
|||
Loading…
Reference in a new issue