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:
parent
a2540be98b
commit
90e33cbd19
19 changed files with 161 additions and 828 deletions
|
|
@ -76,16 +76,6 @@ pub struct ContainerView {
|
|||
/// a legitimate way to keep it idle when it next boots.
|
||||
#[serde(default)]
|
||||
pub paused: bool,
|
||||
/// Effective systemd `CPUQuota=` for this container (e.g. `"400%"`) —
|
||||
/// the per-agent override from `meta/resource-limits.json` when set,
|
||||
/// otherwise the hive-wide `agentCpuQuota`. Always populated: there
|
||||
/// is no "unset" state to render, only "same as everyone else".
|
||||
/// Reflects what the *drop-in says*, which is what the next start
|
||||
/// will enforce — not a live cgroup reading.
|
||||
pub cpu_quota: String,
|
||||
/// Effective systemd `MemoryMax=` for this container (e.g. `"8G"`).
|
||||
/// Same resolution + caveat as [`ContainerView::cpu_quota`].
|
||||
pub memory_max: String,
|
||||
}
|
||||
|
||||
impl From<ContainerView> for hive_sh4re::container::AgentStatusRow {
|
||||
|
|
@ -99,10 +89,9 @@ impl From<ContainerView> for hive_sh4re::container::AgentStatusRow {
|
|||
/// anymore. Stubbed to `0` rather than dropping the wire field
|
||||
/// outright — leaves `hivectl status`/the dashboard column intact
|
||||
/// syntactically, just always empty, until iris's frontend follow-up
|
||||
/// decides whether to drop the column entirely. `port`, `cpu_quota`,
|
||||
/// `memory_max` have no equivalent on the row at all and are simply
|
||||
/// not carried over. `url` has no source on `ContainerView` at all —
|
||||
/// see [`agent_url`].
|
||||
/// decides whether to drop the column entirely. `port` has no
|
||||
/// equivalent on the row at all and is simply not carried over. `url`
|
||||
/// has no source on `ContainerView` at all — see [`agent_url`].
|
||||
fn from(v: ContainerView) -> Self {
|
||||
Self {
|
||||
url: agent_url(&v.name),
|
||||
|
|
@ -148,37 +137,12 @@ fn agent_url_for_domain(domain: &str, name: &str) -> String {
|
|||
/// Build the full container list. Wraps `lifecycle::list()` and
|
||||
/// resolves every per-agent attribute the dashboard surfaces.
|
||||
///
|
||||
/// Takes `hive` because the effective resource limits are a per-field
|
||||
/// fallback onto the hive-wide `agent_cpu_quota` / `agent_memory_max`,
|
||||
/// and those live on [`crate::coordinator::HiveEnv`], not on disk. Both callers already
|
||||
/// hold a `Coordinator`, so this is a parameter rather than a global.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// The container list could not be read.
|
||||
pub async fn build_all(hive: &crate::coordinator::HiveEnv) -> anyhow::Result<Vec<ContainerView>> {
|
||||
pub async fn build_all() -> anyhow::Result<Vec<ContainerView>> {
|
||||
let raw = lifecycle::list().await?;
|
||||
let locked = read_meta_locked_revs();
|
||||
// Read once per scan rather than re-read for every container on every
|
||||
// SSE scan. An unreadable file shows every row at the hive defaults;
|
||||
// the error log is the only signal, as `ContainerView` has no field
|
||||
// to carry it.
|
||||
let limits = crate::resource_limits::read().unwrap_or_else(|e| {
|
||||
tracing::error!(
|
||||
path = %crate::resource_limits::resource_limits_path().display(),
|
||||
error = ?e,
|
||||
"resource limits unreadable — container rows show hive defaults"
|
||||
);
|
||||
std::collections::BTreeMap::new()
|
||||
});
|
||||
let swarm_limits = crate::resource_limits::read_swarm().unwrap_or_else(|e| {
|
||||
tracing::error!(
|
||||
path = %crate::resource_limits::swarm_limits_path().display(),
|
||||
error = ?e,
|
||||
"swarm resource caps unreadable — container rows ignore them"
|
||||
);
|
||||
std::collections::BTreeMap::new()
|
||||
});
|
||||
let mut out = Vec::new();
|
||||
for c in &raw {
|
||||
let Some(logical) = c.strip_prefix(AGENT_PREFIX) else {
|
||||
|
|
@ -243,13 +207,6 @@ pub async fn build_all(hive: &crate::coordinator::HiveEnv) -> anyhow::Result<Vec
|
|||
(None, None)
|
||||
};
|
||||
let paused = Coordinator::is_paused(&logical);
|
||||
let (cpu_quota, memory_max) = crate::resource_limits::effective_from_with_swarm(
|
||||
&swarm_limits,
|
||||
&limits,
|
||||
logical.as_str(),
|
||||
&hive.agent_cpu_quota,
|
||||
&hive.agent_memory_max,
|
||||
);
|
||||
out.push(ContainerView {
|
||||
port: lifecycle::agent_web_port(logical.as_str()),
|
||||
running,
|
||||
|
|
@ -263,8 +220,6 @@ pub async fn build_all(hive: &crate::coordinator::HiveEnv) -> anyhow::Result<Vec
|
|||
status_text,
|
||||
status_set_at,
|
||||
paused,
|
||||
cpu_quota,
|
||||
memory_max,
|
||||
});
|
||||
}
|
||||
Ok(out)
|
||||
|
|
@ -570,9 +525,8 @@ mod tests {
|
|||
|
||||
/// The `From` impl both `handle_agent_status`'s poll path and
|
||||
/// `stream_agent_status`'s push path go through — pins the field
|
||||
/// mapping so the two can't quietly diverge, and that `port` /
|
||||
/// `cpu_quota` / `memory_max` (no equivalent on the row) are dropped
|
||||
/// on purpose rather than by omission.
|
||||
/// mapping so the two can't quietly diverge, and that `port` (no
|
||||
/// equivalent on the row) is dropped on purpose rather than by omission.
|
||||
#[test]
|
||||
fn agent_status_row_carries_every_field_the_row_has_and_drops_the_rest() {
|
||||
use super::ContainerView;
|
||||
|
|
@ -592,8 +546,6 @@ mod tests {
|
|||
status_text: Some("shipping".to_owned()),
|
||||
status_set_at: Some(Utc.timestamp_opt(1_700_000_000, 0).unwrap()),
|
||||
paused: true,
|
||||
cpu_quota: "400%".to_owned(),
|
||||
memory_max: "8G".to_owned(),
|
||||
};
|
||||
|
||||
let row = AgentStatusRow::from(view);
|
||||
|
|
|
|||
Loading…
Reference in a new issue