Skip to content

fix: reject LocalDNS listener upstreams - #9471

Open
Saewon Kwak (saewoni) wants to merge 9 commits into
mainfrom
sakwa/localdns-day0-fix
Open

Saewon Kwak (saewoni) wants to merge 9 commits into
mainfrom
sakwa/localdns-day0-fix

Conversation

@saewoni

Copy link
Copy Markdown
Contributor

Summary

Reject invalid upstream resolver state before generating the LocalDNS
Corefile.

Day-0 bug

During LocalDNS startup, 70-localdns.conf is removed so DHCP/VNET DNS
servers can be discovered and used as CoreDNS upstreams. The network reload is
asynchronous, so resolv.conf can temporarily be empty, stale, or contain a
mix of a real upstream and a LocalDNS listener.

The existing code flattened all nameserver entries into one space-joined
string and compared that string with individual IP addresses. As a result,
states such as the following were not rejected:

nameserver 10.0.0.1
nameserver 169.254.10.10

The LocalDNS listener could then be inserted into the CoreDNS forward
directive, creating a self-referential forwarding path. An exact listener-only
state could also skip replacement and be persisted as the upstream. The cluster
listener 169.254.10.11 was not checked at all.

Change

  • Validate each upstream nameserver independently.
  • Reject malformed or non-address entries.
  • Reject the LocalDNS node listener 169.254.10.10.
  • Reject the LocalDNS cluster listener 169.254.10.11.
  • Preserve the existing no-op behavior for the valid Azure DNS upstream
    168.63.129.16.
  • Keep the live second read in replace_azurednsip_in_corefile so resolver
    changes after the wait are surfaced rather than hidden by reusing an older
    snapshot.

Empty resolver state is already handled by the non-empty wait guard from
#9361. This PR addresses the
follow-up listener and mixed-list validation described in
#9361 review discussion.

Testing

  • Added coverage for the node listener address.
  • Added coverage for the cluster listener address.
  • Added coverage for a valid upstream mixed with a LocalDNS listener.
  • bash -n passed for the modified shell script and spec.
  • git diff --check passed.
  • ShellSpec was not run locally because Docker is unavailable; repository CI
    should provide the full ShellSpec and ShellCheck validation.

Copilot AI balanced review requested due to automatic review settings September 11, 2026 18:34
@github-actions

github-actions Bot commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Windows Unit Test Results

  3 files   21 suites   1m 18s ⏱️
789 tests 789 ✅ 0 💤 0 ❌
815 runs  815 ✅ 0 💤 0 ❌

Results for commit 9f50a52.

♻️ This comment has been updated with latest results.

Copilot AI 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.

🟡 Changes recommended

The new validation still accepts malformed non-address values that can break LocalDNS startup.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Hardens LocalDNS Corefile generation against self-referential upstream resolvers.

Changes:

  • Validates upstream entries and rejects LocalDNS listener addresses.
  • Adds ShellSpec coverage for listener-only and mixed upstream states.
File summaries
File Description
parts/linux/cloud-init/artifacts/localdns.sh Adds upstream validation before Corefile replacement.
spec/parts/linux/cloud-init/artifacts/localdns_spec.sh Tests listener rejection and Azure DNS behavior.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI review requested due to automatic review settings September 11, 2026 18:48

Copilot AI 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.

🔵 Needs a closer look

The new whitelist still accepts malformed addresses that can break LocalDNS startup.

Review details

Suppressed comments (1)

parts/linux/cloud-init/artifacts/localdns.sh:188

  • 🟡 Medium Risk — 🔧 Script Logic: This character whitelist is not IP-address validation: values such as 999.999.999.999, deadbeef, and : all match and are then inserted into the CoreDNS forward directive. A malformed resolver state can therefore still make LocalDNS fail at startup. Please enforce IPv4 octet ranges and valid IPv6 structure, with corresponding malformed-address tests.
        if ! [[ "${upstream_dns_ip}" =~ ^[0-9a-fA-F.:]+$ ]]; then
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 11, 2026 20:03

