config PRs: remove the hive's config-PR webhook, poll and core merge
An operator's merge on the forge deploys a config PR through
swarm-controller's DeployRequest{rev}. The hive-side path that queued a
MergeConfigPr approval and merged the PR as `core` goes:
- the `/webhook/config-pr` receiver, its HMAC secret, the WebhookRegister
boot node and the org-hook registration; the hive vhost's `/webhook/`
location
- the 5-minute config-PR poll
- ApprovalKind::MergeConfigPr, its dashboard card, and the deploy DAG it
drove (DeployWindow, MergeVerify, DeployApply, FinalizeDeploy,
DeployTail), with verify_commit, the two-phase meta deploy, rollback
refs, the PR-failure comment and forge/pr_merge.rs
- `fetched_sha`, `sha_short`/`pr_number` on approval events, and
`sha`/`tag` on HelperEvent::ApprovalResolved: only the merge path set
them
`config_repo`, `merged_pr_for_commit` and `post_pr_comment` move to
forge/pr_comment.rs for the merged-rev deploy's refusal comment.
Approvals v5 drops stored `merge_config_pr` rows; a test reopens a v4
database holding them.
Closes #4850
This commit is contained in:
parent
a5ea015bc6
commit
efbfec6d01
39 changed files with 286 additions and 3199 deletions
|
|
@ -6,7 +6,7 @@
|
|||
//! that already held the resource could get away with declaring nothing.
|
||||
//!
|
||||
//! **The one sanctioned exception is a brace** — a pure-resource-holder root
|
||||
//! ([`NodeKind::AgentWindow`], [`NodeKind::DeployWindow`]) declaring for a
|
||||
//! ([`NodeKind::AgentWindow`]) declaring for a
|
||||
//! coordinated subtree whose members then declare nothing. See
|
||||
//! `docs/scheduler/coordinator.md`, _Braces_ — which also carries the per-operation DAG
|
||||
//! shapes, so they are not restated here.
|
||||
|
|
@ -314,42 +314,6 @@ pub(crate) fn graceful_rebuild_nodes<'a>(
|
|||
rebuild_subtree(builder, agent, relock, true, after)
|
||||
}
|
||||
|
||||
/// The rebuild subgraph a [`NodeKind::DeployApply`] grows into its own DAG once
|
||||
/// the merge has landed and `prepare_deploy` has staged the lock, plus the
|
||||
/// [`NodeKind::FinalizeDeploy`] that closes the window behind it.
|
||||
///
|
||||
/// `relock = false` is the whole reason this composes: `prepare_deploy` already
|
||||
/// relocked and staged `flake.lock`, so the appended `MetaSync` must do the dir
|
||||
/// prep + `sync_agents` *without* re-locking over it.
|
||||
///
|
||||
/// `FinalizeDeploy` waits on **two** roots, which together reproduce the gate
|
||||
/// the old fused node had around its inline `rebuild_no_meta` call:
|
||||
/// - `AfterOk` `Prebuild` — a parent's state is its roll-up, so this is `Done`
|
||||
/// only once `StopForUpdate` → `Swap` → `RebuildBookkeeping` all are (a failed *or*
|
||||
/// cancelled child rolls the parent up `Failed`). That's the old
|
||||
/// `build_result`.
|
||||
/// - `AfterOk` `Reconcile` — the old call passed `deferred_start = false` on
|
||||
/// purpose: the container had to come back up *before* the deploy was
|
||||
/// finalized. `Reconcile` alone would not do, being `AfterAny` — it reaches
|
||||
/// `Done` even after a failed `Swap`.
|
||||
///
|
||||
/// Declared into a **running** `DeployApply`'s own builder, not submitted: the
|
||||
/// roots below become children of that node, which puts them inside the
|
||||
/// `DeployWindow`'s subtree — so the `MetaWindow` this subgraph's `MetaSync`
|
||||
/// and `FinalizeDeploy` declare is re-entered from the ancestor already holding
|
||||
/// it rather than deadlocking against it.
|
||||
pub(crate) fn deploy_rebuild_nodes(builder: &JobBuilder, agent: &str, approval_id: i64) {
|
||||
let roots = rebuild_nodes(builder, agent, false, None);
|
||||
let _finalize = builder
|
||||
.node(NodeKind::FinalizeDeploy {
|
||||
agent: agent.to_owned(),
|
||||
approval_id,
|
||||
})
|
||||
.needs(Resource::MetaWindow)
|
||||
.after_ok(roots.agent_window)
|
||||
.after_ok(roots.reconcile);
|
||||
}
|
||||
|
||||
/// One uniform rebuild shape — no `was_running` branch. `StopForUpdate`
|
||||
/// noops when already down; the tail `Reconcile` auto-noops the start
|
||||
/// when `wanted = Offline` (a rebuild of a deliberately-stopped agent
|
||||
|
|
@ -375,71 +339,6 @@ pub fn rebuild(builder: &JobBuilder, agent: &str, relock: bool) -> Vec<hive_jobq
|
|||
]
|
||||
}
|
||||
|
||||
/// Approval-driven deploy (`MergeConfigPr`) as a phase subtree rather than the
|
||||
/// single opaque node it used to be. Structure:
|
||||
/// - `DeployWindow` (**root**): the resource holder — global meta window, agent
|
||||
/// lease, build slot — held across every child below. No work of its own; it
|
||||
/// reaches `Finishing` immediately and the children run inside it.
|
||||
/// - `MergeVerify` (child): drift-gate + fetch + eval-verify. Mutates nothing,
|
||||
/// so a failure here cancel-cascades its siblings with the forge and the
|
||||
/// applied repo exactly as they were.
|
||||
/// - `DeployApply` (child, `AfterOk` `MergeVerify`): the irreversible half —
|
||||
/// ff-merge + `prepare_deploy`. It doesn't rebuild inline; it grows
|
||||
/// [`deploy_rebuild_nodes`] into this DAG as its own children, so the build
|
||||
/// and the closing `FinalizeDeploy` are real nodes under the same window.
|
||||
/// - `DeployTail` (child, `AfterAny` `DeployApply`): the compensation +
|
||||
/// bookkeeping tail — rollback when a merge landed unfinalized, forge tag
|
||||
/// mirror, PR failure comment (see [`NodeKind::DeployTail`]).
|
||||
///
|
||||
/// - `ResolveApproval` (**root**, `AfterAny` `DeployWindow`): resolves the
|
||||
/// approval row. A root rather than another child, so it isn't inside the
|
||||
/// window's resource subtree — it runs once the window has released the meta
|
||||
/// window, lease and build slot. One edge suffices here: `DeployWindow` is the
|
||||
/// DAG's only other group-root, so its roll-up already *is* the whole
|
||||
/// pipeline's outcome.
|
||||
///
|
||||
/// The window still spans the container build, as it must: `prepare_deploy`
|
||||
/// leaves `flake.lock` staged-uncommitted for the build's whole duration.
|
||||
pub fn approval_deploy(builder: &JobBuilder, agent: &str, approval_id: i64) {
|
||||
let a = || agent.to_owned();
|
||||
// The window is the widest holder in the tree: it brackets a nix
|
||||
// build (`BuildSlot`), takes the container down across the swap
|
||||
// (`Agent`), and serialises the meta mutation its subtree performs
|
||||
// (`MetaWindow`). All three are held for its whole subtree, which
|
||||
// is what lets the appended rebuild's `MetaSync` and the
|
||||
// `FinalizeDeploy` re-enter rather than contend.
|
||||
let window = builder
|
||||
.node(NodeKind::DeployWindow {
|
||||
agent: a(),
|
||||
approval_id,
|
||||
})
|
||||
.needs(Resource::BuildSlot)
|
||||
.needs(Resource::Agent(a()))
|
||||
.needs(Resource::MetaWindow);
|
||||
let verify = builder
|
||||
.node(NodeKind::MergeVerify {
|
||||
agent: a(),
|
||||
approval_id,
|
||||
})
|
||||
.part_of(window);
|
||||
let apply = builder
|
||||
.node(NodeKind::DeployApply {
|
||||
agent: a(),
|
||||
approval_id,
|
||||
})
|
||||
.part_of(window)
|
||||
.after_ok(verify);
|
||||
let _tail = builder
|
||||
.node(NodeKind::DeployTail {
|
||||
agent: a(),
|
||||
approval_id,
|
||||
})
|
||||
.part_of(window)
|
||||
.after_any(apply);
|
||||
|
||||
resolve_approval_tails(builder, approval_id, window);
|
||||
}
|
||||
|
||||
/// First deploy of an agent this hive has never seen, asked for by the swarm:
|
||||
/// `Provision` (proposed/applied repos, state subvolume, meta registration)
|
||||
/// then `Create` (`nixos-container create`), drop-in write, then `Reconcile`
|
||||
|
|
|
|||
Loading…
Reference in a new issue