Merge lp:~allenap/maas/ntp-vendor-data-routable-pairs into lp:~maas-committers/maas/trunk

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 5378
Proposed branch: lp:~allenap/maas/ntp-vendor-data-routable-pairs
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 107 lines (+54/-11)
2 files modified
src/metadataserver/tests/test_vendor_data.py (+26/-3)
src/metadataserver/vendor_data.py (+28/-8)
To merge this branch: bzr merge lp:~allenap/maas/ntp-vendor-data-routable-pairs
Reviewer Review Type Date Requested Status
Andres Rodriguez (community) Approve
Review via email: mp+306188@code.launchpad.net

Commit message

Choose NTP servers for vendor-data by finding routable rack controller addresses from the perspective of the node being deployed.

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm! Just a comment inline but non-blocker.

review: Approve
Revision history for this message
Gavin Panella (allenap) wrote :

Thanks for the review!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/metadataserver/tests/test_vendor_data.py'
2--- src/metadataserver/tests/test_vendor_data.py 2016-09-16 16:24:22 +0000
3+++ src/metadataserver/tests/test_vendor_data.py 2016-09-20 07:36:22 +0000
4@@ -7,6 +7,7 @@
5
6 from unittest.mock import sentinel
7
8+from maasserver.dbviews import register_view
9 from maasserver.models.config import Config
10 from maasserver.testing.factory import factory
11 from maasserver.testing.testcase import MAASServerTestCase
12@@ -123,13 +124,35 @@
13 self.assertThat(dict(configuration), Equals({}))
14
15 def test_yields_boot_cluster_address_when_machine_has_booted(self):
16+ register_view("maasserver_routable_pairs")
17 Config.objects.set_config("ntp_external_only", False)
18+
19 machine = factory.make_Machine()
20- machine.boot_cluster_ip = factory.make_ip_address()
21- machine.save()
22+ address = factory.make_StaticIPAddress(
23+ interface=factory.make_Interface(node=machine))
24+
25+ rack_primary = factory.make_RackController(subnet=address.subnet)
26+ rack_primary_address = factory.make_StaticIPAddress(
27+ interface=factory.make_Interface(node=rack_primary),
28+ subnet=address.subnet)
29+
30+ rack_secondary = factory.make_RackController(subnet=address.subnet)
31+ rack_secondary_address = factory.make_StaticIPAddress(
32+ interface=factory.make_Interface(node=rack_secondary),
33+ subnet=address.subnet)
34+
35+ vlan = address.subnet.vlan
36+ vlan.primary_rack = rack_primary
37+ vlan.secondary_rack = rack_secondary
38+ vlan.dhcp_on = True
39+ vlan.save()
40+
41 configuration = generate_ntp_configuration(machine)
42 self.assertThat(dict(configuration), Equals({
43 "ntp": {
44- "servers": [machine.boot_cluster_ip],
45+ "servers": sorted((
46+ rack_primary_address.ip,
47+ rack_secondary_address.ip,
48+ )),
49 },
50 }))
51
52=== modified file 'src/metadataserver/vendor_data.py'
53--- src/metadataserver/vendor_data.py 2016-09-16 16:24:22 +0000
54+++ src/metadataserver/vendor_data.py 2016-09-20 07:36:22 +0000
55@@ -7,9 +7,12 @@
56 'get_vendor_data',
57 ]
58
59+from collections import defaultdict
60 from itertools import chain
61+import random
62
63 from maasserver.models.config import Config
64+from maasserver.routablepairs import find_addresses_between_nodes
65 from provisioningserver.utils.text import (
66 make_gecos_field,
67 split_string_list,
68@@ -58,14 +61,31 @@
69 ntp_servers = Config.objects.get_config("ntp_servers")
70 ntp_servers = set(split_string_list(ntp_servers))
71 else:
72- if node.boot_cluster_ip is None:
73- # For now this means there are no NTP servers but this will change
74- # with the "routable pairs" work, at which point we'll be able to
75- # easily calculate all rack addresses routable from the node.
76- ntp_servers = set()
77- else:
78- # Point the node back to the rack it booted from.
79- ntp_servers = {node.boot_cluster_ip}
80+ # Point the node back to its primary and secondary rack controllers as
81+ # a source of time information.
82+ rack_controllers = node.get_boot_rack_controllers()
83+ routable_addrs = find_addresses_between_nodes([node], rack_controllers)
84+ routable_addrs_by_rack = _group_addresses_by_right_node(routable_addrs)
85+ # Choose one routable address per rack at random.
86+ ntp_servers = {
87+ random.choice(address).format()
88+ for address in routable_addrs_by_rack.values()
89+ }
90
91 if len(ntp_servers) >= 1:
92 yield "ntp", {"servers": sorted(ntp_servers)}
93+
94+
95+def _group_addresses_by_right_node(addresses):
96+ """Group `addresses` by the "right" node.
97+
98+ Effectively this assumes that there is only one "left" node and thus
99+ ignores it; it's only concerned with grouping addresses on the "right".
100+
101+ :param addresses: The output from `find_addresses_between_nodes`.
102+ :return: A dict mapping "right" nodes to a list of their IP addresses.
103+ """
104+ collated = defaultdict(list)
105+ for _, _, right_node, right_ip in addresses:
106+ collated[right_node].append(right_ip)
107+ return collated