swarm-controller: split main.rs into jobq, routes and startup modules
no behaviour change: a pure move of items and tests into new modules, plus visibility edits (pub(crate)) and path updates in sibling modules that named crate-root items. same routes, same OpenAPI, 561 tests before and after. why: #5470, new features stop landing in one 6.4k-line file by default. files outside swarm-controller/src: docs/agent-lifecycle/agent-roster.md, swarm-ui JobsPage.tsx and AgentsPage.tsx, nix/host-modules/swarm-controller.nix and swarm-grafana.nix hold comments that named main.rs for items that moved.
This commit is contained in:
parent
f0a6d6c042
commit
738dd1c95b
42 changed files with 6854 additions and 6680 deletions
81
swarm-controller/src/routes/config_prs.rs
Normal file
81
swarm-controller/src/routes/config_prs.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
//! Agents' open config PRs.
|
||||
|
||||
use anyhow::Result;
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
};
|
||||
|
||||
use crate::forge;
|
||||
use crate::routes::{AppState, StatusUnavailable};
|
||||
|
||||
/// `agent`'s open config PR, from [`ConfigPrCache`](crate::config_pr::ConfigPrCache) — kept
|
||||
/// current by a webhook nudge (near-real-time) backstopped by a periodic
|
||||
/// scan (worst case: up to one `config_pr::POLL_INTERVAL` stale if a
|
||||
/// delivery was ever missed). Not a live forge read either way, so this
|
||||
/// answers even when the forge itself is momentarily unreachable.
|
||||
///
|
||||
/// `200` with a `null` body means "no open PR" (or "no scan has completed
|
||||
/// yet") — not distinguished, for the same reason
|
||||
/// [`ConfigPrCache::get`](crate::config_pr::ConfigPrCache::get) doesn't: both read as "nothing to show"
|
||||
/// to the swarm-ui config-PR panel this feeds, and a cache is a best-effort
|
||||
/// read, not a source of truth callers should expect to disambiguate
|
||||
/// against.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/agents/{name}/config-pr",
|
||||
params(("name" = String, Path, description = "agent name")),
|
||||
responses(
|
||||
(status = 200, description = "the agent's open config PR, or null if none / not scanned yet", body = Option<forge::ConfigPrStatus>),
|
||||
(status = 503, description = "no forge is configured on this host", body = String),
|
||||
),
|
||||
tag = "agents"
|
||||
)]
|
||||
pub(crate) async fn get_agent_config_pr(
|
||||
State(state): State<AppState>,
|
||||
Path(name): Path<String>,
|
||||
) -> Result<Json<Option<forge::ConfigPrStatus>>, StatusUnavailable> {
|
||||
let Some(cache) = state.config_prs.get() else {
|
||||
return Err(StatusUnavailable(
|
||||
"no forge is configured on this host".to_owned(),
|
||||
));
|
||||
};
|
||||
Ok(Json(cache.get(&name)))
|
||||
}
|
||||
|
||||
/// Every agent with an open config PR, in one response — the bulk
|
||||
/// counterpart to [`get_agent_config_pr`]. swarm-ui's config-PR table needs
|
||||
/// every agent's status to render, and fetching them one at a time doesn't
|
||||
/// scale and isn't how the rest of swarm-ui's single-fetch pages (jobq,
|
||||
/// hives status) work.
|
||||
///
|
||||
/// Deliberately **not** `/api/agents/config-prs`: agent names are
|
||||
/// user-specified (any string `hive_types::Ident` accepts), so a literal
|
||||
/// path segment sitting where a `{name}` capture could plausibly also want
|
||||
/// to live is a real, not theoretical, clash risk the moment someone names
|
||||
/// an agent `config-prs` — per mara's review call, closed off by
|
||||
/// construction rather than relying on axum's static-route-priority
|
||||
/// tiebreak to paper over it.
|
||||
///
|
||||
/// Only agents with a currently-open PR are present — same "absence is the
|
||||
/// answer" shape [`get_agent_config_pr`]'s `null` uses, just at map-entry
|
||||
/// granularity instead of per-request.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/config-prs",
|
||||
responses(
|
||||
(status = 200, description = "agent name -> open config PR, only agents with one present", body = std::collections::HashMap<String, forge::ConfigPrStatus>),
|
||||
(status = 503, description = "no forge is configured on this host", body = String),
|
||||
),
|
||||
tag = "agents"
|
||||
)]
|
||||
pub(crate) async fn get_config_prs(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<std::collections::HashMap<String, forge::ConfigPrStatus>>, StatusUnavailable> {
|
||||
let Some(cache) = state.config_prs.get() else {
|
||||
return Err(StatusUnavailable(
|
||||
"no forge is configured on this host".to_owned(),
|
||||
));
|
||||
};
|
||||
Ok(Json(cache.snapshot()))
|
||||
}
|
||||
Loading…
Reference in a new issue