hive-c0re: fail on an unparseable resource-limits or topology file, write both atomically
resource-limits.json and topology.json were read with parse errors folded into an empty map, and written in place with std::fs::write. One truncated resource-limits.json followed by a single set_limits call rewrote the file with only that agent's entry, erasing every other agent's CPU and memory overrides without a log line. topology.json had the same shape: reconcile rebuilt it from the live set, losing pending (provisioned, never spawned) names. - agent_config::read_map / write_map are generic over the stored type. tool-groups and capabilities behave as before. - resource_limits::read / effective return an error for an existing but unreadable file; a missing file is still the empty map. set_limits fails without writing on such a file, and writes atomically. - topology: reconcile fails without writing on an unreadable file and writes atomically. all_agents logs the error and returns no agents, so a ManageRootAgent holder starts without cross-agent mounts. Read-path behaviour on an unreadable resource-limits.json, per caller: - write_dropins (every spawn / swap / WriteDropin): logs the error and keeps the limits drop-in already under /run; the agent still starts. With no drop-in yet (first start since boot) it writes the hive defaults, because no drop-in means an uncapped container. - render_flake: propagates, so sync_agents (and spawn/rebuild/destroy jobs) fail. An empty map would give tighter-capped agents the hive memoryMaxBytes. - container_view::build_all: logs the error each scan and renders the rows at the hive defaults (no ContainerView wire change). - set_resource_limits reply: propagates. Closes #4731
This commit is contained in:
parent
97cf8a1b2b
commit
6fac00dcc5
8 changed files with 332 additions and 119 deletions
|
|
@ -88,7 +88,7 @@ fn set_groups_at(path: &Path, name: &str, groups: &[String]) -> anyhow::Result<(
|
|||
if !groups.is_empty() {
|
||||
validate_groups(groups)?;
|
||||
}
|
||||
let mut current = super::read_map(path)?;
|
||||
let mut current: BTreeMap<String, Vec<String>> = super::read_map(path)?;
|
||||
if groups.is_empty() {
|
||||
current.remove(name);
|
||||
} else {
|
||||
|
|
@ -104,7 +104,7 @@ pub fn remove_agent(name: &str) -> std::io::Result<()> {
|
|||
}
|
||||
|
||||
fn remove_agent_at(path: &Path, name: &str) -> std::io::Result<()> {
|
||||
let mut current = super::read_map(path)?;
|
||||
let mut current: BTreeMap<String, Vec<String>> = super::read_map(path)?;
|
||||
if current.remove(name).is_some() {
|
||||
super::write_map(path, ¤t)?;
|
||||
}
|
||||
|
|
@ -151,7 +151,8 @@ mod tests {
|
|||
let path = dir.path().join(TOOL_GROUPS_FILE);
|
||||
set_groups_at(&path, "alice", &["inbox".to_owned()]).expect("set on missing file");
|
||||
set_groups_at(&path, "ruth", &["messaging".to_owned()]).expect("set");
|
||||
let map = crate::agent_config::read_map(&path).expect("read");
|
||||
let map: BTreeMap<String, Vec<String>> =
|
||||
crate::agent_config::read_map(&path).expect("read");
|
||||
assert_eq!(map["alice"], vec!["inbox".to_owned()]);
|
||||
assert_eq!(map["ruth"], vec!["messaging".to_owned()]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue