Merge lp:~lamont/maas/bug-1606508 into lp:~maas-committers/maas/trunk

Proposed by LaMont Jones
Status: Merged
Approved by: LaMont Jones
Approved revision: no longer in the source branch.
Merged at revision: 5496
Proposed branch: lp:~lamont/maas/bug-1606508
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 208 lines (+131/-12)
5 files modified
src/maasserver/models/iprange.py (+4/-0)
src/maasserver/models/tests/test_iprange.py (+14/-0)
src/provisioningserver/dhcp/config.py (+45/-10)
src/provisioningserver/dhcp/tests/test_config.py (+66/-0)
src/provisioningserver/templates/dhcp/dhcpd6.conf.template (+2/-2)
To merge this branch: bzr merge lp:~lamont/maas/bug-1606508
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
Review via email: mp+308854@code.launchpad.net

Commit message

Properly configure DHCPv6 for high availability.

Description of the change

Properly configure DHCPv6 for high availability.

To post a comment you must log in.
Revision history for this message
LaMont Jones (lamont) wrote :

FWIW, I struggled to find a place where the tests for dhcp/config.py are not skipped, and failed (lxc, vm, and bare metal all skip them when running xenial, at a minimum.)

Fix verified via install-and-look technology.

Revision history for this message
Mike Pontillo (mpontillo) wrote :

Missing some unit tests. (Other than that, looks good.)

review: Needs Fixing
Revision history for this message
Mike Pontillo (mpontillo) wrote :

Looks good. Thanks for adding the tests.

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

The attempt to merge lp:~lamont/maas/bug-1606508 into lp:maas failed. Below is the output from the failed tests.

Hit:1 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:2 http://security.ubuntu.com/ubuntu xenial-security InRelease [94.5 kB]
Get:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [95.7 kB]
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Fetched 190 kB in 0s (293 kB/s)

