Skip to content

feat: Preserve private DNS isolation through serving failures - #237

Merged
scotwells merged 43 commits into
feat/internal-dns-shared-query-servingfrom
feat/internal-dns-serving-recovery
Oct 22, 2026
Merged

scotwells merged 43 commits into
feat/internal-dns-shared-query-servingfrom
feat/internal-dns-serving-recovery

Conversation

@scotwells

@scotwells scotwells commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Keep validated private DNS available during configuration agent restarts and control plane outages.

CoreDNS restores accepted snapshots from persistent storage and activates record changes without restarting DNS listeners. Failed restart installations retry activation. The fleet verifies installed publications before reporting readiness. Rejected additions preserve accepted records; if an update removes records or resolver access and cannot be applied, the member stops serving the affected configuration.

Test plan

  • Focused restart tests, including a regression that fails without the retry fix
  • CI: API and controller tests
  • CI: Lint and generated manifests
  • CI: Container packaging
  • CI: Repository end-to-end tests

Stacked on #236. Architecture: #229.

Related: datum-cloud/enhancements#921

@scotwells
scotwells force-pushed the feat/internal-dns-serving-recovery branch from f73df4a to bfe4a3a Compare October 9, 2026 00:14
@scotwells
scotwells force-pushed the feat/internal-dns-serving-recovery branch 2 times, most recently from 90db938 to 1d7fb92 Compare October 9, 2026 00:22
@scotwells
scotwells force-pushed the feat/internal-dns-serving-recovery branch from 1d7fb92 to 697822e Compare October 9, 2026 01:33
@scotwells
scotwells added this pull request to stack #240 October 9, 2026 02:17
@scotwells
scotwells force-pushed the feat/internal-dns-serving-recovery branch from 4830b10 to 8a42d50 Compare October 12, 2026 17:09
@scotwells
scotwells force-pushed the feat/internal-dns-serving-recovery branch 2 times, most recently from 67f3407 to 50ed071 Compare October 12, 2026 21:17
@scotwells
scotwells force-pushed the feat/internal-dns-serving-recovery branch 2 times, most recently from d28b974 to f46429c Compare October 12, 2026 22:07
@scotwells
scotwells force-pushed the feat/internal-dns-serving-recovery branch from f46429c to 0839f10 Compare October 12, 2026 22:16
ecv
ecv previously approved these changes Oct 22, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Every failure path here fails closed for isolation. Follow-ups are in #261, and the first two are worth doing before staging relies on restarts: restoreActive does not mark activation needed when ApplyForce fails, and probeLocalDaemons accepts REFUSED and SERVFAIL, so a gated node can report Ready. Every restart test sets UnsafeAllowNoDNSVerify, so none of them runs the probe. The body says invalid updates retain accepted state, but a rejected record removal or version bump drops all serving. Say which is intended.

@scotwells
scotwells dismissed ecv’s stale review October 22, 2026 02:02

The merge-base changed after approval.

ecv
ecv previously approved these changes Oct 22, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving at 0f08c61. A failed restore now marks activation needed and retries, and fail-closed writes its marker, so a restart no longer reports Ready over a gated node. The probe still accepts REFUSED and SERVFAIL, and a failing restore retries at 1 Hz with no backoff. Both are in #261.

ecv
ecv previously approved these changes Oct 22, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving. Only the parent merge changed this PR. Its own commits and diff are unchanged apart from line offsets.

scotwells and others added 3 commits October 22, 2026 10:19
…nal-dns-serving-recovery

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nal-dns-serving-recovery

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@kevwilliams kevwilliams left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hold: a withdrawal whose render fails keeps serving the withdrawn data.

  • Agent.reconcile returns on a renderPublications error, and on the store.Save after Active = nil, before any gate. The old files and daemons keep answering for a revoked binding or deleted record, and every tick retries the same error. Still true at the top of the stack (#244).
  • Fix: call failClosed whenever !canRetainActive() and reconcile fails for any reason, not only when Apply fails.
  • Test: inject a render error on a withdrawal and assert serving stops.

scotwells and others added 3 commits October 22, 2026 14:43
`Agent.reconcile` only failed closed when `Apply` was rejected. If the desired state withdrew something the approved configuration serves (a revoked binding, a detached zone or a deleted record) and reconciliation failed earlier, for example in `renderPublications` or the checkpoint save after clearing `Active`, it returned before any gate. The daemons kept answering with the withdrawn data and every tick retried the same error.

Reconcile now records whether the approved configuration can be retained before it starts, and fails closed on any reconcile error when it cannot. A shutdown is not treated as a failed install, since `restoreActive` gates again on restart. A render failure that withdraws nothing still keeps the approved configuration. A new test injects a render error on a binding withdrawal and asserts that serving is gated, and that the same error without a withdrawal does not gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The local daemon readiness probe queried CoreDNS over UDP and TCP, but CoreDNS has listened only on TCP since the shared query serving change, with dnsdist in front of it for UDP. The UDP query was refused, so `internal-dns-node` never became Ready and the E2E environment timed out in `env:internal-dns:up`. The probe now checks CoreDNS over TCP only and still checks dnsdist over both UDP and TCP, matching what each daemon listens on. The publication probe timeout test now listens on TCP accordingly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@scotwells

Copy link
Copy Markdown
Contributor Author

@kevwilliams Fixed in 3f8fa1a. Agent.reconcile now checks canRetainActive() before it starts and calls failClosed on any reconcile error when the approved configuration cannot be retained, including a renderPublications error and the checkpoint save after Active = nil. A shutdown is excluded because restoreActive gates again on restart. TestWithdrawalRenderFailureStopsServing injects a render error on a binding withdrawal and asserts that serving is gated, and that the same error without a withdrawal leaves serving alone. The fix is merged up through #243, and into #244 locally.

This push also carries 50d1585, which fixes the Chainsaw E2E hold on #239 and #243: the local readiness probe queried CoreDNS over UDP, but CoreDNS listens only on TCP.

ecv
ecv previously approved these changes Oct 22, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving at 50d1585. Reconcile now fails closed on any error when the desired state withdraws something the approved configuration serves, so a revoked binding stops answering even if rendering fails, and a test covers both the withdrawal and the no-withdrawal case. The readiness probe checks CoreDNS over TCP only, matching #236's TCP-only listener. probeLocalDaemons still accepts any DNS response from dnsdist, which #261 tracks.

@scotwells
scotwells dismissed ecv’s stale review October 22, 2026 20:37

The merge-base changed after approval.

@scotwells
scotwells requested a review from ecv October 22, 2026 20:37

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving. The head is unchanged; only the base moved after the parent merged.

@scotwells
scotwells merged commit 9b4e245 into main Oct 22, 2026
18 checks passed
@scotwells
scotwells deleted the feat/internal-dns-serving-recovery branch October 22, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants