Merge lp:~danilo/maas/bug-16867570-fqdn-controller into lp:~maas-committers/maas/trunk

Proposed by Данило Шеган
Status: Merged
Approved by: Данило Шеган
Approved revision: no longer in the source branch.
Merged at revision: 6046
Proposed branch: lp:~danilo/maas/bug-16867570-fqdn-controller
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 113 lines (+57/-3)
4 files modified
src/maasserver/rpc/rackcontrollers.py (+10/-1)
src/maasserver/rpc/tests/test_rackcontrollers.py (+43/-0)
src/provisioningserver/rpc/clusterservice.py (+1/-1)
src/provisioningserver/rpc/tests/test_clusterservice.py (+3/-1)
To merge this branch: bzr merge lp:~danilo/maas/bug-16867570-fqdn-controller
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+323747@code.launchpad.net

Commit message

Support rack controllers using fully-qualified domain names as their hostnames

When a rack controller has a hostname set including a domain name (in the dotted form, eg. foo.example.com), registering this rack controller to existing MAAS regiond should keep the FQDN for the controller (if a domain does not exist already, it is added as non-authoritative domain name in MAAS).

Description of the change

To avoid introducing any API changes (eg. by allowing a domain argument to register() calls), we instead allow dotted hostname value and only parse it before committing to database.

Testing instructions:

I've reproduced part of the problem described in the bug using:

  uvt-kvm create --memory 2048 --ssh-public-key-file ~/.ssh/authorized_keys maas1
  uvt-kvm ssh --insecure maas1 sudo apt-add-repository ppa:maas/next-proposed
  uvt-kvm ssh --insecure maas1 sudo apt update
  uvt-kvm ssh --insecure maas1 sudo apt install maas

  uvt-kvm create --memory 2048 --ssh-public-key-file ~/.ssh/authorized_keys maas2
  uvt-kvm ssh --insecure maas2 sudo apt-add-repository ppa:maas/next-proposed
  uvt-kvm ssh --insecure maas2 sudo apt update
  uvt-kvm ssh --insecure maas2 sudo apt install maas-rack-controller
  echo maas2.test | uvt-kvm ssh --insecure maas2 sudo tee /etc/hostname

(though, after I restarted from scratch, packages are failing to install for me)