Copilot AI 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.

🔵 Needs a closer look

The validator still accepts syntactically invalid IP addresses that can break LocalDNS startup.

Review details

Suppressed comments (1)

parts/linux/cloud-init/artifacts/localdns.sh:193

  • 🟡 Medium Risk — Script Logic: This checks only the character set, not whether the token is a syntactically valid IP address. Values such as 999.999.999.999, deadbeef, :, and 1..2.3 all pass and are then written into the CoreDNS forward directive, so malformed resolver state can still make LocalDNS fail at startup—the state this change is intended to reject. Validate each token as an actual IPv4/IPv6 address (including octet/group structure and ranges) before proceeding.
        case "${upstream_dns_ip}" in
            *[!0-9a-fA-F.:]*|"")
                echo "Invalid upstream VNET DNS server '${upstream_dns_ip}' in ${RESOLV_CONF}."
                return 1
                ;;
        esac
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@saewoni

Copy link
Copy Markdown
Contributor Author

Addressed review comment #9471 (comment) in commit 94fad76. Replaced the character whitelist with POSIX-compatible IPv4/IPv6 structural validation, including IPv4-mapped IPv6 support. Added regression cases for 999.999.999.999, deadbeef, :::, and ....; invalid values are rejected before Corefile replacement.

Copilot AI review requested due to automatic review settings September 11, 2026 21:15

Copilot AI 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.

🟡 Changes recommended

The validator currently rejects every ordinary IPv4 upstream and also accepts several malformed IPv6 forms.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

parts/linux/cloud-init/artifacts/localdns.sh:213

  • 🔴 High Risk — Script Logic: This branch runs before the plain-IPv4 check, so every normal IPv4 resolver (for example 10.0.0.1 or Azure DNS 168.63.129.16) contains a dot but does not match :[^:]+$ and exits with failure here. replace_azurednsip_in_corefile will therefore fail and LocalDNS startup exits 216 on the common IPv4 configuration. Handle colon-free IPv4 values before entering the embedded-IPv4/IPv6 path.
                if (value ~ /\./) {
                    if (value !~ /:[^:]+$/) exit 1
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

@aks-node-assistant

Copy link
Copy Markdown
Contributor

AgentBaker Linux gate detective

Run: https://msazure.visualstudio.com/CloudNativeCompute/_build/results?buildId=180752543
Failed jobs/stage/tasks: buildaclfipstlgen2 / Test, Scan, and Cleanup; buildAzureLinuxV3gen2kata / Build VHD

Detective summary

  • buildaclfipstlgen2 failed before Packer VM provisioning. Surface error: ARM template validation returned QuotaExceeded for WestUS3 standardDDSv5Family cores, current usage 1400 of limit 1400 with 8 additional cores required. Corroboration: failed timeline task plus Build VHD/Test-Scan-Cleanup log and the existing recurring wiki signature all match the same quota pattern.
  • buildAzureLinuxV3gen2kata failed in Build VHD before image creation completed. Surface error: expected SIG image version PackerSigGalleryEastUS/AzureLinuxV3katagen2/1.1789157787.1744 was not found, followed by cleanup ResourceNotFound fallout. Corroboration: failed timeline task, Build VHD log, cleanup log, and PR metadata/changed files all point away from the LocalDNS shell changes.

Likely cause and signature

  • vhd-westus3-standardddsv5family-quota-exceeded: shared WestUS3 VHD build capacity quota exhaustion, not PR-change-caused. Confidence: high.
  • vhd-azurelinuxv3kata-sig-version-resource-notfound: SIG image creation/lookup or propagation flake for AzureLinuxV3 kata, not PR-change-caused. Confidence: medium.

Root-cause challenge

Strongest alternative is a PR-caused regression because this PR changes localdns.sh and its shell tests, but both failures happen in VHD build/provisioning infrastructure before any LocalDNS E2E behavior is exercised. Test-code/product regression, CSE, dependency/package, and Packer-template theories are less likely than shared infra capacity/image-version availability based on the error locations and changed-file scope.

Recommended owner/action

AgentBaker VHD build infrastructure owners should restore WestUS3 standardDDSv5Family quota headroom and investigate why the AzureLinuxV3 kata SIG version was unavailable after the build step. PR author action is likely none unless a rerun still fails after infra capacity/image availability is restored.

Evidence

Copilot AI review requested due to automatic review settings September 11, 2026 21:44
@saewoni

Copy link
Copy Markdown
Contributor Author

Addressed review comment #9471 (comment) in commit e3cac8f6.

The IPv6 validator now rejects triple colons and unmatched single leading/trailing colons while preserving the valid compressed unspecified address ::.

Added ShellSpec cases for:

  • 1:::2
  • :1:2:3:4:5:6:7:8
  • 1:2:3:4:5:6:7:8:
  • ::

Copilot AI 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.

🟡 Changes recommended

The validator currently rejects ordinary IPv4 upstreams, causing LocalDNS startup to fail.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

parts/linux/cloud-init/artifacts/localdns.sh:217

  • 🔴 High Risk — Script Logic: This branch handles every dotted value as an IPv4-embedded IPv6 address and requires a colon before the later pure-IPv4 validation can run. Standard upstreams such as 168.63.129.16 and 10.0.0.1 therefore return failure, causing LocalDNS startup to exit 216. Limit this branch to dotted values that also contain a colon so line 223 validates ordinary IPv4 addresses.
                if (value ~ /\./) {
                    if (value !~ /:[^:]+$/) exit 1
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

@yewmsft Ye Wang (yewmsft) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the direction changed since my last read, and the new validator breaks all ipv4 upstreams.

localdns.sh:216 — every ipv4 address has a . and no :, so it hits exit 1 at 217 before valid_ipv4() is ever consulted. that branch was written for ipv4-mapped ipv6 (::ffff:10.0.0.1) but it swallows bare ipv4 first. sourced the function at this head and ran it:

nameserver 168.63.129.16  -> rc=1  Invalid upstream VNET DNS server '168.63.129.16'
nameserver 10.0.0.1       -> rc=1  Invalid upstream VNET DNS server '10.0.0.1'

that is exit $ERR_LOCALDNS_FAIL -> systemctlEnableAndStart localdns 30 fails in cse_config.sh -> every node with localdns enabled fails to provision. shellspec is red on this head for the same reason.

stepping back — is this the right direction? RESOLV_CONF is /run/systemd/resolve/resolv.conf, written only by systemd-resolved, which serializes from its own dns server list and only ever emits canonical addresses. it cannot produce 1:::2 or .... or 999.999.999.999. the thing we actually need to reject is the two listener ips, and that is a string compare. we added 40 lines of hand-rolled ipv6 parsing on a day-0 provisioning path to guard inputs that can't occur, and it took out the one path that does. i'd revert to the simple form and keep the listener check.

also, all 8 new tests are negative ipv6 shapes. none cover the positive ipv4 path that just regressed, and none of these are still missing:

  • listener first, ip second (169.254.10.10 then 10.0.0.1) — the loop early-returns so it is order sensitive by construction, and every mixed test today puts the legit ip first. the original bug was about position in the list, pin both orders
  • .10 + .11 together, no legit upstream
  • 168.63.129.16 + 10.0.0.1 — the only shape that hits the replace branch while the list already contains AZURE_DNS_IP
  • single legit non-azure ip alone

localdns.sh:389 (not in the diff) — verify_default_route_interface does the same awk | paste -sd' ' read, but takes $1 only, checks .10 only, and .11 not at all. and if $1 is the listener we give up instead of trying the next server. follow-up pr is fine, but let's not keep two copies of this check.

Agentbaker E2E is skipping on this run. day-0 resolver path, please get a real run linked before merge.

Copilot AI review requested due to automatic review settings September 11, 2026 23:30
@aks-node-assistant

Copy link
Copy Markdown
Contributor

AgentBaker Linux gate detective

Run: https://msazure.visualstudio.com/CloudNativeCompute/_build/results?buildId=180768632
Failed jobs/stage/tasks: build stage / multiple Build VHD jobs / Build VHD task during Packer ARM template validation

Detective summary

The gate is failing before image creation during Packer VM deployment validation in WestUS3. The first useful failure is ARM InvalidTemplateDeployment with inner QuotaExceeded for standardDDSv5Family cores: current usage 1396 of limit 1400, with 16 additional cores required and a minimum limit of 1412.

Corroboration

Timeline reports failed Build VHD tasks across the matrix, and the failed Build VHD logs show the same WestUS3 standardDDSv5Family quota exhaustion before Packer creates a VM. There are no failed E2E test records. Build metadata and changed files tie the run to LocalDNS shell/spec changes, but the failure occurs in shared regional capacity validation before LocalDNS behavior is exercised.

Likely cause and signature

Likely root cause: shared AgentBaker VHD build infrastructure quota exhaustion in WestUS3 for standardDDSv5Family. Classification: VHD build / infra-capacity quota, not PR-change-caused. Confidence: high. Wiki signature: vhd-westus3-standardddsv5family-quota-exceeded.

Root-cause challenge

Strongest alternative is a PR-caused regression because this PR changes localdns.sh and its spec, but the failed steps are Packer ARM template validation and quota preflight before any LocalDNS content can affect provisioning. Product, test-code, CSE/provisioning, dependency/package, and Packer-template theories are less likely than shared regional quota exhaustion.

Recommended owner/action

AgentBaker VHD build infrastructure owners should restore standardDDSv5Family quota headroom in WestUS3 or move affected build capacity to a region/SKU family with available cores. PR author action is likely none unless a rerun still fails after capacity is restored.

Evidence

Copilot AI 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.

🔵 Needs a closer look

The format check still accepts malformed addresses that can break LocalDNS startup.

Review details

Suppressed comments (1)

parts/linux/cloud-init/artifacts/localdns.sh:201

  • 🟡 Medium Risk — 🔧 Script Logic: This character whitelist is not address validation. Malformed values such as 999.999.999.999, deadbeef, 1:2:3, and ... all pass and are then inserted into the CoreDNS forward directive, so a transient malformed resolver state can still break LocalDNS startup despite this PR's stated rejection guarantee. Parse each token as an actual IPv4/IPv6 literal (including IPv4 ranges and IPv6 structure), then reject unspecified/listener addresses before modifying the Corefile.
    # systemd-resolved emits canonical address values; reject tokens outside that format.
    for upstream_dns_ip in ${UPSTREAM_VNET_DNS_SERVERS}; do
        case "${upstream_dns_ip}" in
            "::"|*[!0-9a-fA-F.:]*|"")
                echo "Invalid upstream VNET DNS server '${upstream_dns_ip}' in ${RESOLV_CONF}."
                return 1
                ;;
        esac
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 12, 2026 00:08

Copilot AI 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.

🔵 Needs a closer look

The character allowlist still accepts malformed and non-address upstream values.

Review details

Suppressed comments (1)

parts/linux/cloud-init/artifacts/localdns.sh:197

  • 🟡 Medium Risk — Script Logic: This is only a character allowlist, not address validation. Non-address or malformed values such as abc, 1.2.3, 999.999.999.999, and 2001:db8::1::2 all bypass this branch and are written into the Corefile, so a bad resolver snapshot can still produce an unusable or self-resolving forwarder instead of being rejected. Please validate each token as a syntactically valid IPv4 or IPv6 address (and reject unusable unspecified addresses) before copying or editing the Corefile.
            "::"|*[!0-9a-fA-F.:]*|"")
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 12, 2026 00:35

