27
21
from urlparse import urlparse
29
23
from django.conf import settings
30
from maasserver.exceptions import (
31
NoAddressFoundForHost,
24
from maasserver.exceptions import UnresolvableHost
34
from netaddr import IPAddress
36
# Arbitrary non-privileged port
29
from provisioningserver.utils.network import resolve_hostname
40
32
def get_maas_facing_server_host(nodegroup=None):
52
44
return urlparse(maas_url).hostname
55
def get_maas_facing_server_address(nodegroup=None):
47
def get_maas_facing_server_address(nodegroup=None, ipv4=True, ipv6=True):
56
48
"""Return address where nodes and workers can reach the MAAS server.
58
The address is taken from DEFAULT_MAAS_URL or nodegroup.maas_url.
50
The address is taken from `DEFAULT_MAAS_URL` or `nodegroup.maas_url`.
59
51
If there is more than one IP address for the host, the addresses
60
52
will be sorted and the first IP address in the sorted set will be
61
returned. IPv4 addresses will be sorted before IPv6 addresses, so
62
IPv4 addresses will be preferred if both exist.
53
returned. IPv4 addresses will be sorted before IPv6 addresses, so
54
this prefers IPv4 addresses over IPv6 addresses. It also prefers global
55
IPv6 addresses over link-local IPv6 addresses or IPv6-mapped IPv4
64
58
:param nodegroup: The nodegroup from the point of view of which the
65
59
server address should be computed.
60
:param ipv4: Include IPv4 addresses? Defaults to `True`.
61
:param ipv6: Include IPv6 addresses? Defaults to `True`.
66
62
:return: An IP address as a unicode string. If the configured URL
67
63
uses a hostname, this function will resolve that hostname.
64
:raise UnresolvableHost: if no IP addresses could be found for
67
hostname = get_maas_facing_server_host(nodegroup)
70
hostname = get_maas_facing_server_host(nodegroup)
72
address_info = getaddrinfo(hostname, PORT)
74
raise UnresolvableHost("Unable to resolve host %s" % hostname)
76
for (family, socktype, proto, canonname, sockaddr) in address_info:
77
if family not in (AF_INET, AF_INET6):
78
# We're not interested in anything other than IPv4 and v6
79
# addresses, so bail out of this loop.
81
# The contents of sockaddr differ for IPv6 and IPv4, but the
82
# first elemment is always the address, and that's all we care
84
addresses.add(IPAddress(sockaddr[0]))
69
if valid_ipv6(hostname):
71
addresses.add(hostname)
72
elif valid_ipv4(hostname):
74
addresses.add(hostname)
77
addresses = addresses.union(resolve_hostname(hostname, 4))
79
addresses = addresses.union(resolve_hostname(hostname, 6))
85
80
if len(addresses) == 0:
86
raise NoAddressFoundForHost(
87
"No address found for host %s." % hostname)
81
raise UnresolvableHost("No address found for host %s." % hostname)
88
82
return min(addresses).format().decode("ascii")