dashboard: deployed sha chip per container
ContainerView grows deployed_sha (first 12 chars of the rev that /var/lib/hyperhive/meta/flake.lock currently has locked for agent-<name>). renderContainers appends a 'deployed:<sha12>' chip next to the container name + port — title attribute explains it's the meta-lock sha. degrades gracefully when the meta repo isn't seeded yet (missing / unparsable lock = empty map = no chip). new read_meta_locked_revs helper does the JSON parsing without unwraps.
This commit is contained in:
parent
691057d2d3
commit
2f6ecc4dc0
2 changed files with 43 additions and 0 deletions
|
|
@ -187,6 +187,12 @@ struct ContainerView {
|
|||
/// disable other buttons.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pending: Option<&'static str>,
|
||||
/// First 12 chars of the sha the meta flake currently has locked
|
||||
/// for this agent's input. Reflects what's actually deployed; can
|
||||
/// differ from `applied/<n>/main` only between
|
||||
/// `meta::prepare_deploy` and `finalize_deploy` (≤ build duration).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
deployed_sha: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
@ -281,6 +287,7 @@ async fn build_container_views(
|
|||
) -> (Vec<ContainerView>, bool) {
|
||||
let mut out = Vec::new();
|
||||
let mut any_stale = false;
|
||||
let locked = read_meta_locked_revs();
|
||||
for c in raw_containers {
|
||||
let (logical, is_manager) = if c == MANAGER_NAME {
|
||||
(MANAGER_NAME.to_owned(), true)
|
||||
|
|
@ -299,6 +306,9 @@ async fn build_container_views(
|
|||
let pending = transient_snapshot
|
||||
.get(&logical)
|
||||
.map(|st| transient_label(st.kind));
|
||||
let deployed_sha = locked
|
||||
.get(&format!("agent-{logical}"))
|
||||
.map(|s| s[..s.len().min(12)].to_owned());
|
||||
out.push(ContainerView {
|
||||
port: lifecycle::agent_web_port(&logical),
|
||||
running: lifecycle::is_running(&logical).await,
|
||||
|
|
@ -308,11 +318,39 @@ async fn build_container_views(
|
|||
needs_update,
|
||||
needs_login,
|
||||
pending,
|
||||
deployed_sha,
|
||||
});
|
||||
}
|
||||
(out, any_stale)
|
||||
}
|
||||
|
||||
/// Parse `/var/lib/hyperhive/meta/flake.lock` into a map of node name
|
||||
/// (`agent-<n>`, `hyperhive`) → locked sha. Missing / unparsable lock
|
||||
/// yields an empty map so the dashboard degrades gracefully when the
|
||||
/// meta repo hasn't been seeded yet.
|
||||
fn read_meta_locked_revs() -> std::collections::HashMap<String, String> {
|
||||
let mut out = std::collections::HashMap::new();
|
||||
let Ok(raw) = std::fs::read_to_string("/var/lib/hyperhive/meta/flake.lock") else {
|
||||
return out;
|
||||
};
|
||||
let Ok(json) = serde_json::from_str::<serde_json::Value>(&raw) else {
|
||||
return out;
|
||||
};
|
||||
let Some(nodes) = json.get("nodes").and_then(|v| v.as_object()) else {
|
||||
return out;
|
||||
};
|
||||
for (name, node) in nodes {
|
||||
if let Some(rev) = node
|
||||
.get("locked")
|
||||
.and_then(|v| v.get("rev"))
|
||||
.and_then(|v| v.as_str())
|
||||
{
|
||||
out.insert(name.clone(), rev.to_owned());
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Transient state for agents whose container does NOT yet exist
|
||||
/// (`Spawning`). Lifecycle ops on existing containers surface as
|
||||
/// `ContainerView.pending` inline; this list only catches pre-creation.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue