commission fails if `maas-url` uses an IPv6

Bug #2020142 reported by Simon Déziel
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
MAAS
Fix Released
High
Christian Grabowski

Bug Description

When MAAS is configured with a `maas-url` using IPv6 (like `http://[::]:5240/MAAS`), deploying a VM fails.

Here is how to reproduce the issue

1) Save and execute the attached reproducer script
$ sh -x reproducer
2) Workaround a problem enabling DHCP
$ lxc exec maas -- maas admin vlan update -d 1 untagged dhcp_on=True primary_rack=maas
3) Log to MAAS' UI to finish the initial configuration
4) Commission `vm01`
5) Deploy `vm01` using 20.04
6) Check the deployment progress/fail using LXD VGA console
$ lxc console --type vga vm01

When the deploy fails, the regiond.log contains this:
$ lxc exec maas -- cat /var/snap/maas/common/log/regiond.log
...
2023-05-19 01:04:48 regiond: [info] 127.0.0.1 POST /MAAS/metadata/status/efwykd HTTP/1.1 --> 204 NO_CONTENT (referrer: -; agent: python-requests/2.22.0)
2023-05-19 01:04:48 regiond: [info] 127.0.0.1 POST /MAAS/metadata/status/efwykd HTTP/1.1 --> 204 NO_CONTENT (referrer: -; agent: python-requests/2.22.0)
2023-05-19 01:04:48 regiond: [info] 127.0.0.1 POST /MAAS/metadata/status/efwykd HTTP/1.1 --> 204 NO_CONTENT (referrer: -; agent: python-requests/2.22.0)
2023-05-19 01:04:48 maasserver.preseed: [warn] WARNING: '/snap/maas/27397/etc/maas/preseeds/curtin_userdata' contains deprecated preseed variables. Please remove: main_archive_directory, ports_archive_directory
2023-05-19 01:04:48 maasserver: [error] ################################ Exception: Unable to find MAAS server IP address: Address family for hostname not supported. MAAS's DNS server requires this IP address for the NS records in its zone files. Make sure that the configuration setting for the MAAS URL has the correct hostname. Consult the command 'maas-region local_config_set --maas-url' (deb installs) or 'maas config --maas-url' (snap installs) for more details. ################################
2023-05-19 01:04:48 maasserver: [error] Traceback (most recent call last):
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/dns/zonegenerator.py", line 149, in get_dns_server_addresses
    ips = get_maas_facing_server_addresses(
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/server_address.py", line 76, in get_maas_facing_server_addresses
    addresses = resolve_hostname(
  File "/snap/maas/27397/lib/python3.10/site-packages/provisioningserver/utils/network.py", line 791, in resolve_hostname
    address_info = resolve_host_to_addrinfo(hostname, ip_version)
  File "/snap/maas/27397/lib/python3.10/site-packages/provisioningserver/utils/network.py", line 770, in resolve_host_to_addrinfo
    address_info = getaddrinfo(
  File "/usr/lib/python3.10/socket.py", line 955, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -9] Address family for hostname not supported

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/maas/27397/usr/lib/python3/dist-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/utils/views.py", line 293, in view_atomic_with_post_commit_savepoint
    return view_atomic(*args, **kwargs)
  File "/usr/lib/python3.10/contextlib.py", line 79, in inner
    return func(*args, **kwds)
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/api/support.py", line 62, in __call__
    response = super().__call__(request, *args, **kwargs)
  File "/snap/maas/27397/usr/lib/python3/dist-packages/django/views/decorators/vary.py", line 20, in inner_func
    response = func(*args, **kwargs)
  File "/snap/maas/27397/usr/lib/python3.10/dist-packages/piston3/resource.py", line 197, in __call__
    result = self.error_handler(e, request, meth, em_format)
  File "/snap/maas/27397/usr/lib/python3.10/dist-packages/piston3/resource.py", line 195, in __call__
    result = meth(request, *args, **kwargs)
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/api/support.py", line 371, in dispatch
    return function(self, request, *args, **kwargs)
  File "/snap/maas/27397/lib/python3.10/site-packages/metadataserver/api.py", line 1155, in read
    user_data = get_curtin_userdata(request, node)
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/preseed.py", line 427, in get_curtin_userdata
    configs=get_curtin_yaml_config(request, node),
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/preseed.py", line 352, in get_curtin_yaml_config
    network_config = compose_curtin_network_config(
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/preseed_network.py", line 763, in compose_curtin_network_config
    generator = NodeNetworkConfiguration(
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/preseed_network.py", line 672, in __init__
    self.default_dns_servers = self.node.get_default_dns_servers(
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/models/node.py", line 5272, in get_default_dns_servers
    maas_dns_servers = get_dns_server_addresses(
  File "/snap/maas/27397/lib/python3.10/site-packages/maasserver/dns/zonegenerator.py", line 157, in get_dns_server_addresses
    raise UnresolvableHost(
maasserver.exceptions.UnresolvableHost: Unable to find MAAS server IP address: Address family for hostname not supported. MAAS's DNS server requires this IP address for the NS records in its zone files. Make sure that the configuration setting for the MAAS URL has the correct hostname. Consult the command 'maas-region local_config_set --maas-url' (deb installs) or 'maas config --maas-url' (snap installs) for more details.

2023-05-19 01:04:48 regiond: [info] 127.0.0.1 POST /MAAS/metadata/status/efwykd HTTP/1.1 --> 204 NO_CONTENT (referrer: -; agent: python-requests/2.22.0)
2023-05-19 01:04:49 regiond: [info] 127.0.0.1 POST /MAAS/metadata/status/efwykd HTTP/1.1 --> 204 NO_CONTENT (referrer: -; agent: python-requests/2.22.0)

Current workaround is to use a different `maas-url` using an IPv4 like `http://0.0.0.0:5240/MAAS`.

The problem was reproduced with MAAS snap channel `3.3/stable` and `3.4/beta`.

Additional information:

$ lxc exec maas -- snap list maas
Name Version Rev Tracking Publisher Notes
maas 3.4.0~beta1-14097-g.08ee1439a 27397 3.4/beta canonical✓ -

Tags: lxd-cloud

Related branches

Revision history for this message
Simon Déziel (sdeziel) wrote :
Simon Déziel (sdeziel)
tags: added: lxd-cloud
Revision history for this message
Christian Grabowski (cgrabowski) wrote :

It appears the issue is `socket.getaddrinfo()` does not work for IPv6 only hosts (links for context https://github.com/python/cpython/issues/54623, https://github.com/python/cpython/issues/82082, and https://bugs.python.org/issue10414). And while it does work for dual stack hosts, it seems until `socket.getaddrinfo()` is fixed (see latter of the github issues linked) using a higher level function to resolve the address info should work.

Marking as triaged

Changed in maas:
status: New → Triaged
importance: Undecided → High
assignee: nobody → Christian Grabowski (cgrabowski)
status: Triaged → In Progress
Revision history for this message
Simon Déziel (sdeziel) wrote :

The problem is when "::" is attempted to be resolved as an IPv4 it seems:

# cat << "EOF" > snippet.py
import socket
from socket import (
    AF_INET,
    AF_INET6,
    EAI_NODATA,
    EAI_NONAME,
    gaierror,
    getaddrinfo,
    IPPROTO_TCP,
)

def resolve_host_to_addrinfo(
    hostname, ip_version=4, port=0, proto=IPPROTO_TCP
):
    """Wrapper around `getaddrinfo`: return address information for `hostname`.

    :param hostname: Host name (or IP address).
    :param ip_version: Look for addresses of this IP version only: 4 for IPv4,
        6 for IPv6, or 0 for both. (Default: 4)
    :param port: port number, if any specified. (Default: 0)
    :return: a list of 5-tuples (family, type, proto, canonname, sockaddr)
        suitable for creating sockets and connecting. If `hostname` does not
        resolve (for that `ip_version`), then the list is empty.
    """
    addr_families = {4: AF_INET, 6: AF_INET6, 0: 0}
    assert ip_version in addr_families
    try:
        address_info = getaddrinfo(
            hostname, port, family=addr_families[ip_version], proto=proto
        )
    except gaierror as e:
        if e.errno in (EAI_NONAME, EAI_NODATA):
            # Name does not resolve.
            address_info = []
        else:
            raise
    return address_info

print(resolve_host_to_addrinfo("0.0.0.0", 4))
print(resolve_host_to_addrinfo("0.0.0.0", 0))
print(resolve_host_to_addrinfo("0.0.0.0"))
print(resolve_host_to_addrinfo("::", 6))
print(resolve_host_to_addrinfo("::", 0))
print(resolve_host_to_addrinfo("::")) # fails
EOF

# python3 snippet.py
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('0.0.0.0', 0))]
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('0.0.0.0', 0))]
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('0.0.0.0', 0))]
[(<AddressFamily.AF_INET6: 10>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('::', 0, 0, 0))]
[(<AddressFamily.AF_INET6: 10>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('::', 0, 0, 0))]
Traceback (most recent call last):
  File "/root/snippet.py", line 44, in <module>
    print(resolve_host_to_addrinfo("::")) # fails
  File "/root/snippet.py", line 28, in resolve_host_to_addrinfo
    address_info = getaddrinfo(
  File "/usr/lib/python3.10/socket.py", line 955, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -9] Address family for hostname not supported

Revision history for this message
Christian Grabowski (cgrabowski) wrote :

Well yes, but that would only happen if the machine being deployed is IPv4 only and you provide it an IPv6 address, which is guarded further up in the call stack, where MAAS checks if the given machine has a gateway IP configured for IPv4, IPv6 or dual stack. In an IPv6 only environment, `socket.getaddrinfo()` currently fails regardless, according to the bug thread, due to hardcoded IPv4 flags in the stdlib.

Changed in maas:
milestone: none → 3.5.0
status: In Progress → Fix Committed
Changed in maas:
milestone: 3.5.0 → 3.5.0-beta1
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Bug attachments

Remote bug watches

Bug watches keep track of this bug in other bug trackers.