swarm UI: an alerts page, read by the controller with a Viewer Grafana token from bao
swarm-bao-grafana-controller-token, on the host that runs Grafana, logs in to Grafana's API over its socket as the built-in admin (the password swarm-bao-grafana-admin minted, #5138) and keeps a `swarm-controller` service account that is an enabled Viewer. It mints a token for that account and writes it to bao at swarm/controller/swarm-controller/grafana/token under Grafana's leaf. A ten-minute timer runs it again. The unit keeps a stored token Grafana accepts. If Grafana refuses the stored token with 401, or bao holds none, the unit deletes every token of the account and mints a new one. Grafana's grant gains create/read/update on that leaf, and the controller's gains read. swarm-controller serves GET /api/alerts from Grafana's /api/prometheus/grafana/api/v1/alerts. It reads the token from bao, keeps it in memory, and re-reads bao once on a 401. The HTTP client has 5s connect and 15s request timeouts. Any failure is a 503 that names its cause. swarm-ui gets an /alerts page listing them, built the same way as the hives page. This is option (c) on #5129, the operator's choice.
This commit is contained in:
parent
8cb6273782
commit
7d09776742
23 changed files with 888 additions and 37 deletions
|
|
@ -50,6 +50,7 @@ mod agent_login;
|
|||
mod agent_renewal;
|
||||
mod agent_state_stream;
|
||||
mod agent_status;
|
||||
mod alerts;
|
||||
mod auth;
|
||||
mod builder;
|
||||
mod claude_login;
|
||||
|
|
@ -839,6 +840,7 @@ fn socket_path() -> PathBuf {
|
|||
(name = "schedules", description = "scheduled prompts (`swarmctl schedule`)"),
|
||||
(name = "review-classifier", description = "trying review classifications against a PR (swarm-ui's try-out page), and the classifier's swarm-wide settings"),
|
||||
(name = "pulls", description = "open pull requests, for the try-out page's dropdowns"),
|
||||
(name = "alerts", description = "the swarm Grafana's current alerts (swarm-ui's alerts page)"),
|
||||
)
|
||||
)]
|
||||
struct ApiDoc;
|
||||
|
|
@ -972,6 +974,9 @@ struct AppState {
|
|||
reviews: Arc<review_classifier::review::Reviews>,
|
||||
/// The review classifier's finished runs.
|
||||
runs: review_classifier::runs::Runs,
|
||||
/// Grafana's alerts API, for `GET /api/alerts`. `None` when no Grafana URL
|
||||
/// is configured.
|
||||
alerts: Option<Arc<alerts::Grafana>>,
|
||||
}
|
||||
|
||||
/// Env var the controller's NixOS module sets from
|
||||
|
|
@ -3451,6 +3456,7 @@ async fn main() -> Result<()> {
|
|||
try_outs: review_classifier::TryOuts::default(),
|
||||
reviews: Arc::default(),
|
||||
runs,
|
||||
alerts: alerts::from_env(),
|
||||
};
|
||||
|
||||
let app = build_app(state);
|
||||
|
|
@ -3468,6 +3474,7 @@ async fn main() -> Result<()> {
|
|||
fn build_app(state: AppState) -> axum::Router {
|
||||
let (router, api) = OpenApiRouter::<AppState>::with_openapi(ApiDoc::openapi())
|
||||
.routes(routes!(health))
|
||||
.routes(routes!(alerts::get_alerts))
|
||||
.routes(routes!(get_hives))
|
||||
.routes(routes!(get_hives_status))
|
||||
.routes(routes!(get_links))
|
||||
|
|
@ -3660,6 +3667,7 @@ mod tests {
|
|||
try_outs: super::review_classifier::TryOuts::default(),
|
||||
reviews: std::sync::Arc::default(),
|
||||
runs: super::review_classifier::runs::Runs::Live(None),
|
||||
alerts: None,
|
||||
};
|
||||
(state, sched)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue