From 3097d4b45912bc89ca956699c599e14491c6f63d Mon Sep 17 00:00:00 2001 From: Daniel Alley Date: Sat, 6 Jun 2026 23:35:22 -0400 Subject: [PATCH] Use ThreadedResolver to honor /etc/hosts and nsswitch.conf Pulpcore depended on aiodns, which causes aiohttp to default to AsyncResolver (c-ares) for DNS resolution. c-ares is a DNS client that speaks the wire protocol directly -- it does not go through glibc's getaddrinfo() and therefore ignores nsswitch.conf and /etc/hosts. This causes sync to fail when the remote hostname is only resolvable via /etc/hosts or other non-DNS nsswitch sources. Explicitly use aiohttp.resolver.ThreadedResolver, which wraps socket.getaddrinfo() in a thread pool. Since getaddrinfo() uses the system resolver, it respects nsswitch.conf ordering and reads /etc/hosts when configured. This is expected to have negligible impact as sync hits a limited number of hosts, and DNS resolution happens once-per-host. Since we now bypass c-ares entirely, drop the aiodns dependency and the related pycares version constraint from CI. Co-Authored-By: Claude Opus 4.6 --- .ci/assets/ci_constraints.txt | 2 -- pulpcore/download/factory.py | 8 +++++++- pulpcore/download/http.py | 4 +++- pyproject.toml | 1 - 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.ci/assets/ci_constraints.txt b/.ci/assets/ci_constraints.txt index c9198f19a70..e3e22649cd9 100644 --- a/.ci/assets/ci_constraints.txt +++ b/.ci/assets/ci_constraints.txt @@ -15,5 +15,3 @@ azure-storage-blob!=12.28.* # Apparently does not work with current azurite. -pycares<5 -# older aiodns versions don't pin pycares UB, and are broken by pycares>=5 diff --git a/pulpcore/download/factory.py b/pulpcore/download/factory.py index be2c2d7a879..8f37ae33817 100644 --- a/pulpcore/download/factory.py +++ b/pulpcore/download/factory.py @@ -144,7 +144,13 @@ def _make_aiohttp_session_from_remote(self): # I don't see why... # https://github.com/aio-libs/aiohttp/pull/3372 return aiohttp.ClientSession( - connector=aiohttp.TCPConnector(loop=asyncio.get_event_loop(), **tcp_conn_opts), + # ThreadedResolver uses getaddrinfo() which honors /etc/hosts and nsswitch.conf; + # the default AsyncResolver (c-ares) bypasses the system resolver entirely. + connector=aiohttp.TCPConnector( + loop=asyncio.get_event_loop(), + resolver=aiohttp.resolver.ThreadedResolver(loop=asyncio.get_event_loop()), + **tcp_conn_opts, + ), timeout=timeout, headers=headers, requote_redirect_url=False, diff --git a/pulpcore/download/http.py b/pulpcore/download/http.py index 0a714e67eaa..b2b82d40008 100644 --- a/pulpcore/download/http.py +++ b/pulpcore/download/http.py @@ -161,7 +161,9 @@ def __init__( self._close_session_on_finalize = False else: timeout = aiohttp.ClientTimeout(total=None, sock_connect=600, sock_read=600) - conn = aiohttp.TCPConnector() + # ThreadedResolver uses getaddrinfo() which honors /etc/hosts and nsswitch.conf; + # the default AsyncResolver (c-ares) bypasses the system resolver entirely. + conn = aiohttp.TCPConnector(resolver=aiohttp.resolver.ThreadedResolver()) self.session = aiohttp.ClientSession( connector=conn, timeout=timeout, headers=headers, requote_redirect_url=False ) diff --git a/pyproject.toml b/pyproject.toml index efcd69f2da9..f43d179ba46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,6 @@ classifiers=[ ] requires-python = ">=3.11" dependencies = [ - "aiodns>=3.3.0,<3.7", # Looks like only bugfixes in z-Stream. "aiofiles>=22.1,<=25.1.0", # Uses sort of CalVer, luckily not released often https://github.com/Tinche/aiofiles/issues/144 . "aiohttp>=3.10.10,<3.15", # SemVer https://docs.aiohttp.org/en/stable/faq.html#what-is-the-api-stability-and-deprecation-policy . "asyncio-throttle>=1.0,<=1.0.2", # Unsure about versioning, but not released often anyway.