To confirm that the bug is fixed, I've applied the diff from this branch to running instances of both rackd/regiond code on maas1/maas2 VMs (and restarting all MAAS services after), and re-registered the rack controller. It now shows up with the correct domain name.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks good. Going to approve with the condition that you add one more test. See inline comment.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/rpc/rackcontrollers.py'
2--- src/maasserver/rpc/rackcontrollers.py 2017-01-28 00:51:47 +0000
3+++ src/maasserver/rpc/rackcontrollers.py 2017-05-10 11:10:44 +0000
4@@ -20,6 +20,7 @@
5 )
6 from maasserver.enum import NODE_TYPE
7 from maasserver.models import (
8+ Domain,
9 Node,
10 NodeGroupToRackController,
11 RackController,
12@@ -92,10 +93,18 @@
13 if interfaces is None:
14 interfaces = {}
15
16+ # If hostname is actually a FQDN, split the domain off and
17+ # create it as non-authoritative domain if it does not exist already.
18+ domain = Domain.objects.get_default_domain()
19+ if hostname.find('.') > 0:
20+ hostname, domainname = hostname.split('.', 1)
21+ (domain, _) = Domain.objects.get_or_create(
22+ name=domainname, defaults={'authoritative': False})
23+
24 this_region = RegionController.objects.get_running_controller()
25 node = find(system_id, hostname, interfaces)
26 if node is None:
27- node = RackController.objects.create(hostname=hostname)
28+ node = RackController.objects.create(hostname=hostname, domain=domain)
29 maaslog.info(
30 "New rack controller '%s' was created by region '%s' upon "
31 "first connection.",
32
33=== modified file 'src/maasserver/rpc/tests/test_rackcontrollers.py'
34--- src/maasserver/rpc/tests/test_rackcontrollers.py 2017-01-28 00:51:47 +0000
35+++ src/maasserver/rpc/tests/test_rackcontrollers.py 2017-05-10 11:10:44 +0000
36@@ -323,6 +323,49 @@
37 url=urlparse('http://localhost/MAAS/'), is_loopback=True)
38 self.assertEqual('', rack_registered.url)
39
40+ def test_creates_rackcontroller_domain(self):
41+ # Create a domain if a newly registered rackcontroller uses a FQDN
42+ # as the hostname, but the domain does not already existing in MAAS,
43+ hostname = "newcontroller.example.com"
44+ interfaces = {
45+ factory.make_name("eth0"): {
46+ "type": "physical",
47+ "mac_address": factory.make_mac_address(),
48+ "parents": [],
49+ "links": [],
50+ "enabled": True,
51+ }
52+ }
53+ url = 'http://%s/MAAS' % factory.make_name('host')
54+ rack_registered = register(
55+ "rack-id-foo", interfaces=interfaces, url=urlparse(url),
56+ is_loopback=False, hostname=hostname)
57+ self.assertEqual("newcontroller", rack_registered.hostname)
58+ self.assertEqual("example.com", rack_registered.domain.name)
59+ self.assertFalse(rack_registered.domain.authoritative)
60+
61+ def test_reuses_rackcontroller_domain(self):
62+ # If a domain name already exists for a FQDN hostname, it is
63+ # not modified.
64+ factory.make_Domain("example.com", authoritative=True)
65+ hostname = "newcontroller.example.com"
66+ interfaces = {
67+ factory.make_name("eth0"): {
68+ "type": "physical",
69+ "mac_address": factory.make_mac_address(),
70+ "parents": [],
71+ "links": [],
72+ "enabled": True,
73+ }
74+ }
75+ url = 'http://%s/MAAS' % factory.make_name('host')
76+ rack_registered = register(
77+ "rack-id-foo", interfaces=interfaces, url=urlparse(url),
78+ is_loopback=False, hostname=hostname)
79+ self.assertEqual("newcontroller", rack_registered.hostname)
80+ self.assertEqual("example.com", rack_registered.domain.name)
81+ self.assertTrue(rack_registered.domain.authoritative)
82+
83
84 class TestUpdateForeignDHCP(MAASServerTestCase):
85
86
87=== modified file 'src/provisioningserver/rpc/clusterservice.py'
88--- src/provisioningserver/rpc/clusterservice.py 2017-04-11 20:36:41 +0000
89+++ src/provisioningserver/rpc/clusterservice.py 2017-05-10 11:10:44 +0000
90@@ -751,7 +751,7 @@
91
92 # Gather the interface definition and hostname.
93 interfaces = get_all_interfaces_definition()
94- hostname = gethostname().split('.')[0]
95+ hostname = gethostname()
96
97 def cb_register(data):
98 self.localIdent = data["system_id"]
99
100=== modified file 'src/provisioningserver/rpc/tests/test_clusterservice.py'
101--- src/provisioningserver/rpc/tests/test_clusterservice.py 2017-04-05 14:30:21 +0000
102+++ src/provisioningserver/rpc/tests/test_clusterservice.py 2017-05-10 11:10:44 +0000
103@@ -1438,7 +1438,9 @@
104 @inlineCallbacks
105 def test_registerRackWithRegion_end_to_end(self):
106 maas_url = factory.make_simple_http_url()
107- hostname = platform.node().split('.')[0]
108+ hostname = "rackcontrol.example.com"
109+ self.patch_autospec(clusterservice, 'gethostname').return_value = (
110+ hostname)
111 interfaces = get_all_interfaces_definition()
112 self.useFixture(ClusterConfigurationFixture(
113 maas_url=maas_url))