sudo: unable to resolve host juju-prod-cdo-maas-machine-3
E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)
E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/models/iprange.py'
--- src/maasserver/models/iprange.py 2016-05-12 19:07:37 +0000
+++ src/maasserver/models/iprange.py 2016-10-19 22:51:50 +0000
@@ -161,6 +161,10 @@
161 if end_ip not in cidr:161 if end_ip not in cidr:
162 raise ValidationError(162 raise ValidationError(
163 "End IP address must be within subnet: %s." % cidr)163 "End IP address must be within subnet: %s." % cidr)
164 if (start_ip.version == 6 and self.type == IPRANGE_TYPE.DYNAMIC and
165 netaddr.IPRange(start_ip, end_ip).size < 256):
166 raise ValidationError(
167 "IPv6 dynamic range must be at least 256 addresses in size.")
164 self.clean_prevent_dupes_and_overlaps()168 self.clean_prevent_dupes_and_overlaps()
165169
166 @property170 @property
167171
=== modified file 'src/maasserver/models/tests/test_iprange.py'
--- src/maasserver/models/tests/test_iprange.py 2016-06-09 23:26:48 +0000
+++ src/maasserver/models/tests/test_iprange.py 2016-10-19 22:51:50 +0000
@@ -134,6 +134,20 @@
134 ValidationError, '.*End IP address must not be less than.*'):134 ValidationError, '.*End IP address must not be less than.*'):
135 iprange.save()135 iprange.save()
136136
137 def test__requires_256_addresses_for_ipv6_dynamic(self):
138 subnet = factory.make_Subnet(
139 cidr='2001:db8::/64', gateway_ip='fe80::1', dns_servers=[])
140 iprange = IPRange(
141 start_ip='2001:db8::', end_ip='2001:db8::fe',
142 user=factory.make_User(), subnet=subnet,
143 type=IPRANGE_TYPE.DYNAMIC,
144 comment="This is a comment.")
145 with ExpectedException(
146 ValidationError,
147 ".*IPv6 dynamic range must be "
148 "at least 256 addresses in size."):
149 iprange.save()
150
137 def test__requires_type(self):151 def test__requires_type(self):
138 subnet = make_plain_subnet()152 subnet = make_plain_subnet()
139 iprange = IPRange(153 iprange = IPRange(
140154
=== modified file 'src/provisioningserver/dhcp/config.py'
--- src/provisioningserver/dhcp/config.py 2016-09-26 15:35:54 +0000
+++ src/provisioningserver/dhcp/config.py 2016-10-19 22:51:50 +0000
@@ -20,6 +20,7 @@
20from netaddr import (20from netaddr import (
21 IPAddress,21 IPAddress,
22 IPNetwork,22 IPNetwork,
23 IPRange,
23)24)
24from provisioningserver.boot import BootMethodRegistry25from provisioningserver.boot import BootMethodRegistry
25from provisioningserver.utils import (26from provisioningserver.utils import (
@@ -296,6 +297,35 @@
296 IPAddress(addr)297 IPAddress(addr)
297 for addr in net_utils.get_all_interface_addresses()]298 for addr in net_utils.get_all_interface_addresses()]
298299
300 shared_networks = _process_network_parameters_v6(
301 rack_addrs, failover_peers, shared_networks)
302
303 try:
304 return template.substitute(
305 global_dhcp_snippets=global_dhcp_snippets, hosts=hosts,
306 failover_peers=failover_peers, shared_networks=shared_networks,
307 platform_codename=platform_codename,
308 omapi_key=omapi_key, **helpers)
309 except (KeyError, NameError) as error:
310 raise DHCPConfigError(
311 "Failed to render DHCP configuration.") from error
312
313
314def _process_network_parameters_v6(
315 rack_addrs, failover_peers, shared_networks):
316 """Preprocess shared_networks prior to rendering the template.
317
318 This is a separate function, partly for readability, and partly for ease
319 of testing.
320
321 :param rack_addrs: a list of IPAddress values for the interfaces on this
322 rack controller.
323 :param failover_peers: failover_peers from get_config_v6.
324 :param shared_networks: shared_networks from get_config_v6.
325 :return: an updated shared_networks, suitable for rendering the template.
326 """
327 peers = {x["name"]: x for x in failover_peers}
328
299 for shared_network in shared_networks:329 for shared_network in shared_networks:
300 for subnet in shared_network["subnets"]:330 for subnet in shared_network["subnets"]:
301 cidr = IPNetwork(subnet['subnet_cidr'])331 cidr = IPNetwork(subnet['subnet_cidr'])
@@ -312,13 +342,18 @@
312 ntp_servers_ipv4, ntp_servers_ipv6 = _get_addresses(*ntp_servers)342 ntp_servers_ipv4, ntp_servers_ipv6 = _get_addresses(*ntp_servers)
313 subnet["ntp_servers_ipv4"] = ", ".join(ntp_servers_ipv4)343 subnet["ntp_servers_ipv4"] = ", ".join(ntp_servers_ipv4)
314 subnet["ntp_servers_ipv6"] = ", ".join(ntp_servers_ipv6)344 subnet["ntp_servers_ipv6"] = ", ".join(ntp_servers_ipv6)
315345 for pool in subnet["pools"]:
316 try:346 peer = pool.get("failover_peer", None)
317 return template.substitute(347 if peer is not None:
318 global_dhcp_snippets=global_dhcp_snippets, hosts=hosts,348 ip_range = IPRange(
319 failover_peers=failover_peers, shared_networks=shared_networks,349 pool["ip_range_low"],
320 platform_codename=platform_codename,350 pool["ip_range_high"])
321 omapi_key=omapi_key, **helpers)351 if peers[peer]["mode"] == "primary":
322 except (KeyError, NameError) as error:352 pool["ip_range_high"] = str(
323 raise DHCPConfigError(353 IPAddress(
324 "Failed to render DHCP configuration.") from error354 ip_range.first + int(ip_range.size / 2) - 1))
355 else:
356 pool["ip_range_low"] = str(
357 IPAddress(
358 ip_range.first + int(ip_range.size / 2)))
359 return shared_networks
325360
=== modified file 'src/provisioningserver/dhcp/tests/test_config.py'
--- src/provisioningserver/dhcp/tests/test_config.py 2016-10-18 11:55:44 +0000
+++ src/provisioningserver/dhcp/tests/test_config.py 2016-10-19 22:51:50 +0000
@@ -475,6 +475,72 @@
475 Contains(expected))475 Contains(expected))
476476
477477
478class Test_process_shared_network_v6(MAASTestCase):
479 """Tests for `_process_network_parameters_v6`."""
480
481 scenarios = (
482 ('singleton', dict(
483 expected={
484 'ip_range_high': '2001:db8:3:1::ffff',
485 'ip_range_low': '2001:db8:3:1::',
486 'failover_peer': None},
487 rack_addrs=[netaddr.IPAddress('2001:db8:3:280::2')],
488 failover_peers=[])),
489 ('primary', dict(
490 expected={
491 'ip_range_high': '2001:db8:3:1::7fff',
492 'ip_range_low': '2001:db8:3:1::',
493 'failover_peer': 'failover-vlan-5020'},
494 rack_addrs=[netaddr.IPAddress('2001:db8:3:280::2')],
495 failover_peers=[{
496 'mode': 'primary',
497 'peer_address': '2001:db8:3:0:1::',
498 'name': 'failover-vlan-5020',
499 'address': '2001:db8:3:280::2'}])),
500 ('secondary', dict(
501 expected={
502 'ip_range_high': '2001:db8:3:1::ffff',
503 'ip_range_low': '2001:db8:3:1::8000',
504 'failover_peer': 'failover-vlan-5020'},
505 rack_addrs=[netaddr.IPAddress('2001:db8:3:0:1::')],
506 failover_peers=[{
507 'mode': 'secondary',
508 'address': '2001:db8:3:0:1::',
509 'name': 'failover-vlan-5020',
510 'peer_address': '2001:db8:3:280::2'}])))
511
512 def test__adjusts_parameters_for_primary(self):
513 shared_networks = [
514 {
515 'name': 'vlan-5020',
516 'subnets': [
517 {
518 'domain_name': 'maas.example.com',
519 'pools': [{
520 'ip_range_high': '2001:db8:3:1::ffff',
521 'ip_range_low': '2001:db8:3:1::',
522 'failover_peer': self.expected['failover_peer']}],
523 'dns_servers': [],
524 'subnet_mask': 'ffff:ffff:ffff:ffff::',
525 'ntp_servers': [],
526 'broadcast_ip': '2001:db8:3::ffff:ffff:ffff:ffff',
527 'router_ip': 'fe80::1',
528 'subnet': '2001:db8:3::',
529 'subnet_cidr': '2001:db8:3::/64',
530 'dhcp_snippets': []
531 }],
532 }]
533 self.patch(
534 config, 'compose_conditional_bootloader').return_value = ""
535 self.patch(
536 config, '_get_addresses').return_value = (
537 [''], ['2001:db8:280::2'])
538 actual = config._process_network_parameters_v6(
539 self.rack_addrs, self.failover_peers, shared_networks)
540 self.assertDictEqual(
541 actual[0]['subnets'][0]['pools'][0], self.expected)
542
543
478class TestComposeConditionalBootloader(MAASTestCase):544class TestComposeConditionalBootloader(MAASTestCase):
479 """Tests for `compose_conditional_bootloader`."""545 """Tests for `compose_conditional_bootloader`."""
480546
481547
=== modified file 'src/provisioningserver/templates/dhcp/dhcpd6.conf.template'
--- src/provisioningserver/templates/dhcp/dhcpd6.conf.template 2016-10-12 22:07:21 +0000
+++ src/provisioningserver/templates/dhcp/dhcpd6.conf.template 2016-10-19 22:51:50 +0000
@@ -50,8 +50,8 @@
50 option dhcp6.sntp-servers {{dhcp_subnet['ntp_servers_ipv6']}};50 option dhcp6.sntp-servers {{dhcp_subnet['ntp_servers_ipv6']}};
51 {{endif}}51 {{endif}}
5252
53 default-lease-time 600;53 default-lease-time 1800;
54 max-lease-time 600;54 max-lease-time 1800;
55 #55 #
56 # Subnet DHCP snippets56 # Subnet DHCP snippets
57 #57 #