job_queue: add NodeKind::Reparent (topology moves as a queue node, #2719)

This commit is contained in:
damocles 2026-07-26 18:46:38 +02:00 committed by mara
commit 05b373474a
6 changed files with 177 additions and 5 deletions

View file

@ -186,6 +186,25 @@ pub enum NodeKind {
/// (commit fused under `META_LOCK`). The payload rides this node — the only
/// consumer — rather than the generic DAG container.
WritePermFile { agent: String, payload: PermPayload },
/// Topology move(s) — `set-parent` (len 1) or `set-parent-bulk` (len N) —
/// as a single queue node. Agentless like [`NodeKind::MetaLock`]: a
/// reparent touches the meta repo, not any one container, and a bulk
/// move spans multiple agents anyway. `needs_meta_window() = true`, same
/// precedent as [`NodeKind::WritePermFile`] (also a small
/// git-commit-under-`META_LOCK` op) — a reparent's commit must not land
/// inside another node's staged deploy `prepare_deploy`→`finalize_deploy`
/// window. `(child, new_parent)` pairs, applied in order under one
/// `META_LOCK` acquisition / one git commit (`meta::bulk_commit_topology`
/// handles both the single- and multi-move case uniformly).
#[allow(
dead_code,
reason = "constructed by templates::reparent(), landed ahead of the call-site swap \
(pending an answer on whether that swap should be synchronous or \
fire-and-forget) exercised today by job_queue::tests only"
)]
Reparent {
moves: Vec<(hive_types::Ident, Option<hive_types::Ident>)>,
},
/// Group root of the approval-deploy (`MergeConfigPr`) subtree, and the
/// node that **owns the deploy window**. It performs no work of its own —
/// it exists so the resources it declares (the global
@ -316,6 +335,7 @@ impl NodeKind {
NodeKind::Drain { .. } => "drain",
NodeKind::WriteDropin { .. } => "write_dropin",
NodeKind::WritePermFile { .. } => "write_perm_file",
NodeKind::Reparent { .. } => "reparent",
NodeKind::DeployWindow { .. } => "deploy_window",
NodeKind::MergeVerify { .. } => "merge_verify",
NodeKind::DeployApply { .. } => "deploy_apply",
@ -327,7 +347,8 @@ impl NodeKind {
}
/// The agent this node targets, or `""` for agentless kinds
/// ([`NodeKind::MetaLock`] on the `hyperhive` pseudo-agent, and the
/// ([`NodeKind::MetaLock`] on the `hyperhive` pseudo-agent,
/// [`NodeKind::Reparent`] which can span multiple agents, and the
/// [`NodeKind::Dag`] container).
#[must_use]
pub fn agent(&self) -> &str {
@ -352,7 +373,7 @@ impl NodeKind {
| NodeKind::FinalizeDeploy { agent }
| NodeKind::DeployTail { agent }
| NodeKind::SetWanted { agent, .. } => agent,
NodeKind::MetaLock { .. } | NodeKind::Dag { .. } => "",
NodeKind::MetaLock { .. } | NodeKind::Reparent { .. } | NodeKind::Dag { .. } => "",
}
}
@ -372,7 +393,7 @@ impl NodeKind {
/// Container-affecting kinds require the DAG to hold the agent's
/// lifecycle lease (acquired at the first such node, held until the
/// DAG is terminal). Lease-exempt kinds (`MetaSync`, `Prebuild`,
/// `Provision`, `MetaLock`, `WritePermFile`) touch the store / meta repo, not the
/// `Provision`, `MetaLock`, `WritePermFile`, `Reparent`) touch the store / meta repo, not the
/// running container — which is exactly why a `Prebuild` can overlap
/// another DAG's work on the same agent. `Provision` precedes the
/// container's existence entirely, so the lease is first taken at the
@ -425,6 +446,7 @@ impl NodeKind {
| NodeKind::Provision { .. }
| NodeKind::MetaLock { .. }
| NodeKind::WritePermFile { .. }
| NodeKind::Reparent { .. }
| NodeKind::DeployWindow { .. }
| NodeKind::FinalizeDeploy { .. }
)