Skip to content

Commit

Permalink
Use internal MAAS domain as the preseed URL of a deploying machine.
Browse files Browse the repository at this point in the history
Using the IP address the deploying machine contacted on the rack controller, the subnet is determined. If that subnet is known and doesn't have any DNS nameservers defined, then it uses MAAS DNS to as the URL to contact the metadata endpoint.
  • Loading branch information
Blake Rouse committed Aug 3, 2018
1 parent 040aad6 commit 26c5b41
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 17 deletions.
23 changes: 21 additions & 2 deletions src/maasserver/rpc/boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
ObjectDoesNotExist,
ValidationError,
)
from maasserver.dns.config import get_resource_name_for_subnet
from maasserver.enum import (
BOOT_RESOURCE_FILE_TYPE,
INTERFACE_TYPE,
Expand All @@ -25,6 +26,7 @@
Node,
PhysicalInterface,
RackController,
Subnet,
VLAN,
)
from maasserver.node_status import NODE_STATUS
Expand Down Expand Up @@ -242,6 +244,20 @@ def get_boot_config_for_machine(machine, configs, purpose):
return osystem, series, subarch


def get_base_url_for_local_ip(local_ip, internal_domain):
"""Get the base URL for the preseed using the `local_ip`."""
subnet = Subnet.objects.get_best_subnet_for_ip(local_ip)
if subnet is not None and not subnet.dns_servers:
# Use the MAAS internal domain to resolve the IP address of
# the rack controllers on the subnet.
return 'http://%s.%s:5248/' % (
get_resource_name_for_subnet(subnet), internal_domain)
else:
# Either no subnet or the subnet has DNS servers defined. In
# that case fallback to using IP address only.
return 'http://%s:5248/' % local_ip


@synchronous
@transactional
def get_config(
Expand Down Expand Up @@ -280,6 +296,7 @@ def get_config(
'default_distro_series',
'kernel_opts',
'use_rack_proxy',
'maas_internal_domain',
])
if machine is not None:
# Update the last interface, last access cluster IP address, and
Expand Down Expand Up @@ -323,7 +340,8 @@ def get_config(
arch, subarch = machine.split_arch()
if configs['use_rack_proxy']:
preseed_url = compose_preseed_url(
machine, base_url='http://%s:5248/' % local_ip)
machine, base_url=get_base_url_for_local_ip(
local_ip, configs['maas_internal_domain']))
else:
preseed_url = compose_preseed_url(
machine, base_url=rack_controller.url,
Expand Down Expand Up @@ -394,7 +412,8 @@ def get_config(
purpose = "commissioning" # enlistment
if configs['use_rack_proxy']:
preseed_url = compose_enlistment_preseed_url(
base_url='http://%s:5248/' % local_ip)
base_url=get_base_url_for_local_ip(
local_ip, configs['maas_internal_domain']))
else:
preseed_url = compose_enlistment_preseed_url(
rack_controller=rack_controller, default_region_ip=region_ip)
Expand Down
98 changes: 83 additions & 15 deletions src/maasserver/rpc/tests/test_boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from unittest.mock import ANY

from maasserver import server_address
from maasserver.dns.config import get_resource_name_for_subnet
from maasserver.enum import (
BOOT_RESOURCE_FILE_TYPE,
INTERFACE_TYPE,
Expand Down Expand Up @@ -53,8 +54,8 @@ def get_config(*args, **kwargs):
if explicit_count is None:
# If you need to adjust this value up be sure that 100% you cannot
# lower this value. If you want to adjust this value down, big +1!
assert count <= 20, (
'%d > 20; Query count should remain below 20 queries '
assert count <= 21, (
'%d > 21; Query count should remain below 21 queries '
'at all times.' % count)
else:
# This test sets an explicit count. This should *ONLY* be used if
Expand Down Expand Up @@ -159,7 +160,7 @@ def test__purpose_local_does_less_work(self):
mac = node.get_boot_interface().mac_address
config = get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac,
query_count=6)
query_count=7)
self.assertEquals({
"system_id": node.system_id,
"arch": node.split_arch()[0],
Expand Down Expand Up @@ -318,7 +319,7 @@ def test__splits_domain_from_node_hostname(self):
self.assertEqual(host, observed_config.get('hostname'))
self.assertEqual(domainname, observed_config.get('domain'))

def test__has_enlistment_preseed_url_with_local_ip(self):
def test__has_enlistment_preseed_url_with_local_ip_no_subnet(self):
rack_controller = factory.make_RackController()
local_ip = factory.make_ip_address()
remote_ip = factory.make_ip_address()
Expand All @@ -330,6 +331,36 @@ def test__has_enlistment_preseed_url_with_local_ip(self):
base_url='http://%s:5248/' % local_ip),
observed_config["preseed_url"])

def test__has_enlistment_preseed_url_with_local_ip_subnet_with_dns(self):
rack_controller = factory.make_RackController()
subnet = factory.make_Subnet()
local_ip = factory.pick_ip_in_Subnet(subnet)
remote_ip = factory.make_ip_address()
factory.make_default_ubuntu_release_bootable()
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip)
self.assertEqual(
compose_enlistment_preseed_url(
base_url='http://%s:5248/' % local_ip),
observed_config["preseed_url"])