Copilot AI 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.

🟡 Changes recommended

Address validation remains incomplete, and the unchanged-Corefile test helper cannot detect mutations.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

parts/linux/cloud-init/artifacts/localdns.sh:198

  • 🟡 Medium Risk — 🔧 Script Logic: This character whitelist does not validate an IP address. Inputs such as 999.999.999.999, abc, and 1:2 all pass and are then inserted into the CoreDNS forward directive, so malformed resolver state can still produce an unusable Corefile and abort LocalDNS startup. Please validate IPv4 octet ranges and complete IPv6 syntax before modifying the Corefile.
    # systemd-resolved emits canonical address values; reject tokens outside that format.
    for upstream_dns_ip in ${UPSTREAM_VNET_DNS_SERVERS}; do
        case "${upstream_dns_ip}" in
            "::"|*[!0-9a-fA-F.:]*|"")
                echo "Invalid upstream VNET DNS server '${upstream_dns_ip}' in ${RESOLV_CONF}."
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment on lines +84 to +88
if ! assert_updated_localdns_corefile_unchanged; then
echo "Updated localdns corefile changed unexpectedly."
return 1
fi
return "$status"
@aks-node-assistant

Copy link
Copy Markdown
Contributor

AgentBaker Linux gate detective

Run: https://msazure.visualstudio.com/CloudNativeCompute/_build/results?buildId=180793366
Failed job/stage/task: e2e stage / Run AgentBaker E2E / Ubuntu2604Minimal_NPD_Basic

