Watch
0
0
Fork
You've already forked hyperhive
0

hive-c0re: the per-agent resource limit override is gone

The hive no longer sets an agent's CPU or memory cap: caps come from the swarm, else the hive-wide defaults. The container load tab was the only hive UI that set them, and its figures are already exported as OTEL metrics, so with the tab gone nothing wrote meta/resource-limits.json.

Removed: the file's reader and writer, the `hivectl agent set-limits` verb with its host-socket request, the `GET /api/container-resources` and `POST /api/resource-limits/{name}` dashboard endpoints, and the `cpu_quota`/`memory_max` fields of the container view that only the tab read. A leftover resource-limits.json is ignored.
This commit is contained in:
iris 2026-10-14 23:57:55 +02:00 • committed by mara
commit 90e33cbd19
19 changed files with 161 additions and 828 deletions

View file

@ -3,7 +3,7 @@
//! swarm-controller keeps one key per agent in the `agent-limits` bucket
//! ([`swarm_queue_client::agent_limits`]). Every [`READ_INTERVAL`] this reads
//! the key of each agent this hive has and stores what it finds in
//! `swarm-resource-limits.json`, where the drop-in and the dashboard read it.
//! `swarm-resource-limits.json`, where the drop-in reads it.
//! A running agent gets a changed cap at its first spawn or rebuild after
//! that read.
//!
@ -92,9 +92,9 @@ async fn sync(client: &async_nats::Client) -> Result<()> {
/// The caps to store for `declared`, by agent. An agent with no field set
/// gets no entry.
///
/// Every value goes through the validators the operator's own input path
/// uses, because it is rendered verbatim into the container's systemd
/// drop-in. One bad value refuses the whole set.
/// Every value goes through the `resource_limits` validators, because it is
/// rendered verbatim into the container's systemd drop-in. One bad value
/// refuses the whole set.
fn validated(declared: &BTreeMap<String, AgentCaps>) -> Result<BTreeMap<String, AgentLimits>> {
let mut out = BTreeMap::new();
for (agent, caps) in declared {
@ -127,48 +127,38 @@ mod tests {
use std::collections::BTreeMap;
use super::validated;
use crate::resource_limits::AgentLimits;
use swarm_queue_client::agent_limits::AgentCaps;
/// `atlas`'s answer with `atlas_key` as the value read for it, over a hive
/// chain that caps it at 800% / 16G.
/// `atlas`'s answer with `atlas_key` as the value read for it, over the
/// hive-wide defaults of 200% / 4G.
fn atlas_with(atlas_key: &str) -> (String, String) {
let declared = BTreeMap::from([(
"atlas".to_owned(),
serde_json::from_str::<AgentCaps>(atlas_key).expect("decodes"),
)]);
let stored = validated(&declared).expect("valid caps");
let hive_side = BTreeMap::from([(
"atlas".to_owned(),
AgentLimits {
cpu_quota: Some("800%".to_owned()),
memory_max: Some("16G".to_owned()),
},
)]);
crate::resource_limits::effective_from_with_swarm(
&stored, &hive_side, "atlas", "200%", "4G",
)
crate::resource_limits::effective_from(&stored, "atlas", "200%", "4G")
}
/// The other half of swarm-controller's
/// `agent_limits::the_route_writes_the_caps_a_hive_reads_and_delete_clears_them`:
/// the first value is the bytes that route stores. The cap replaces the
/// hive's chain; a deleted key reads as `{}` and gives the chain back.
/// hive default; a deleted key reads as `{}` and gives the default back.
#[test]
fn the_caps_the_route_stores_replace_the_hive_chain_and_a_cleared_key_restores_it() {
fn the_caps_the_route_stores_replace_the_hive_default_and_a_cleared_key_restores_it() {
assert_eq!(
atlas_with(r#"{"cpu_quota":"400%","memory_max":"8G"}"#),
("400%".to_owned(), "8G".to_owned())
);
assert_eq!(atlas_with("{}"), ("800%".to_owned(), "16G".to_owned()));
assert_eq!(atlas_with("{}"), ("200%".to_owned(), "4G".to_owned()));
}
/// Per field: a swarm memory cap leaves CPU on the hive's chain.
/// Per field: a swarm memory cap leaves CPU on the hive default.
#[test]
fn a_field_the_swarm_leaves_unset_stays_with_the_hive() {
assert_eq!(
atlas_with(r#"{"memory_max":"2G"}"#),
("800%".to_owned(), "2G".to_owned())
("200%".to_owned(), "2G".to_owned())
);
}