def test__has_enlistment_preseed_url_internal_domain(self):
rack_controller = factory.make_RackController()
subnet = factory.make_Subnet()
subnet.dns_servers = []
subnet.save()
local_ip = factory.pick_ip_in_Subnet(subnet)
remote_ip = factory.make_ip_address()
factory.make_default_ubuntu_release_bootable()
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip)
self.assertEqual(
compose_enlistment_preseed_url(
base_url='http://%s.%s:5248/' % (
get_resource_name_for_subnet(subnet),
Config.objects.get_config('maas_internal_domain'))),
observed_config["preseed_url"])

def test__has_enlistment_preseed_url_with_region_ip(self):
rack_controller = factory.make_RackController()
local_ip = factory.make_ip_address()
Expand Down Expand Up @@ -369,7 +400,7 @@ def test__enlistment_return_generic_when_none(self):
rack_controller.system_id, local_ip, remote_ip, arch=arch)
self.assertEqual('generic', observed_config['subarch'])

def test_preseed_url_for_known_node_local_ip(self):
def test_preseed_url_for_known_node_local_ip_no_subnet(self):
rack_url = 'http://%s' % factory.make_name('host')
network = IPNetwork("10.1.1/24")
local_ip = factory.pick_ip_in_network(network)
Expand All @@ -385,6 +416,43 @@ def test_preseed_url_for_known_node_local_ip(self):
observed_config["preseed_url"],
StartsWith('http://%s:5248' % local_ip))

def test_preseed_url_for_known_node_local_ip_subnet_with_dns(self):
rack_url = 'http://%s' % factory.make_name('host')
subnet = factory.make_Subnet()
local_ip = factory.pick_ip_in_Subnet(subnet)
remote_ip = factory.make_ip_address()
self.patch(
server_address, 'resolve_hostname').return_value = {local_ip}
rack_controller = factory.make_RackController(url=rack_url)
node = self.make_node(primary_rack=rack_controller)
mac = node.get_boot_interface().mac_address
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac)
self.assertThat(
observed_config["preseed_url"],
StartsWith('http://%s:5248' % local_ip))

def test_preseed_url_for_known_node_internal_domain(self):
rack_url = 'http://%s' % factory.make_name('host')
subnet = factory.make_Subnet()
subnet.dns_servers = []
subnet.save()
local_ip = factory.pick_ip_in_Subnet(subnet)
remote_ip = factory.make_ip_address()
self.patch(
server_address, 'resolve_hostname').return_value = {local_ip}
rack_controller = factory.make_RackController(url=rack_url)
node = self.make_node(primary_rack=rack_controller)
mac = node.get_boot_interface().mac_address
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac)
self.assertThat(
observed_config["preseed_url"],
StartsWith(
'http://%s.%s:5248' % (
get_resource_name_for_subnet(subnet),
Config.objects.get_config('maas_internal_domain'))))