Detective summary

The E2E task failed after VMSS/node readiness during post-provisioning Linux validation. The first useful failure is Ubuntu2604Minimal_NPD_Basic reporting Critical kernel issues detected with a kernel call trace at boot-time timestamp 1.286683. The task then exited with status 1.

Corroboration

The failed test record, the Run AgentBaker E2E timeline task, and the E2E log all point to the same scenario and kernel-call-trace validator failure. The log also shows E2E_FAILED_TESTS_RETRY_COUNT=0, so this run did not retry the scenario. A prior wiki row already tracks the same Ubuntu 26.04 Minimal kernel-critical-validation signature, while other adjacent scenarios completed kernel validation without critical issues.

Likely cause and signature

Likely root cause: recurring Ubuntu 26.04 Minimal image/kernel validation flake or image issue surfaced by NPD_Basic, not a LocalDNS PR change. Classification: E2E/test kernel validation. Confidence: medium. Wiki signature: e2e-ubuntu2604minimal-kernel-critical-validation.

Root-cause challenge

Strongest alternative is a PR-caused LocalDNS regression because this PR changes localdns.sh and shell specs, but the failure is an NPD_Basic kernel call trace after readiness and does not fail at LocalDNS validation. Product/test-code regression and CSE/provisioning are less likely than shared image/kernel validation flake based on the existing matching signature and scenario scope.

Recommended owner/action

Treat this as an AgentBaker E2E/image flake unless it reproduces after rerun. Node/VHD owners should inspect the Ubuntu 26.04 Minimal kernel log artifact for the call trace signature; PR author action is likely none unless rerun reproduces with a LocalDNS-specific failure.

Evidence

@saewoni

Copy link
Copy Markdown
Contributor Author

comprehensive test result here: #9503 (comment)

Conclusive Live Validation — All Three Problems Resolved

All three PR problems were reproduced and confirmed fixed on a single fresh, LocalDNS-enabled Ubuntu 22.04 agent node, patched with the latest cherry-picked artifacts from the combined branch.

Setup

PR #9439 — Deterministic terminal failure (previously inconclusive) — NOW CONFIRMED

Fault: sabotaged the coredns binary path and drove repeated restarts to exhaust the budget.

RESTART_ATTEMPT_1..5: ActiveState=active   (recovered each time)
after_6:              ActiveState=failed  Result=start-limit-hit
STARTLIMIT_HIT=true (attempt 6)
FINAL_ACTIVESTATE=failed
FINAL_RESULT=start-limit-hit
STARTLIMIT_OBSERVED=true
DROPIN=removed
HOST_DNS=...mcr.microsoft.com      (host still resolves — no blackhole)
RECOVERED_ACTIVESTATE=active

Result: the bounded budget lands LocalDNS deterministically in failed with Result=start-limit-hit after 5 starts in the window, instead of restarting forever. On that terminal path, #9360's ExecStopPost still removed the drop-in and host DNS kept resolving. Confirmed live.

