Repository navigation
fix(masque): Keep a connector's /96 when its grant record fails - #1195
Conversation
grant create allocates the connector's /96 in the ledger before it writes the grant record. When that write failed, the ledger kept an entry no record pointed at. grant retire could not tombstone it, because Retire reads the record first, and a plain retry allocated a second /96. Each failure cost one of the ledger's 256 entries for good. Create now names the connector and its /96 when the record write fails, so creating the same connector again reuses that allocation. When the record already exists after a lost reply, the error says to rotate it. Retire tombstones the allocation of a connector that has no record by finding it in the authority's ledgers, then disables the record in case a racing create wrote one. Serving and refresh refuse a retired entry, so neither the stranded /96 nor a raced record serves after the retire. Refs #978
Add the M12 row to TestMASQUE. The probe client sends from four addresses in two /112 subdivisions of VPC 10's connector /96 to a workload on the compute node, a workload on the fixture's node and the off-fabric host through NAT. Every pair must be answered. While the connector is connected, the row requires exactly one BGPAdvertisement of the connector's route, carrying only the /96, and none for a longer prefix inside it. edgeprobe connectip takes several -src addresses for this. The provider guide now says how return traffic reaches addresses inside the /96. Fixes #978
|
Warning Polylane could not verify the production impact of this pull request. I checked the production account: no workload runs masque-authority (633 deployments, 1041 pods, 560 namespaces live) and only its CLI imports the changed package. Cloud Monitoring and log reads for the account returned no series. Also considered · 3 refuted
Analysed against 1 cloud account and 1 repository
Polylane could not find the cloud resources this repository manages, so this review looked at the entire cloud account. Connect this repository to its resources and the next review will focus on exactly what this code deploys to. Polylane analysed Rate this review: 👍 helpful · 👎 not helpful · 😕 confusing |
|
Second-pass verdicts on head 09b0f3d. pr-rereviewer: VERDICT: merge. It ran gh pr view 1195 --json title,body,isDraft,headRefOid; git rev-parse HEAD; git log --show-signature main..HEAD. pr-conventions-reviewer: VERDICT: merge. It ran gh pr view 1195 --json title,body,commits,files,baseRefName,isDraft; git diff --stat 6b333af...09b0f3d; git diff of docs and authority files; gh pr list --state open. First pass: pr-adversary returned merge after running go test -race ./internal/edge/masque/authority/, go vet ./tests/edgeconformance/..., and reading the Create, Retire and ledger paths. The conventions reviewer's first pass held on PR text only, and those findings were applied in the fix phase (title, body, draft state), so no code changed between passes. CI is green on the head: every check passed, including Build, Lint, Unit Tests, Unit Tests (root), E2E Tests and Manifests. The debug-image and service-api publish jobs were skipped by design. Auto-merge is enabled with the merge method, the only one the main ruleset allows. The ruleset requires one approving review, a code owner review and approval of the last push, so the PR waits for a human approval. |
ecv
left a comment
There was a problem hiding this comment.
Approve.
The fix keeps the stranded /96 and makes it recoverable instead of reclaiming it, which is the safe choice: no path here frees a /96 a live grant could hold. Ledgers.Allocate already returns an existing entry for the same connector, so a retry reuses it, and Retire now tombstones a record-less allocation.
Createwith the same connector and VPC/cell after a Secret create failure reuses the entry (Allocateis idempotent for a non-retired connector), so the 256 cap is not consumed again. Ledger writes still go throughLedgers.update, a conditionalUpdateon the read's resourceVersion with conflict retry; the PR adds only a read (holding) and no new write path.retireUnrecordedruns only whenDisablereturns NotFound, then tombstones and re-runsDisableto catch a racing Create. A Create whose record lands after that secondDisableleaves an enabled record on a retired allocation. The recordedRetirehas the same window (Disable, then ledger Retire), so this is no worse than before.- Context cancel mid-
CreateafterAllocateleaves the entry exactly like a Secret failure; the same retry orRetirerecovers it. A lost reply on the Secret create gives AlreadyExists on retry, and the error points atgrant rotate. - Conformance changes only add the
M12-aggregate-routingrow and multi--srcsupport inedgeprobe connectip. No assertion is removed, and with one or no-srcthe send loop behaves as before.
Follow-ups:
- The grant Secret is named by connector alone (
RecordName), but the ledger is keyed by VPC and cell. A--connectorthat already has a record in another VPC or cell passesAllocatein the new ledger and then hits AlreadyExists, which strands an entry there. The new message tells the user to rotate, which is wrong for that case, andRetireof the recorded connector never tombstones the other ledger's entry. Check for an existing record before allocating, or makeRetiresweep every ledger holding the name. - A stranded entry is only recovered if the operator reads the error and retries or retires. Nothing sweeps record-less allocations, so a Create that dies (process kill) before returning the error still leaks until someone finds it. A periodic reconcile of ledger entries without records would close it.
Fixes #978.
Summary
A failed grant-record write no longer strands a connector's /96 allocation.
A retry with the same connector keeps its /96, a lost reply points the operator at rotate, and retire tombstones an allocation that has no record.
The lab suite also gains a check that return traffic reaches addresses in several subdivisions of one /96 through its single aggregate route.
Test plan