build agents only from internal/meta; delete the hive's local meta flake
The hive no longer renders, locks or commits a meta flake. A rebuild's MetaSync node picks the internal/meta commit and records it with the hyperhive and config pins it holds; Prebuild, Swap and Create build from it, and a head that does not pin the agent's current config fails the build naming the agent. hive-priv's meta_rev is required. Removed: meta.rs sync/lock/render, the manual-rebuild relock, the boot sweep's hyperhive bump (MetaLock), the update-meta-inputs form and its panel, MetaWindow, the hive's hyperhive_rev setting. Kept: agent_set::refresh holds what sync_agents also did (topology.json, the gateway's agent-socket map and nginx include), called from spawn, destroy, rebuild and the migration. The boot reconcile and the stale-start upgrade compare the agent's marker with the hyperhive pin of internal/meta; the dashboard's deployed chip reads the config marker a successful build writes.
This commit is contained in:
parent
cea4827918
commit
4aa11b3a94
1 changed files with 1042 additions and 3793 deletions
|
|
@ -37,12 +37,8 @@ pub struct Coordinator {
|
|||
/// `build_logs.rs` for retention.
|
||||
pub build_logs: Arc<crate::build_logs::BuildLogs>,
|
||||
/// Store path of the hyperhive flake source (no fragment). Used to
|
||||
/// identify the running revision (`current_flake_rev`); the meta flake
|
||||
/// pins `hyperhive` by forge URL and [`Self::hyperhive_rev`] instead.
|
||||
/// identify the running revision (`current_flake_rev`).
|
||||
pub hyperhive_flake: String,
|
||||
/// Git rev of the hyperhive checkout this host runs. Pins the meta
|
||||
/// flake's `hyperhive` input; `None` makes the meta render fail.
|
||||
pub hyperhive_rev: Option<String>,
|
||||
/// Store path of the `claude-code` build every agent runs, handed to
|
||||
/// each container at start as `HYPERHIVE_CLAUDE_CODE_PATH`. Set by
|
||||
/// the NixOS module option
|
||||
|
|
@ -139,14 +135,7 @@ pub struct Coordinator {
|
|||
/// snapshot.
|
||||
dashboard_events: broadcast::Sender<DashboardEvent>,
|
||||
event_seq: AtomicU64,
|
||||
/// Count of dashboard-triggered `meta-update` runs currently in
|
||||
/// flight. `post_meta_update` returns 200 immediately and does the
|
||||
/// multi-minute `nix flake update` + agent-rebuild ripple in a
|
||||
/// background task, so without this the META INPUTS panel showed
|
||||
/// no sign anything was happening. Held via
|
||||
/// `MetaUpdateGuard`; a count > 0 surfaces on `/api/state` as
|
||||
/// `meta_update_running` and via the `MetaUpdateRunning` event.
|
||||
meta_updates_active: AtomicU64,
|
||||
|
||||
/// Last container snapshot seen by `rescan_containers_and_emit`,
|
||||
/// keyed by `ContainerView.name`. The rescan diffs a fresh
|
||||
/// `container_view::build_all` against this map and emits one
|
||||
|
|
@ -155,8 +144,8 @@ pub struct Coordinator {
|
|||
/// tokio mutex so the rescan can `await` `lifecycle::list` /
|
||||
/// `is_running` without blocking other coordinator paths.
|
||||
last_containers: tokio::sync::Mutex<HashMap<String, ContainerView>>,
|
||||
/// Global job-DAG queue. Every container/meta op (rebuild,
|
||||
/// meta-update, first-spawn, power changes) is submitted as a DAG
|
||||
/// Global job-DAG queue. Every container op (rebuild,
|
||||
/// first-spawn, power changes) is submitted as a DAG
|
||||
/// of primitive nodes; a single scheduler drives them with
|
||||
/// build-slot + per-agent-lease gating so the dashboard renders one
|
||||
/// ordered view of pending + running work. See `job_queue/` for
|
||||
|
|
@ -189,8 +178,6 @@ pub struct Coordinator {
|
|||
#[serde(default)]
|
||||
pub struct HiveEnv {
|
||||
pub hyperhive_flake: String,
|
||||
/// Git rev of the hyperhive checkout this host runs; see [`Coordinator::hyperhive_rev`].
|
||||
pub hyperhive_rev: Option<String>,
|
||||
/// Store path of the `claude-code` agents run, or `None` for "each
|
||||
/// agent keeps the one out of its own nixpkgs". Travels into the
|
||||
/// container as `HYPERHIVE_CLAUDE_CODE_PATH` — a plain string, kept
|
||||
|
|
@ -214,7 +201,6 @@ impl Default for HiveEnv {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
hyperhive_flake: "/etc/hyperhive".to_string(),
|
||||
hyperhive_rev: None,
|
||||
claude_code_path: None,
|
||||
dashboard_port: 7000,
|
||||
agent_cpu_quota: "200%".to_string(),
|
||||
|
|
@ -334,33 +320,6 @@ fn fold_tombstones_by_agent<'a>(
|
|||
out
|
||||
}
|
||||
|
||||
/// RAII guard for the `meta-update` in-progress flag, held for the
|
||||
/// duration of a `run_meta_update` background task. Created by
|
||||
/// `Coordinator::meta_update_guard`. Drop decrements the active-run
|
||||
/// count; the count crossing back to 0 emits
|
||||
/// `MetaUpdateRunning { running: false }`, so a concurrent pair of
|
||||
/// updates only flips the dashboard flag once.
|
||||
pub struct MetaUpdateGuard {
|
||||
coord: Arc<Coordinator>,
|
||||
}
|
||||
|
||||
impl Drop for MetaUpdateGuard {
|
||||
fn drop(&mut self) {
|
||||
if self
|
||||
.coord
|
||||
.meta_updates_active
|
||||
.fetch_sub(1, Ordering::SeqCst)
|
||||
== 1
|
||||
{
|
||||
self.coord
|
||||
.emit_dashboard_event(DashboardEvent::MetaUpdateRunning {
|
||||
seq: self.coord.next_seq(),
|
||||
running: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The two ways [`Coordinator::set_paused_by_name`] can fail. See its own
|
||||
/// doc comment for why this is a distinct type rather than one
|
||||
/// `anyhow::Error` (`Write` already wraps one, `BadName` never needs to).
|
||||
|
|
@ -390,7 +349,6 @@ impl Coordinator {
|
|||
) -> Result<Self> {
|
||||
let HiveEnv {
|
||||
hyperhive_flake,
|
||||
hyperhive_rev,
|
||||
claude_code_path,
|
||||
dashboard_port,
|
||||
agent_cpu_quota,
|
||||
|
|
@ -428,7 +386,6 @@ impl Coordinator {
|
|||
broker: Arc::new(broker),
|
||||
build_logs,
|
||||
hyperhive_flake,
|
||||
hyperhive_rev,
|
||||
claude_code_path,
|
||||
dashboard_port,
|
||||
agent_cpu_quota,
|
||||
|
|
@ -443,7 +400,7 @@ impl Coordinator {
|
|||
last_stopped_running: Mutex::new(None),
|
||||
dashboard_events,
|
||||
event_seq: AtomicU64::new(0),
|
||||
meta_updates_active: AtomicU64::new(0),
|
||||
|
||||
last_containers: tokio::sync::Mutex::new(HashMap::new()),
|
||||
job_queue: Arc::new(crate::job_queue::JobQueue::new(build_slots)),
|
||||
power,
|
||||
|
|
@ -452,13 +409,12 @@ impl Coordinator {
|
|||
}
|
||||
|
||||
/// Snapshot the hive-wide configuration fields as a [`HiveEnv`].
|
||||
/// Pass the result to `lifecycle::provision_container` / `rebuild` / `meta::sync_agents`
|
||||
/// Pass the result to `lifecycle::swap_update` / `write_dropins`
|
||||
/// instead of threading the individual fields separately.
|
||||
#[must_use]
|
||||
pub fn hive_env(&self) -> HiveEnv {
|
||||
HiveEnv {
|
||||
hyperhive_flake: self.hyperhive_flake.clone(),
|
||||
hyperhive_rev: self.hyperhive_rev.clone(),
|
||||
claude_code_path: self.claude_code_path.clone(),
|
||||
dashboard_port: self.dashboard_port,
|
||||
agent_cpu_quota: self.agent_cpu_quota.clone(),
|
||||
|
|
@ -553,31 +509,6 @@ impl Coordinator {
|
|||
let _ = self.dashboard_events.send(event);
|
||||
}
|
||||
|
||||
/// Mark a `meta-update` as in flight and return an RAII guard that
|
||||
/// clears it on drop (including drop-via-panic). The first
|
||||
/// concurrent run emits `MetaUpdateRunning { running: true }`; the
|
||||
/// last one to finish emits `running: false`. The dashboard's META
|
||||
/// INPUTS panel reads the flag to show a disabled "updating…"
|
||||
/// state while the lock bump + rebuild ripple runs.
|
||||
pub fn meta_update_guard(self: &Arc<Self>) -> MetaUpdateGuard {
|
||||
if self.meta_updates_active.fetch_add(1, Ordering::SeqCst) == 0 {
|
||||
self.emit_dashboard_event(DashboardEvent::MetaUpdateRunning {
|
||||
seq: self.next_seq(),
|
||||
running: true,
|
||||
});
|
||||
}
|
||||
MetaUpdateGuard {
|
||||
coord: Arc::clone(self),
|
||||
}
|
||||
}
|
||||
|
||||
/// True while at least one dashboard-triggered `meta-update` is
|
||||
/// running. Surfaced on `/api/state` as `meta_update_running` so a
|
||||
/// client that cold-loads mid-update sees the in-progress state.
|
||||
pub fn meta_update_in_progress(&self) -> bool {
|
||||
self.meta_updates_active.load(Ordering::SeqCst) > 0
|
||||
}
|
||||
|
||||
/// Rebuild the per-container snapshot, diff it against the last
|
||||
/// one cached on `self`, and emit one
|
||||
/// `DashboardEvent::ContainerStateChanged` per added/changed row
|
||||
|
|
@ -586,7 +517,7 @@ impl Coordinator {
|
|||
/// `nixos-container list` returns or what a row's
|
||||
/// `running` / `needs_update` / `needs_login` / `deployed_sha`
|
||||
/// resolves to — lifecycle ops, destroy,
|
||||
/// rebuild, meta-update, and the crash-watcher's periodic poll.
|
||||
/// rebuild, and the crash-watcher's periodic poll.
|
||||
/// Cheap when nothing changed (one `nixos-container list` + a
|
||||
/// `HashMap` diff + zero emits).
|
||||
pub async fn rescan_containers_and_emit(self: &Arc<Self>) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue