refactor(hive-c0re): drop the request_init_config tool and InitConfig approval
swarm-controller's `InitAgentConfigRepo` node already covers config-repo creation, so this deletes a duplicate rather than a capability; old `init_config` rows are skipped by `collect_lenient` with no migration, by operator decision. Refs #4398
This commit is contained in:
parent
3f086bc659
commit
a3b672d1d5
31 changed files with 134 additions and 601 deletions
|
|
@ -229,9 +229,8 @@ pub fn write(topology: &BTreeMap<String, Option<String>>) -> std::io::Result<()>
|
|||
|
||||
/// Compute the default topology for a fresh install: every agent is a
|
||||
/// root (parent = null). There is no structural "manager" — agents
|
||||
/// arrange themselves via explicit parent edges (an agent-requested
|
||||
/// sub-agent gets a requester-as-parent edge at `init_config`; the
|
||||
/// operator reparents via the dashboard / `RequestSetParent` API).
|
||||
/// arrange themselves via explicit parent edges, written by the operator
|
||||
/// through the dashboard / `RequestSetParent` API.
|
||||
/// Used by `meta::sync_agents` on first call to seed `topology.json`.
|
||||
///
|
||||
/// As soon as an explicit write lands (dashboard / `RequestSetParent`
|
||||
|
|
@ -298,53 +297,6 @@ pub fn apply_set_parent(
|
|||
Ok(next)
|
||||
}
|
||||
|
||||
/// Declare a brand-new agent's parent edge before the agent exists in
|
||||
/// the container set. Unlike [`crate::meta::bulk_commit_topology`] /
|
||||
/// [`apply_set_parent`] (which reparent an entry that must already be
|
||||
/// present), this inserts a fresh `child -> parent`
|
||||
/// row. Used by the `InitConfig` approval to place a just-scaffolded
|
||||
/// sub-agent under its requesting parent, so the edge is in place
|
||||
/// before the first apply-commit spawns the container (and before
|
||||
/// [`reconcile`] would otherwise default it to the manager).
|
||||
///
|
||||
/// Idempotent when the edge already exists. Refuses to clobber an entry
|
||||
/// whose parent differs (one agent can't steal another's child) and
|
||||
/// validates that `parent` is itself a known agent.
|
||||
pub fn add_child(child: &str, parent: &str) -> Result<(), String> {
|
||||
let current = read();
|
||||
match apply_add_child(¤t, child, parent)? {
|
||||
Some(next) => write(&next).map_err(|e| format!("write topology.json: {e}")),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Pure form of [`add_child`] for unit tests. Returns the post-insert
|
||||
/// map (caller writes it back), `None` for an idempotent no-op (edge
|
||||
/// already present), or an error string (unknown parent / name owned by
|
||||
/// a different parent).
|
||||
pub fn apply_add_child(
|
||||
topo: &BTreeMap<String, Option<String>>,
|
||||
child: &str,
|
||||
parent: &str,
|
||||
) -> Result<Option<BTreeMap<String, Option<String>>>, String> {
|
||||
if !topo.contains_key(parent) {
|
||||
return Err(format!("unknown parent: {parent}"));
|
||||
}
|
||||
match topo.get(child) {
|
||||
Some(Some(p)) if p == parent => return Ok(None),
|
||||
Some(existing) => {
|
||||
return Err(format!(
|
||||
"agent {child} already exists in topology (parent: {existing:?}); \
|
||||
refusing to reparent via add_child"
|
||||
));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
let mut next = topo.clone();
|
||||
next.insert(child.to_owned(), Some(parent.to_owned()));
|
||||
Ok(Some(next))
|
||||
}
|
||||
|
||||
/// Reconcile `topology.json` against the current agent set. Adds an
|
||||
/// entry (default: parent = null — a new agent with no declared parent
|
||||
/// is its own root) for any agent missing from the file; removes
|
||||
|
|
@ -353,10 +305,10 @@ pub fn apply_add_child(
|
|||
/// choices stick across regenerations. Returns true when the file
|
||||
/// changed and should be re-committed by the caller.
|
||||
///
|
||||
/// `pending` lists agents that have an operator-approved proposed config
|
||||
/// repo but no container yet (init'd, not yet spawned). They are KEPT
|
||||
/// (not dropped) so the parent edge written at `InitConfig` approval
|
||||
/// survives until the first apply-commit, but they are NOT seeded with a
|
||||
/// `pending` lists agents that have a provisioned proposed config repo
|
||||
/// but no container yet (provisioned, not yet spawned). They are KEPT
|
||||
/// (not dropped) so an explicit parent edge written before the first
|
||||
/// spawn survives until the first apply-commit, but they are NOT seeded with a
|
||||
/// default parent here and NOT added to roles — that happens when the
|
||||
/// container actually spawns and the name moves into `agent_names`.
|
||||
pub fn reconcile(agent_names: &[String], pending: &[String]) -> std::io::Result<bool> {
|
||||
|
|
@ -384,12 +336,11 @@ pub fn apply_reconcile(
|
|||
for name in agent_names {
|
||||
if !next.contains_key(name) {
|
||||
// A new agent with no declared parent defaults to root
|
||||
// (parent = null). Agent-requested sub-agents always carry an
|
||||
// explicit requester-as-parent edge (written at init_config
|
||||
// approval), so they never hit this default — only
|
||||
// user/operator-initiated spawns do, and those are roots. No
|
||||
// agent is structurally privileged here: "root-ness" is just
|
||||
// a null parent.
|
||||
// (parent = null). An agent placed under a parent carries an
|
||||
// explicit edge written before its first spawn, so it never
|
||||
// hits this default — only spawns with no declared parent do,
|
||||
// and those are roots. No agent is structurally privileged
|
||||
// here: "root-ness" is just a null parent.
|
||||
next.insert(name.clone(), None);
|
||||
changed = true;
|
||||
}
|
||||
|
|
@ -502,8 +453,7 @@ mod tests {
|
|||
#[test]
|
||||
fn default_seed_makes_every_agent_root() {
|
||||
// No structural manager: every agent defaults to root (null
|
||||
// parent). Explicit edges (init_config / dashboard) are layered
|
||||
// on later.
|
||||
// parent). Explicit edges are layered on later.
|
||||
let agents = vec![
|
||||
"alice".to_owned(),
|
||||
crate::lifecycle::MANAGER_NAME.to_owned(),
|
||||
|
|
@ -630,42 +580,6 @@ mod tests {
|
|||
assert_eq!(next, topo_three_level());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_add_child_inserts_new_edge_under_parent() {
|
||||
// alice spawns a brand-new child `dora`: the edge lands
|
||||
// with alice as parent without disturbing the rest of the tree.
|
||||
let next = apply_add_child(&topo_three_level(), "dora", "alice")
|
||||
.unwrap()
|
||||
.expect("brand-new edge should produce a map");
|
||||
assert_eq!(next.get("dora"), Some(&Some("alice".to_owned())));
|
||||
// existing entries untouched.
|
||||
assert_eq!(next.get("bob"), Some(&Some("alice".to_owned())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_add_child_is_idempotent_when_edge_exists() {
|
||||
// bob already under alice — re-init returns a no-op (None).
|
||||
assert!(
|
||||
apply_add_child(&topo_three_level(), "bob", "alice")
|
||||
.unwrap()
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_add_child_refuses_unknown_parent() {
|
||||
let err = apply_add_child(&topo_three_level(), "dora", "nobody").unwrap_err();
|
||||
assert!(err.contains("unknown parent"), "err = {err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_add_child_refuses_name_owned_by_other_parent() {
|
||||
// bob lives under alice; the manager can't claim it via add_child.
|
||||
let err = apply_add_child(&topo_three_level(), "bob", crate::lifecycle::MANAGER_NAME)
|
||||
.unwrap_err();
|
||||
assert!(err.contains("already exists"), "err = {err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_reconcile_adds_missing_live_agent_as_root() {
|
||||
// A live agent with no prior topology entry defaults to root
|
||||
|
|
@ -696,7 +610,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn apply_reconcile_keeps_pending_init_agent_edge() {
|
||||
// `dora` was init'd under alice (edge present) but has no
|
||||
// `dora` was placed under alice (edge present) but has no
|
||||
// container yet, so it's absent from the live set. It must NOT
|
||||
// be dropped, and its alice-parent edge must be preserved (not
|
||||
// re-seeded under the manager).
|
||||
|
|
|
|||
Loading…
Reference in a new issue