Repository navigation
sandboxd: a persistent cordon and one admission model - #476
Merged
Merged
Conversation
…ves in POST/DELETE /v1/cordon keep a node out of service across restarts through the marker file <data_dir>/cordoned. A cordoned node refuses claims, forks and checkpoint claims, gossips no pools, parks refill and adopts no other node's archived claims, while its own claims keep serving and a root live move in is admitted under the usual caps. Drain stays transient and still refuses moves in; the pool method that lifts it is now Undrain. Refill now parks a closed node instead of returning early, so a pool removed while a clone was in flight is still dropped on a drained or cordoned node.
Uncordon sent DELETE /v1/drain; it now sends DELETE /v1/cordon, and Undrain lifts a drain. A caller that still pairs Drain with Uncordon leaves the node drained, which Info reports, rather than opening a node it meant to keep closed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #475. Adds a persistent per-node cordon next to the transient drain, documents the admission model as one table, and renames the SDK verbs so each one names a single hold.
Answers to #475
docs/cluster.md#node-admission, with five states (serving, cordoned, draining, draining withevacuate=1, cordoned and draining) against the six questions.sandboxd-api.mdlinks to it instead of repeating it.cordonedis new.<data_dir>/cordoned.node cordoned.move_concurrency.drainingkeeps its meaning: transient, refuses moves in. The two states are independent, and eachDELETElifts only its own.0or omitted stays "no cap"; to take nothing, cordon the node. Changing what0means would touch every deployed config. The table and themax_claimsrow indeploy.mdsay so. Open to overrule.Drain,Undrain,Cordon,Uncordon. See the decision below.max_claims, which is documented incluster.md.max_runningbinds at the wake. A cordoned or draining node never adopts.SDK verb decision (for CMGS)
Uncordon(Go) anduncordon()(Python) used to sendDELETE /v1/drain. They now sendDELETE /v1/cordon; the newUndrain/undrain()sendsDELETE /v1/drain.#475 asks for renaming "without breaking callers", and this is a behaviour change for an existing call. I chose it because it fails closed:
DrainwithUncordonleaves the node drained. The response andInforeportdraining: true.Uncordonlifting both holds. That would silently stop a running evacuation whenever someone lifts a cordon.Release note text:
Design
Manager.cordonedsits next todraining, both underm.mu.Cordonwrites the marker withutils.WriteFileSync, then sets the flag.Uncordonremoves the marker and syncs the dir, then clears the flag.cordonMuorders the two writers.NewManagerstats the file beforeRun, so a node that boots cordoned never starts refill or a golden build.quotaErrrefuses on the cordon and delegates tocapacityErr. That covers claim, fork, checkpoint claim, the fork re-check andWarmCountsgossip.admitMoveLockedcallscapacityErr;CommitMovestill checks onlydraining.closedLocked()(draining or cordoned).adoptArchivedrefuses when cordoned, after theheldcase, so the node keeps re-adopting its own rows.m.muthatquotaErr,WarmCountsandrefillOncealready hold. No allocation, no new lock, no I/O. File I/O happens only on the two endpoints and once at boot.SetPoolswhile a clone was in flight is therefore dropped on a drained or cordoned node too. Before this, it lingered until the node opened, which under a days-long cordon has no bound.Manager.Uncordon(which lifted a drain) is nowUndrain.sandboxd_cordoned; thesandboxd_draininghelp text no longer says "cordoned".Tests
New pool tests:
TestCordonRefusesClaimsTrimsWarmAndSurvivesARestartTestACloneInFlightAtCordonIsNotKeptTestACordonedNodeStillDropsAPoolRemovedMidCloneTestCordonRefusesForksAndCheckpointClaimsTestACordonedNodeKeepsServingItsOwnClaimsTestACordonedNodeNeverAdoptsButKeepsItsOwnRowAcrossARestartTestAMoveLandsOnACordonedNodeTestCordonOutlivesAReloadAndAnUndrainTestCordonIsAuditedServer tests:
TestCordonEndpointsTestCordonPersistFailureAnswers500AndKeepsStateSDK tests:
TestDrainCordonVerbstest_node_hold_verbs_hit_their_routesMutation controls: each check site was broken one at a time, and a test failed for every one:
capacityErrin move-inloadCordonquotaErrheldGates
GOWORK=off make go-lint: 10 of 100 issues.(5 modules × linux/darwin),fmt --diffempty.asl -forwarder=false ./...clean for sandboxd and sdk/go on linux and darwin.go test -racegreen for sandboxd and sdk/go.ruff format --check,ruff checkclean;pytest277 passed.Hardware
One test host, NUMA node 1. Two sandboxd nodes (a, b) built from 6a7241a, with cocoon v0.7.8 and CH dev acded4b0, a kit Postgres meta-store cell, and an encrypted mesh. Each node ran in its own mount namespace with its root bound at the same path, because live moves need identical
root_dir/run_dirstrings. Pools:rt:24.04none/small, warm 2. Excerpt:b's log over the cordoned restart window holds only startup, reconcile and mesh join, with no refill or golden build. The host was restored to its baseline afterwards (no kit processes, netns, slice or files left).