topology: meta-repo agent hierarchy + ContainerView.parent (#361)
This commit is contained in:
parent
e931c08739
commit
0b03d5bcfb
6 changed files with 403 additions and 3 deletions
|
|
@ -85,6 +85,16 @@ pub async fn sync_agents(
|
|||
std::fs::write(&flake_path, &new_flake)
|
||||
.with_context(|| format!("write {}", flake_path.display()))?;
|
||||
|
||||
// Reconcile topology.json against the live agent set — adds
|
||||
// entries for newly-spawned agents (default: manager as parent,
|
||||
// manager itself as root) and drops removed agents. Operator
|
||||
// overrides via the write API (#361 follow-up) are preserved
|
||||
// because reconcile only fills in missing entries. Idempotent;
|
||||
// when nothing changed the file isn't touched.
|
||||
let agent_names: Vec<String> = agents.iter().map(|a| a.name.clone()).collect();
|
||||
let topology_changed = crate::topology::reconcile(&agent_names)
|
||||
.with_context(|| format!("reconcile {}", crate::topology::topology_path().display()))?;
|
||||
|
||||
if initial {
|
||||
git(&dir, &["init", "--initial-branch=main"]).await?;
|
||||
}
|
||||
|
|
@ -96,12 +106,20 @@ pub async fn sync_agents(
|
|||
// contain '/flake.nix'". Lock then commit once with both
|
||||
// flake.nix and flake.lock — single commit per change.
|
||||
git(&dir, &["add", "flake.nix"]).await?;
|
||||
// Stage topology.json on every sync (regenerated by reconcile
|
||||
// above when the agent set changed). git add is a no-op when the
|
||||
// file content is unchanged.
|
||||
if crate::topology::topology_path().exists() {
|
||||
git(&dir, &["add", "topology.json"]).await?;
|
||||
}
|
||||
nix(&dir, &["flake", "lock"]).await?;
|
||||
if std::path::Path::new(&dir).join("flake.lock").exists() {
|
||||
git(&dir, &["add", "flake.lock"]).await?;
|
||||
}
|
||||
let msg = if initial {
|
||||
format!("seed meta from {} agent(s)", agents.len())
|
||||
} else if topology_changed {
|
||||
"regenerate meta flake + topology".to_owned()
|
||||
} else {
|
||||
"regenerate meta flake".to_owned()
|
||||
};
|
||||
|
|
@ -348,7 +366,7 @@ where
|
|||
let pronouns_escaped = operator_pronouns.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
let _ = writeln!(
|
||||
out,
|
||||
" dashboardPort = {dashboard_port};\n operatorPronouns = \"{pronouns_escaped}\";\n mkAgent = {{ name, isManager, port }}:"
|
||||
" dashboardPort = {dashboard_port};\n operatorPronouns = \"{pronouns_escaped}\";\n mkAgent = {{ name, isManager, port, parent ? null }}:"
|
||||
);
|
||||
out.push_str(
|
||||
r#" let
|
||||
|
|
@ -357,6 +375,7 @@ where
|
|||
else hyperhive.nixosConfigurations.agent-base;
|
||||
input = inputs."agent-${name}";
|
||||
service = if isManager then "hive-m1nd" else "hive-ag3nt";
|
||||
parentEnv = if parent == null then {} else { HIVE_PARENT = parent; };
|
||||
in
|
||||
base.extendModules {
|
||||
modules = [
|
||||
|
|
@ -372,7 +391,7 @@ where
|
|||
HIVE_LABEL = name;
|
||||
HYPERHIVE_STATE_DIR = "/agents/${name}/state";
|
||||
};
|
||||
systemd.services.${service}.environment = {
|
||||
systemd.services.${service}.environment = parentEnv // {
|
||||
HIVE_PORT = toString port;
|
||||
HIVE_LABEL = name;
|
||||
HIVE_DASHBOARD_PORT = toString dashboardPort;
|
||||
|
|
@ -406,14 +425,25 @@ where
|
|||
nixosConfigurations = {
|
||||
"#,
|
||||
);
|
||||
// Pull the topology map once and look up each agent's parent. An
|
||||
// empty / absent topology.json yields `parent = null` for everyone
|
||||
// — equivalent to the pre-#361 status quo (every container at root).
|
||||
// `meta::sync_agents` seeds the file on first run with manager as
|
||||
// root + everyone else under manager.
|
||||
let topology = crate::topology::read();
|
||||
for spec in agents {
|
||||
let parent_attr = topology
|
||||
.get(&spec.name)
|
||||
.and_then(|p| p.as_ref())
|
||||
.map_or_else(|| "null".to_owned(), |p| format!("\"{p}\""));
|
||||
let _ = writeln!(
|
||||
out,
|
||||
" {} = mkAgent {{ name = \"{}\"; isManager = {}; port = {}; }};",
|
||||
" {} = mkAgent {{ name = \"{}\"; isManager = {}; port = {}; parent = {}; }};",
|
||||
spec.name,
|
||||
spec.name,
|
||||
if spec.is_manager { "true" } else { "false" },
|
||||
spec.port,
|
||||
parent_attr,
|
||||
);
|
||||
}
|
||||
out.push_str(" };\n };\n}\n");
|
||||
|
|
|
|||
Loading…
Reference in a new issue