PR #9471 — Listener/invalid upstream rejection (previously inconclusive live) — NOW CONFIRMED

The on-node branch replace_azurednsip_in_corefile was exercised directly against crafted resolver states:

CASE=node_listener    rc=1 leaked=no  reject -> PASS   (rejects 169.254.10.10)
CASE=cluster_listener rc=1 leaked=no  reject -> PASS   (rejects 169.254.10.11)
CASE=mixed            rc=1 leaked=no  reject -> PASS   (valid + listener rejected)
CASE=listener_first   rc=1 leaked=no  reject -> PASS
CASE=malformed_ipv6   rc=1 leaked=no  reject -> PASS   (rejects '::')
CASE=malformed_cidr   rc=1 leaked=no  reject -> PASS   (rejects '10.0.0.1/24')
CASE=valid_single     rc=0            accept -> PASS   (forwards 10.0.0.1)
CASE=valid_azure      rc=0            accept -> PASS   (skips, Azure DNS)

No LocalDNS listener IP was ever written into the generated corefile in any reject case. Valid upstreams forward correctly. Confirmed live (8/8 cases).

PR #9360 — Node DNS restoration after terminal exit — RE-CONFIRMED

Terminal dead-service test on the same patched node:

PRE_ACTIVE=active,  PRE_HOST_DNS resolves
KILLING=<pid>
DEAD_ACTIVESTATE=failed
DEAD_RESULT=signal
ESP_STATUS=status=0            (ExecStopPost ran successfully)
DROPIN=removed                 (70-localdns.conf removed)
RESOLVER=168.63.129.16         (reverted from 169.254.10.10)
HOST_DNS_AFTER_DEATH resolves  (no blackhole)
RECOVERED_ACTIVE=active

Confirmed live.

Final verdict

PR Problem Live result
#9360 Stale node DNS redirect after terminal LocalDNS exit Fixed — drop-in removed, host DNS reverted, no blackhole
#9439 Restart-forever / non-deterministic failure state Fixed — deterministic failed / start-limit-hit after bounded budget; self-heals moderate bursts
#9471 Invalid/listener upstreams accepted Fixed — all listener/malformed inputs rejected, no leak; valid upstreams forwarded

Based on the latest cherry-picked commits from PRs #9360, #9439, and #9471, all three problems are no longer present on the live cluster's LocalDNS-enabled agent node. The disposable node was deleted after testing.

Copilot AI 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.

🟡 Changes recommended

Address validation remains incomplete, and the unchanged-Corefile test helper cannot detect mutations.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

spec/parts/linux/cloud-init/artifacts/localdns_spec.sh:88

  • The new unchanged-file check cannot fail any of these tests: both the expected production failure and a cmp mismatch return status 1, while every caller only asserts The status should be failure. Consequently, a regression that modifies the Corefile before returning failure still passes. Make the wrapper distinguish “function failed and file stayed unchanged” from a comparison failure, and update callers to assert that exact result/status.
            if ! assert_updated_localdns_corefile_unchanged; then
                echo "Updated localdns corefile changed unexpectedly."
                return 1
            fi
            return "$status"
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment on lines +194 to +198
# systemd-resolved emits canonical address values; reject tokens outside that format.
for upstream_dns_ip in ${UPSTREAM_VNET_DNS_SERVERS}; do
case "${upstream_dns_ip}" in
"::"|*[!0-9a-fA-F.:]*|"")
echo "Invalid upstream VNET DNS server '${upstream_dns_ip}' in ${RESOLV_CONF}."
@yewmsft

Copy link
Copy Markdown
Member

the listener check is right, but it's in the wrong place.

1. .11 should be waited for, not rejected. wait_for_localdns_removed_from_resolv_conf (:622) already waits out the async networkctl reload — but only for LOCALDNS_NODE_LISTENER_IP. your new check at :186-192 rejects LOCALDNS_CLUSTER_LISTENER_IP too, eight lines later, with no wait. so the exact transient the PR description calls out ("resolv.conf can temporarily be ... a mix") now hard-fails startup instead of being waited out. and with #9439 in the stack that costs a StartLimitBurst slot each time — 5 of those and localdns is failed.