def test_preseed_url_for_known_node_uses_rack_url(self):
rack_url = 'http://%s' % factory.make_name('host')
network = IPNetwork("10.1.1/24")
Expand Down Expand Up @@ -547,7 +615,7 @@ def test__sets_boot_interface_when_empty(self):
mac = nic.mac_address
get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac,
query_count=21)
query_count=22)
self.assertEqual(nic, reload_object(node).boot_interface)

def test__updates_boot_interface_when_changed(self):
Expand All @@ -562,7 +630,7 @@ def test__updates_boot_interface_when_changed(self):
mac = nic.mac_address
get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac,
query_count=21)
query_count=22)
self.assertEqual(nic, reload_object(node).boot_interface)

def test__sets_boot_cluster_ip_when_empty(self):
Expand Down Expand Up @@ -635,7 +703,7 @@ def test__sets_boot_interface_vlan_to_match_rack_controller(self):

get_config(
rack_controller.system_id, rack_ip.ip, remote_ip, mac=mac,
query_count=27)
query_count=28)
self.assertEqual(
rack_vlan, reload_object(node).get_boot_interface().vlan)

Expand All @@ -655,7 +723,7 @@ def test__doesnt_change_boot_interface_vlan_when_using_dhcp_relay(self):
mac = node.get_boot_interface().mac_address
get_config(
rack_controller.system_id, rack_ip.ip, remote_ip, mac=mac,
query_count=21)
query_count=22)
self.assertEqual(
relay_vlan, reload_object(node).get_boot_interface().vlan)

Expand All @@ -676,7 +744,7 @@ def test__changes_boot_interface_vlan_not_relayed_through_rack(self):
mac = node.get_boot_interface().mac_address
get_config(
rack_controller.system_id, rack_ip.ip, remote_ip, mac=mac,
query_count=27)
query_count=28)
self.assertEqual(
rack_vlan, reload_object(node).get_boot_interface().vlan)

Expand Down Expand Up @@ -730,7 +798,7 @@ def test__commissioning_node_uses_min_hwe_kernel(self):
mac = node.get_boot_interface().mac_address
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac,
query_count=21)
query_count=22)
self.assertEqual("hwe-18.04", observed_config["subarch"])

def test__commissioning_node_uses_min_hwe_kernel_converted(self):
Expand All @@ -744,7 +812,7 @@ def test__commissioning_node_uses_min_hwe_kernel_converted(self):
mac = node.get_boot_interface().mac_address
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac,
query_count=21)
query_count=22)
self.assertEqual("hwe-18.04", observed_config["subarch"])

def test__commissioning_node_uses_min_hwe_kernel_reports_missing(self):
Expand Down Expand Up @@ -781,7 +849,7 @@ def test__testing_deployed_node_uses_none_default_min_hwe_kernel(self):
mac = node.get_boot_interface().mac_address
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac,
query_count=14)
query_count=15)
self.assertEqual(observed_config["release"], commissioning_series)
self.assertEqual(observed_config["subarch"], 'generic')
self.assertEqual(node.distro_series, distro_series)
Expand All @@ -808,7 +876,7 @@ def test__testing_deployed_node_uses_default_min_hwe_kernel(self):
mac = node.get_boot_interface().mac_address
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac,
query_count=14)
query_count=15)
self.assertEqual(observed_config["release"], commissioning_series)
self.assertEqual(observed_config["subarch"], default_min_hwe_kernel)
self.assertEqual(node.distro_series, distro_series)
Expand All @@ -825,7 +893,7 @@ def test__commissioning_node_uses_hwe_kernel_when_series_is_newer(self):
mac = node.get_boot_interface().mac_address
observed_config = get_config(
rack_controller.system_id, local_ip, remote_ip, mac=mac,
query_count=15)
query_count=16)
self.assertEqual("ga-90.90", observed_config["subarch"])

def test__returns_ubuntu_os_series_for_ubuntu_xinstall(self):
Expand Down

0 comments on commit 26c5b41

Please sign in to comment.