Merge lp:~allenap/maas/ntp-vendor-data-split-servers-and-pools 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: 5443
Proposed branch: lp:~allenap/maas/ntp-vendor-data-split-servers-and-pools
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~allenap/maas/ntp-rack-external-too
Diff against target: 197 lines (+72/-29)
4 files modified
src/metadataserver/tests/test_vendor_data.py (+12/-7)
src/metadataserver/vendor_data.py (+11/-3)
src/provisioningserver/ntp/config.py (+20/-19)
src/provisioningserver/ntp/tests/test_config.py (+29/-0)
To merge this branch: bzr merge lp:~allenap/maas/ntp-vendor-data-split-servers-and-pools
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+307564@code.launchpad.net

Commit message

Publish both NTP servers and pools in vendor-data.

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

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/metadataserver/tests/test_vendor_data.py'
--- src/metadataserver/tests/test_vendor_data.py 2016-10-05 06:13:22 +0000
+++ src/metadataserver/tests/test_vendor_data.py 2016-10-05 06:13:22 +0000
@@ -14,6 +14,7 @@
14 generate_system_info,14 generate_system_info,
15 get_vendor_data,15 get_vendor_data,
16)16)
17from netaddr import IPAddress
17from testtools.matchers import (18from testtools.matchers import (
18 Contains,19 Contains,
19 ContainsDict,20 ContainsDict,
@@ -55,7 +56,8 @@
55 vendor_data = get_vendor_data(node)56 vendor_data = get_vendor_data(node)
56 self.assertThat(vendor_data, ContainsDict({57 self.assertThat(vendor_data, ContainsDict({
57 "ntp": Equals({58 "ntp": Equals({
58 "servers": ["bar", "foo"],59 "servers": [],
60 "pools": ["bar", "foo"],
59 }),61 }),
60 }))62 }))
6163
@@ -104,12 +106,15 @@
104106
105 def test_external_only_yields_all_ntp_servers_when_defined(self):107 def test_external_only_yields_all_ntp_servers_when_defined(self):
106 Config.objects.set_config("ntp_external_only", True)108 Config.objects.set_config("ntp_external_only", True)
107 ntp_servers = factory.make_hostname(), factory.make_hostname()109 ntp_hosts = factory.make_hostname(), factory.make_hostname()
110 ntp_addrs = factory.make_ipv4_address(), factory.make_ipv6_address()
111 ntp_servers = ntp_hosts + ntp_addrs
108 Config.objects.set_config("ntp_servers", " ".join(ntp_servers))112 Config.objects.set_config("ntp_servers", " ".join(ntp_servers))
109 configuration = generate_ntp_configuration(node=None)113 configuration = generate_ntp_configuration(node=None)
110 self.assertThat(dict(configuration), Equals({114 self.assertThat(dict(configuration), Equals({
111 "ntp": {115 "ntp": {
112 "servers": sorted(ntp_servers),116 "servers": sorted(ntp_addrs, key=IPAddress),
117 "pools": sorted(ntp_hosts),
113 },118 },
114 }))119 }))
115120
@@ -148,9 +153,9 @@
148 configuration = generate_ntp_configuration(machine)153 configuration = generate_ntp_configuration(machine)
149 self.assertThat(dict(configuration), Equals({154 self.assertThat(dict(configuration), Equals({
150 "ntp": {155 "ntp": {
151 "servers": sorted((156 "servers": sorted(
152 rack_primary_address.ip,157 (rack_primary_address.ip, rack_secondary_address.ip),
153 rack_secondary_address.ip,158 key=IPAddress),
154 )),159 "pools": [],
155 },160 },
156 }))161 }))
157162
=== modified file 'src/metadataserver/vendor_data.py'
--- src/metadataserver/vendor_data.py 2016-10-05 06:13:22 +0000
+++ src/metadataserver/vendor_data.py 2016-10-05 06:13:22 +0000
@@ -10,6 +10,8 @@
10from itertools import chain10from itertools import chain
1111
12from maasserver import ntp12from maasserver import ntp
13from netaddr import IPAddress
14from provisioningserver.ntp.config import normalise_address
13from provisioningserver.utils.text import make_gecos_field15from provisioningserver.utils.text import make_gecos_field
1416
1517
@@ -47,9 +49,15 @@
47 - 102.10.10.1049 - 102.10.10.10
48 - ntp.ubuntu.com50 - ntp.ubuntu.com
4951
50 but MAAS does not yet distinguish between pool and non-pool servers, and52 MAAS assumes that IP addresses are "servers" and hostnames/FQDNs "pools".
51 so this returns a single set of time references.
52 """53 """
53 ntp_servers = ntp.get_servers_for(node)54 ntp_servers = ntp.get_servers_for(node)
54 if len(ntp_servers) >= 1:55 if len(ntp_servers) >= 1:
55 yield "ntp", {"servers": sorted(ntp_servers)}56 # Separate out IP addresses from the rest.
57 addrs, other = set(), set()
58 for ntp_server in map(normalise_address, ntp_servers):
59 bucket = addrs if isinstance(ntp_server, IPAddress) else other
60 bucket.add(ntp_server)
61 servers = [addr.format() for addr in sorted(addrs)]
62 pools = sorted(other) # Hostnames and FQDNs only.
63 yield "ntp", {"servers": servers, "pools": pools}
5664
=== modified file 'src/provisioningserver/ntp/config.py'
--- src/provisioningserver/ntp/config.py 2016-09-29 14:28:06 +0000
+++ src/provisioningserver/ntp/config.py 2016-10-05 06:13:22 +0000
@@ -6,6 +6,7 @@
6__all__ = [6__all__ = [
7 "configure_rack",7 "configure_rack",
8 "configure_region",8 "configure_region",
9 "normalise_address",
9]10]
1011
11from functools import partial12from functools import partial
@@ -58,6 +59,23 @@
58configure_rack = partial(configure, offset=1)59configure_rack = partial(configure, offset=1)
5960
6061
62def normalise_address(address):
63 """Normalise an IP address into a form suitable for the `ntp` daemon.
64
65 It seems to prefer non-mapped IPv4 addresses, for example. Hostnames are
66 passed through.
67 """
68 try:
69 address = IPAddress(address)
70 except AddrFormatError:
71 return address # Hostname.
72 else:
73 if address.is_ipv4_mapped():
74 return address.ipv4()
75 else:
76 return address
77
78
61def _render_ntp_conf(includefile):79def _render_ntp_conf(includefile):
62 """Render ``ntp.conf`` based on the existing configuration.80 """Render ``ntp.conf`` based on the existing configuration.
6381
@@ -93,12 +111,12 @@
93 orphan mode (see http://support.ntp.org/bin/view/Support/OrphanMode).111 orphan mode (see http://support.ntp.org/bin/view/Support/OrphanMode).
94 """112 """
95 lines = ["# MAAS NTP configuration."]113 lines = ["# MAAS NTP configuration."]
96 servers = map(_normalise_address, servers)114 servers = map(normalise_address, servers)
97 lines.extend(115 lines.extend(
98 "%s %s iburst" % (116 "%s %s iburst" % (
99 ("server" if isinstance(server, IPAddress) else "pool"), server)117 ("server" if isinstance(server, IPAddress) else "pool"), server)
100 for server in servers)118 for server in servers)
101 peers = map(_normalise_address, peers)119 peers = map(normalise_address, peers)
102 lines.extend("peer %s" % peer for peer in peers)120 lines.extend("peer %s" % peer for peer in peers)
103 lines.append("tos orphan {:d}".format(offset + 8))121 lines.append("tos orphan {:d}".format(offset + 8))
104 lines.append("") # Add newline at end.122 lines.append("") # Add newline at end.
@@ -168,20 +186,3 @@
168 if not blank:186 if not blank:
169 yield from lines187 yield from lines
170 yield "\n"188 yield "\n"
171
172
173def _normalise_address(address):
174 """Normalise an IP address into a form suitable for the `ntp` daemon.
175
176 It seems to prefer non-mapped IPv4 addresses, for example. Hostnames are
177 passed through.
178 """
179 try:
180 address = IPAddress(address)
181 except AddrFormatError:
182 return address # Hostname.
183 else:
184 if address.is_ipv4_mapped():
185 return address.ipv4()
186 else:
187 return address
188189
=== modified file 'src/provisioningserver/ntp/tests/test_config.py'
--- src/provisioningserver/ntp/tests/test_config.py 2016-09-29 14:28:06 +0000
+++ src/provisioningserver/ntp/tests/test_config.py 2016-10-05 06:13:22 +0000
@@ -114,6 +114,35 @@
114 keywords=Equals({"offset": 1})))114 keywords=Equals({"offset": 1})))
115115
116116
117class TestNormaliseAddress(MAASTestCase):
118 """Tests for `p.ntp.config.normalise_address`."""
119
120 def test_returns_hostnames_unchanged(self):
121 hostname = factory.make_hostname()
122 self.assertThat(config.normalise_address(hostname), Equals(hostname))
123
124 def test_returns_ipv4_addresses_as_IPAddress(self):
125 address = factory.make_ipv4_address()
126 normalised = config.normalise_address(address)
127 self.assertThat(normalised, IsInstance(IPAddress))
128 self.assertThat(normalised.version, Equals(4))
129 self.assertThat(str(normalised), Equals(address))
130
131 def test_returns_ipv6_addresses_as_IPAddress(self):
132 address = factory.make_ipv6_address()
133 normalised = config.normalise_address(address)
134 self.assertThat(normalised, IsInstance(IPAddress))
135 self.assertThat(normalised.version, Equals(6))
136 self.assertThat(str(normalised), Equals(address))
137
138 def test_renders_ipv6_mapped_ipv4_addresses_as_plain_ipv4(self):
139 address_as_ipv4 = factory.make_ipv4_address()
140 address_as_ipv6 = str(IPAddress(address_as_ipv4).ipv6())
141 normalised = config.normalise_address(address_as_ipv6)
142 self.assertThat(normalised, IsInstance(IPAddress))
143 self.assertThat(str(normalised), Equals(address_as_ipv4))
144
145
117def extract_tos_options(configuration):146def extract_tos_options(configuration):
118 commands = re.findall(r"^ *tos +([^\r\n]+)$", configuration, re.MULTILINE)147 commands = re.findall(r"^ *tos +([^\r\n]+)$", configuration, re.MULTILINE)
119 return list(chain.from_iterable(map(str.split, commands)))148 return list(chain.from_iterable(map(str.split, commands)))