refactor(#2285): repoint all hive-c0re host-path consumers to paths.rs

This commit is contained in:
damocles 2026-07-10 19:52:38 +02:00 committed by mara
commit 187c364feb
16 changed files with 95 additions and 125 deletions

View file

@ -61,49 +61,22 @@ pub const CONTAINER_MANAGER_AGENTS_MOUNT: &str = "/agents";
/// inside the container.
pub const CONTAINER_MANAGER_APPLIED_MOUNT: &str = "/applied";
/// The on-host root that gets bind-mounted to `/agents` inside the manager.
/// Hard-coded to match `AGENT_STATE_ROOT` in coordinator.rs (kept duplicated
/// here so lifecycle stays usable as a leaf module).
pub(super) const HOST_AGENTS_ROOT: &str = "/var/lib/hyperhive/agents";
/// On-host applied repo root, mirrored RO into the manager. Matches
/// `APPLIED_STATE_ROOT` in coordinator.rs.
const HOST_APPLIED_ROOT: &str = "/var/lib/hyperhive/applied";
/// On-host meta repo root, mirrored RO into the manager. Matches
/// `meta::meta_dir()` but duplicated here so lifecycle stays a leaf.
const HOST_META_ROOT: &str = "/var/lib/hyperhive/meta";
/// Shared directory accessible to all agents. All agents bind-mount this RW.
const HOST_SHARED_ROOT: &str = "/var/lib/hyperhive/shared";
/// Append bind flags for `child`'s state, harness, and config dirs into
/// `binds`, all read-write. The RW on `state` is deliberate (recovery),
/// not an oversight; see docs/persistence.md ("Parent access to child
/// state") for the rationale. Creates missing host-side directories so
/// nspawn doesn't refuse to start; missing dirs are non-fatal.
fn bind_child_agent_dirs(child: &str, binds: &mut Vec<BindMount>) {
let state_dir = format!("{HOST_AGENTS_ROOT}/{child}/state");
let harness_dir = format!("{HOST_AGENTS_ROOT}/{child}/harness");
let config_dir = format!("{HOST_AGENTS_ROOT}/{child}/config");
for dir in [&state_dir, &harness_dir, &config_dir] {
let _ = std::fs::create_dir_all(dir);
let child_root = crate::paths::agent_state_dir(child);
for sub in ["state", "harness", "config"] {
let host = child_root.join(sub);
let _ = std::fs::create_dir_all(&host);
binds.push(BindMount {
host_path: host.to_string_lossy().into_owned(),
container_path: format!("/agents/{child}/{sub}"),
read_only: false,
});
}
binds.push(BindMount {
host_path: state_dir,
container_path: format!("/agents/{child}/state"),
read_only: false,
});
binds.push(BindMount {
host_path: harness_dir,
container_path: format!("/agents/{child}/harness"),
read_only: false,
});
binds.push(BindMount {
host_path: config_dir,
container_path: format!("/agents/{child}/config"),
read_only: false,
});
}
/// Hive-wide secrets forwarded into every agent container via nspawn
@ -154,8 +127,9 @@ async fn set_nspawn_flags(
notes_dir: &Path,
) -> Result<()> {
// Ensure /shared directory exists before binding. systemd-nspawn requires the bind source to exist.
std::fs::create_dir_all(HOST_SHARED_ROOT)
.with_context(|| format!("create {HOST_SHARED_ROOT}"))?;
let shared_root = crate::paths::shared_root();
std::fs::create_dir_all(&shared_root)
.with_context(|| format!("create {}", shared_root.display()))?;
// Make /shared writable by every agent. Containers share host uids (no
// PrivateUsers), but each agent is a distinct unix user, so a root-owned
// 0755 dir leaves them unable to write — the documented "read/write for
@ -169,8 +143,8 @@ async fn set_nspawn_flags(
{
use std::os::unix::fs::PermissionsExt as _;
let perms = std::fs::Permissions::from_mode(0o1777);
std::fs::set_permissions(HOST_SHARED_ROOT, perms)
.with_context(|| format!("chmod 1777 {HOST_SHARED_ROOT}"))?;
std::fs::set_permissions(&shared_root, perms)
.with_context(|| format!("chmod 1777 {}", shared_root.display()))?;
}
// Ensure /knowledge dir exists. It may be empty until forge seeds it;
// nspawn refuses to start if the bind source is missing entirely.
@ -204,7 +178,7 @@ async fn set_nspawn_flags(
read_only: false,
},
BindMount {
host_path: HOST_SHARED_ROOT.to_owned(),
host_path: shared_root.to_string_lossy().into_owned(),
container_path: CONTAINER_SHARED_MOUNT.to_owned(),
read_only: false,
},
@ -234,10 +208,11 @@ async fn set_nspawn_flags(
read_only: false,
});
}
let own_config = format!("{HOST_AGENTS_ROOT}/{agent_name}/config");
std::fs::create_dir_all(&own_config).with_context(|| format!("create {own_config}"))?;
let own_config = crate::paths::agent_state_dir(agent_name).join("config");
std::fs::create_dir_all(&own_config)
.with_context(|| format!("create {}", own_config.display()))?;
binds.push(BindMount {
host_path: own_config,
host_path: own_config.to_string_lossy().into_owned(),
container_path: format!("/agents/{agent_name}/config"),
read_only: true,
});
@ -270,15 +245,16 @@ async fn set_nspawn_flags(
// startup migration, but make sure the directory is there
// before the role holder comes up in case set_nspawn_flags
// fires first (e.g. cold start with no agents).
std::fs::create_dir_all(HOST_META_ROOT)
.with_context(|| format!("create {HOST_META_ROOT}"))?;
let meta_root = crate::paths::meta_root();
std::fs::create_dir_all(&meta_root)
.with_context(|| format!("create {}", meta_root.display()))?;
binds.push(BindMount {
host_path: HOST_APPLIED_ROOT.to_owned(),
host_path: crate::paths::applied_root().to_string_lossy().into_owned(),
container_path: CONTAINER_MANAGER_APPLIED_MOUNT.to_owned(),
read_only: true,
});
binds.push(BindMount {
host_path: HOST_META_ROOT.to_owned(),
host_path: meta_root.to_string_lossy().into_owned(),
container_path: crate::meta::CONTAINER_MANAGER_META_MOUNT.to_owned(),
read_only: true,
});

View file

@ -864,7 +864,7 @@ pub async fn sync_tmpfiles() {
/// # Errors
/// Returns an error if `create_dir_all` fails.
pub fn ensure_agent_runtime_dir(name: &str) -> Result<()> {
let dir = std::path::PathBuf::from(format!("/run/hyperhive/agents/{name}"));
let dir = crate::paths::agent_runtime_dir(name);
std::fs::create_dir_all(&dir)
.with_context(|| format!("create agent runtime dir {}", dir.display()))
}

View file

@ -9,7 +9,6 @@ use anyhow::{Context, Result, bail};
use super::git::{
git, git_command, git_commit, git_read_tree_reset, git_rev_parse, git_root_commit, git_tag,
};
use super::host_config::HOST_AGENTS_ROOT;
/// Initialize the manager-editable proposed repo. Seeds two tracked
/// files: `agent.nix` (the module the manager edits) and `flake.nix`
@ -217,7 +216,7 @@ pub fn ensure_state_dir(notes_dir: &Path) -> Result<()> {
/// brand-new agent on a btrfs host gets a real subvolume. Subvolume creation
/// is privileged, so it's delegated to hive-priv.
pub async fn ensure_agent_state_subvolume(name: &str) -> Result<()> {
let root = Path::new(HOST_AGENTS_ROOT).join(name);
let root = crate::paths::agent_state_dir(name);
if root.exists() {
return Ok(());
}