Skip to content

fix(connectivity): replace flaky example.org DNS probe with dual-stack fallback - #975

Open
odesenfans wants to merge 3 commits into
mainfrom
od/fix-dns-connectivity-probe-main
Open

fix(connectivity): replace flaky example.org DNS probe with dual-stack fallback#975
odesenfans wants to merge 3 commits into
mainfrom
od/fix-dns-connectivity-probe-main

Conversation

@odesenfans

Copy link
Copy Markdown
Contributor

Backport of #974 to main.

Problem

The droplet integration test (curl --fail .../status/check/fastapi) is flaky because the DNS connectivity probe resolves example.org — an RFC 2606 documentation domain not meant as a live, dual-stack target, which has had recurring DNS flakiness (notably AAAA). The diagnostic VM's /dns requires both A and AAAA, so a flaky lookup returns 503 → check_dns False → status_check_fastapi 503 → job fails.

Fix

Replace the single hostname with an ordered list of reliable dual-stack hosts from two independent providers, tried until one resolves — mirroring the existing CONNECTIVITY_HTTP_URLS fallback:

CONNECTIVITY_DNS_HOSTNAMES = ["one.one.one.one", "dns.google"]
  • Cloudflare one.one.one.one first (matches CONNECTIVITY_IPV4_URL = https://1.1.1.1/), Google dns.google fallback (independent failure domain).
  • host_status.check_dns_ipv4/ipv6: first-success loop, tolerating per-host OSError.
  • Diagnostic VM /dns: loops hosts, 200 once a host yields both families else 503.
  • Still env-overridable.

Identical change to #974 (the dev PR). vm.example.org in haproxy.py is a string sentinel, not a DNS lookup — left unchanged.

Tests

tests/supervisor/test_status.py: 11 passed (added first-host-success, fallback-on-no-address, fallback-on-error, all-fail cases).

…k fallback

example.org is an RFC 2606 documentation domain, never meant as a live
resolution target, and has had DNS flakiness (notably AAAA). Both the node's
host-status DNS check and the diagnostic VM's /dns endpoint resolved it and
required both A and AAAA records, so a single flaky lookup failed
/status/check/fastapi -> broke the droplet integration test (curl --fail).

Replace the single hostname with an ordered list of reliable dual-stack hosts
from two independent providers (Cloudflare one.one.one.one, then Google
dns.google), tried until one resolves -- mirroring the existing
CONNECTIVITY_HTTP_URLS fallback. A single provider's DNS hiccup no longer
fails the check, and the value stays env-overridable.

- conf.py: CONNECTIVITY_DNS_HOSTNAME (str) -> CONNECTIVITY_DNS_HOSTNAMES (list)
- host_status.check_dns_ipv4/ipv6: first-success loop, tolerate per-host OSError
- example_fastapi /dns: loop hosts, 200 once a host yields both families else 503
- tests: cover first-host success, fallback on no-address / on error, all-fail
@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.75510% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.09%. Comparing base (fe92e9c) to head (f5ec2ed).

Files with missing lines Patch % Lines
src/aleph/vm/orchestrator/views/host_status.py 75.00% 3 Missing and 1 partial ⚠️
src/aleph/vm/orchestrator/cli.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #975      +/-   ##
==========================================
+ Coverage   73.02%   73.09%   +0.06%     
==========================================
  Files         118      118              
  Lines       14631    14675      +44     
  Branches     1151     1156       +5     
==========================================
+ Hits        10685    10727      +42     
- Misses       3643     3644       +1     
- Partials      303      304       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@foxpatch-aleph foxpatch-aleph left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Replaces single DNS hostname with a fallback list in connectivity checks and fixes both check_dns_ipv4 and check_dns_ipv6 to iterate through hostnames with proper error handling, improving reliability. Tests cover first-success, fallback, and all-fail scenarios correctly.

…_PROGRAM

The droplet integration tests fail with total DNS breakage inside guest VMs
(socket.gaierror EAI_AGAIN for every hostname, raw-IP egress fine). Root
cause: DNS auto-detection on the droplet now picks up DigitalOcean's
VPC-internal resolver (10.110.15.254), which guests cannot reach through the
host NAT. Pin ALEPH_VM_DNS_NAMESERVERS to public resolvers (1.1.1.1, 8.8.8.8)
in both CI supervisor.env blocks so guest VMs get reachable nameservers.

Separately, the "Test new runtime" job has been silently running the
network-published diagnostic VM (and downloaded runtime) instead of the local
ones: cli.py unconditionally wrote args.fake_data_program (argparse default
None) over the settings, discarding ALEPH_VM_FAKE_DATA_PROGRAM from
supervisor.env since c827c20 (Oct 2023). The startup settings dump in CI
confirmed FAKE_DATA_PROGRAM = None, and the guest traceback matched the
January-published example code (dec8f47), not the repo checkout. Only
override the setting when -f/--fake-data-program is actually passed, so the
env var works again and the job tests the code it claims to test.

Verified: systemd EnvironmentFile passes the JSON list value through verbatim
and pydantic-settings parses it; supervisor unit suites pass.
@odesenfans

Copy link
Copy Markdown
Contributor Author

Same CI root-cause analysis and fixes as #974 (comment) (cherry-picked as b8ce139): pin guest DNS to public resolvers in CI (droplet auto-detection now hands guests an unreachable DigitalOcean VPC resolver), and fix cli.py discarding ALEPH_VM_FAKE_DATA_PROGRAM (dead since Oct 2023) so the new-runtime job tests local code again.

With ALEPH_VM_FAKE_DATA_PROGRAM working again, the supervisor's startup check
asserts that the example venv volume exists (FAKE_DATA_VOLUME,
/opt/examples/volumes/volume-venv.squashfs) -- it is a built artifact, not a
checked-in file, so `scp -pr ./examples` alone cannot provide it. Reuse the
artifact from the existing build_example_venv_volume job: download it into
examples/volumes/ before the scp so it lands where the assert (and the fake
volume mount) expects it.

@foxpatch-aleph foxpatch-aleph left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The test suite for DNS check fallback logic is well-structured and correctly validates all key behaviors: first-host success, fallback on no-address, fallback on raised exception, and total failure returning False. All patches use the correct settings variable name (CONNECTIVITY_DNS_HOSTNAMES, plural) matching the source code.

tests/supervisor/test_status.py (line 176): This IPv6 test covers the "first host has no IPv6" case but not the "first host raises" case (unlike the IPv4 tests which cover both). Consider adding test_check_dns_ipv6_falls_back_when_first_host_raises for symmetry.

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.

2 participants