put both listeners in the wait condition instead:

if [ -n "$current_dns" ] \
   && ! grep -qwF "$LOCALDNS_NODE_LISTENER_IP" <<< "$current_dns" \
   && ! grep -qwF "$LOCALDNS_CLUSTER_LISTENER_IP" <<< "$current_dns"; then

then :186-192 becomes a genuine invariant check rather than a race.

2. :196-201 is a charset filter, not address validation. *[!0-9a-fA-F.:]* passes ..., 1.2.3.4.5.6, 999.999.999.999, 0.0.0.0, 127.0.0.1, ::1. the description says "reject malformed or non-address entries" — it doesn't. 127.0.0.1/::1 in particular land in the forward directive and give you a different flavour of the same self-reference bug.

if you want real validation, use something that parses:

ip route get "${upstream_dns_ip}" >/dev/null 2>&1 || { echo "..."; return 1; }

or drop the format check entirely and keep only the listener check — systemd-resolved doesn't emit garbage, and you say so yourself in the comment.

3. one loop, not two. :186 and :195 iterate the same list. fold both checks into a single pass.

4. :209-219 — still cp then sed -i. I asked for this on #6894. the sed is a no-op when the upstreams already equal ${AZURE_DNS_IP}, so the whole copy/branch collapses:

sed -e "s|${AZURE_DNS_IP}|${UPSTREAM_VNET_DNS_SERVERS}|g" \
    "${LOCALDNS_CORE_FILE}" > "${UPDATED_LOCALDNS_CORE_FILE}" || {
    echo "Failed to generate ${UPDATED_LOCALDNS_CORE_FILE}"
    return 1
}

one write instead of two, and no window where UPDATED_LOCALDNS_CORE_FILE exists with unreplaced content.

5. tests cover reject paths. is there one for "wait succeeds after a mixed list clears"? that's the path that decides whether a node provisions or burns a restart slot.

@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Health
test 0% ❌
windows 27% ❌
staging_cse_windows Package 1 71% ➖
debug 0% ❌
provisioningscripts 2% ❌
parts_windows Package 1 73% ➖
Summary 39% (1983 / 7220) ❌

@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Health
shellspec spec 30% ❌
Summary 30% (4920 / 16599) ❌

Copilot AI 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.

🔵 Needs a closer look

Resolver validation still accepts malformed IP addresses that can break CoreDNS startup, while rejection-path tests fail to detect unexpected Corefile modifications.

2 open issues

Review effort: Balanced

@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Health
github.com/Azure/agentbaker/aks-node-controller 73% ➖
github.com/Azure/agentbaker/aks-node-controller/common 100% ✔
github.com/Azure/agentbaker/aks-node-controller/helpers 68% ➖
github.com/Azure/agentbaker/aks-node-controller/parser 88% ✔
github.com/Azure/agentbaker/aks-node-controller/pkg/gpu 100% ✔
github.com/Azure/agentbaker/aks-node-controller/pkg/nodeconfigutils 92% ✔
github.com/Azure/agentbaker/aks-node-controller/utils 0% ❌
github.com/Azure/agentbaker/apiserver 24% ❌
github.com/Azure/agentbaker/cmd 0% ❌
github.com/Azure/agentbaker/cmd/starter 0% ❌
github.com/Azure/agentbaker/fuzz/api 0% ❌
github.com/Azure/agentbaker/hotfix/render-nodecustomdata 35% ❌
github.com/Azure/agentbaker/pkg/agent 79% ➖
github.com/Azure/agentbaker/pkg/agent/datamodel 77% ➖
github.com/Azure/agentbaker/pkg/agent/toggles 0% ❌
github.com/Azure/agentbaker/pkg/vhdbuilder/datamodel 87% ✔
Summary 76% (6093 / 8041) ➖

This branch has not been deployed

No deployments
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.

5 participants