Merge lp:~mpontillo/maas/subnet-dhcp-dns-settings--bug-1600720--2.0 into lp:maas/2.0
- subnet-dhcp-dns-settings--bug-1600720--2.0
- Merge into 2.0
Proposed by
Mike Pontillo
Status: | Merged |
---|---|
Approved by: | Mike Pontillo |
Approved revision: | no longer in the source branch. |
Merged at revision: | 5163 |
Proposed branch: | lp:~mpontillo/maas/subnet-dhcp-dns-settings--bug-1600720--2.0 |
Merge into: | lp:maas/2.0 |
Diff against target: |
347 lines (+173/-63) 3 files modified
docs/changelog.rst (+3/-1) src/maasserver/dhcp.py (+59/-32) src/maasserver/tests/test_dhcp.py (+111/-30) |
To merge this branch: | bzr merge lp:~mpontillo/maas/subnet-dhcp-dns-settings--bug-1600720--2.0 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike Pontillo (community) | Approve | ||
Review via email: mp+300211@code.launchpad.net |
Commit message
Merge revision 5169 from trunk.
Fix DHCP configuration to properly override subnet DNS with user-configured DNS. (This makes MAAS DHCP consistent with what curtin does.)
Drive-by fix to log an error when DHCP is enabled for a particular address family, but no subnet can be found. (Previous behavior was to silently fail to write the configuration; now if IPv6 is misconfigured, it will not prevent the IPv4 configuration from being written, and vice versa.)
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'docs/changelog.rst' | |||
2 | --- docs/changelog.rst 2016-07-15 02:22:48 +0000 | |||
3 | +++ docs/changelog.rst 2016-07-15 15:53:19 +0000 | |||
4 | @@ -15,7 +15,9 @@ | |||
5 | 15 | 15 | ||
6 | 16 | LP: #1603147 Commissioning dropdown is grey and checkmarks are missing. | 16 | LP: #1603147 Commissioning dropdown is grey and checkmarks are missing. |
7 | 17 | 17 | ||
9 | 18 | LP: #1576116 MAAS adds regions controller as DNS resolver | 18 | LP: #1576116 [2.0rc1] MAAS does not respect default subnet's DNS server when choosing default DNS |
10 | 19 | |||
11 | 20 | LP: #1600720 [2.0rc1] MAAS doesn't honor DNS settings for a subnet for DHCP | ||
12 | 19 | 21 | ||
13 | 20 | 22 | ||
14 | 21 | 2.0.0 (rc2) | 23 | 2.0.0 (rc2) |
15 | 22 | 24 | ||
16 | === modified file 'src/maasserver/dhcp.py' | |||
17 | --- src/maasserver/dhcp.py 2016-04-13 13:18:40 +0000 | |||
18 | +++ src/maasserver/dhcp.py 2016-07-15 15:53:19 +0000 | |||
19 | @@ -316,10 +316,17 @@ | |||
20 | 316 | 316 | ||
21 | 317 | 317 | ||
22 | 318 | def make_subnet_config( | 318 | def make_subnet_config( |
24 | 319 | rack_controller, subnet, dns_servers, ntp_server, default_domain, | 319 | rack_controller, subnet, maas_dns_server, ntp_server, default_domain, |
25 | 320 | failover_peer=None, subnets_dhcp_snippets=[]): | 320 | failover_peer=None, subnets_dhcp_snippets=[]): |
26 | 321 | """Return DHCP subnet configuration dict for a rack interface.""" | 321 | """Return DHCP subnet configuration dict for a rack interface.""" |
27 | 322 | ip_network = subnet.get_ipnetwork() | 322 | ip_network = subnet.get_ipnetwork() |
28 | 323 | if subnet.dns_servers is not None and len(subnet.dns_servers) > 0: | ||
29 | 324 | # Replace MAAS DNS with the servers defined on the subnet. | ||
30 | 325 | dns_servers = ", ".join(subnet.dns_servers) | ||
31 | 326 | elif maas_dns_server is not None and len(maas_dns_server) > 0: | ||
32 | 327 | dns_servers = maas_dns_server | ||
33 | 328 | else: | ||
34 | 329 | dns_servers = "" | ||
35 | 323 | return { | 330 | return { |
36 | 324 | 'subnet': str(ip_network.network), | 331 | 'subnet': str(ip_network.network), |
37 | 325 | 'subnet_mask': str(ip_network.netmask), | 332 | 'subnet_mask': str(ip_network.netmask), |
38 | @@ -368,12 +375,10 @@ | |||
39 | 368 | from maasserver.dns.zonegenerator import get_dns_server_address | 375 | from maasserver.dns.zonegenerator import get_dns_server_address |
40 | 369 | 376 | ||
41 | 370 | try: | 377 | try: |
43 | 371 | dns_servers = get_dns_server_address( | 378 | maas_dns_server = get_dns_server_address( |
44 | 372 | rack_controller, ipv4=(ip_version == 4), ipv6=(ip_version == 6)) | 379 | rack_controller, ipv4=(ip_version == 4), ipv6=(ip_version == 6)) |
45 | 373 | except UnresolvableHost: | 380 | except UnresolvableHost: |
49 | 374 | # No IPv6 DNS server addresses found. As a space-separated string, | 381 | maas_dns_server = None |
47 | 375 | # that becomes the empty string. | ||
48 | 376 | dns_servers = '' | ||
50 | 377 | 382 | ||
51 | 378 | # Select the best interface for this VLAN. This is an interface that | 383 | # Select the best interface for this VLAN. This is an interface that |
52 | 379 | # at least has an IP address. | 384 | # at least has an IP address. |
53 | @@ -382,9 +387,10 @@ | |||
54 | 382 | interface = get_best_interface(interfaces) | 387 | interface = get_best_interface(interfaces) |
55 | 383 | if interface is None: | 388 | if interface is None: |
56 | 384 | raise DHCPConfigurationError( | 389 | raise DHCPConfigurationError( |
60 | 385 | "No interface on rack controller '%s' has an IP address on any " | 390 | "No IPv%d interface on rack controller '%s' has an IP address on " |
61 | 386 | "subnet on VLAN '%s.%d'." % ( | 391 | "any subnet on VLAN '%s.%d'." % ( |
62 | 387 | rack_controller.hostname, vlan.fabric.name, vlan.vid)) | 392 | ip_version, rack_controller.hostname, vlan.fabric.name, |
63 | 393 | vlan.vid)) | ||
64 | 388 | 394 | ||
65 | 389 | # Generate the failover peer for this VLAN. | 395 | # Generate the failover peer for this VLAN. |
66 | 390 | if vlan.secondary_rack_id is not None: | 396 | if vlan.secondary_rack_id is not None: |
67 | @@ -406,7 +412,7 @@ | |||
68 | 406 | for subnet in subnets: | 412 | for subnet in subnets: |
69 | 407 | subnet_configs.append( | 413 | subnet_configs.append( |
70 | 408 | make_subnet_config( | 414 | make_subnet_config( |
72 | 409 | rack_controller, subnet, dns_servers, ntp_server, | 415 | rack_controller, subnet, maas_dns_server, ntp_server, |
73 | 410 | domain, peer_name, subnets_dhcp_snippets)) | 416 | domain, peer_name, subnets_dhcp_snippets)) |
74 | 411 | 417 | ||
75 | 412 | # Generate the hosts for all subnets. | 418 | # Generate the hosts for all subnets. |
76 | @@ -470,31 +476,52 @@ | |||
77 | 470 | for vlan, (subnets_v4, subnets_v6) in vlan_subnets.items(): | 476 | for vlan, (subnets_v4, subnets_v6) in vlan_subnets.items(): |
78 | 471 | # IPv4 | 477 | # IPv4 |
79 | 472 | if len(subnets_v4) > 0: | 478 | if len(subnets_v4) > 0: |
92 | 473 | failover_peer, subnets, hosts, interface = get_dhcp_configure_for( | 479 | try: |
93 | 474 | 4, rack_controller, vlan, subnets_v4, | 480 | config = get_dhcp_configure_for( |
94 | 475 | ntp_server, default_domain, dhcp_snippets) | 481 | 4, rack_controller, vlan, subnets_v4, ntp_server, |
95 | 476 | if failover_peer is not None: | 482 | default_domain, dhcp_snippets) |
96 | 477 | failover_peers_v4.append(failover_peer) | 483 | except DHCPConfigurationError as e: |
97 | 478 | shared_networks_v4.append({ | 484 | # XXX bug #1602412: this silently breaks DHCPv4, but we cannot |
98 | 479 | "name": "vlan-%d" % vlan.id, | 485 | # allow it to crash here since DHCPv6 might be able to run. |
99 | 480 | "subnets": subnets, | 486 | # This error may be irrelevant if there is an IPv4 network in |
100 | 481 | }) | 487 | # the MAAS model which is not configured on the rack, and the |
101 | 482 | hosts_v4.extend(hosts) | 488 | # user only wants to serve DHCPv6. But it is still something |
102 | 483 | interfaces_v4.add(interface) | 489 | # worth noting, so log it and continue. |
103 | 484 | 490 | log.err(e) | |
104 | 491 | else: | ||
105 | 492 | failover_peer, subnets, hosts, interface = config | ||
106 | 493 | if failover_peer is not None: | ||
107 | 494 | failover_peers_v4.append(failover_peer) | ||
108 | 495 | shared_networks_v4.append({ | ||
109 | 496 | "name": "vlan-%d" % vlan.id, | ||
110 | 497 | "subnets": subnets, | ||
111 | 498 | }) | ||
112 | 499 | hosts_v4.extend(hosts) | ||
113 | 500 | interfaces_v4.add(interface) | ||
114 | 485 | # IPv6 | 501 | # IPv6 |
115 | 486 | if len(subnets_v6) > 0: | 502 | if len(subnets_v6) > 0: |
127 | 487 | failover_peer, subnets, hosts, interface = get_dhcp_configure_for( | 503 | try: |
128 | 488 | 6, rack_controller, vlan, subnets_v6, | 504 | config = get_dhcp_configure_for( |
129 | 489 | ntp_server, default_domain, dhcp_snippets) | 505 | 6, rack_controller, vlan, subnets_v6, |
130 | 490 | if failover_peer is not None: | 506 | ntp_server, default_domain, dhcp_snippets) |
131 | 491 | failover_peers_v6.append(failover_peer) | 507 | except DHCPConfigurationError as e: |
132 | 492 | shared_networks_v6.append({ | 508 | # XXX bug #1602412: this silently breaks DHCPv6, but we cannot |
133 | 493 | "name": "vlan-%d" % vlan.id, | 509 | # allow it to crash here since DHCPv4 might be able to run. |
134 | 494 | "subnets": subnets, | 510 | # This error may be irrelevant if there is an IPv6 network in |
135 | 495 | }) | 511 | # the MAAS model which is not configured on the rack, and the |
136 | 496 | hosts_v6.extend(hosts) | 512 | # user only wants to serve DHCPv4. But it is still something |
137 | 497 | interfaces_v6.add(interface) | 513 | # worth noting, so log it and continue. |
138 | 514 | log.err(e) | ||
139 | 515 | else: | ||
140 | 516 | failover_peer, subnets, hosts, interface = config | ||
141 | 517 | if failover_peer is not None: | ||
142 | 518 | failover_peers_v6.append(failover_peer) | ||
143 | 519 | shared_networks_v6.append({ | ||
144 | 520 | "name": "vlan-%d" % vlan.id, | ||
145 | 521 | "subnets": subnets, | ||
146 | 522 | }) | ||
147 | 523 | hosts_v6.extend(hosts) | ||
148 | 524 | interfaces_v6.add(interface) | ||
149 | 498 | return ( | 525 | return ( |
150 | 499 | get_omapi_key(), | 526 | get_omapi_key(), |
151 | 500 | failover_peers_v4, shared_networks_v4, hosts_v4, interfaces_v4, | 527 | failover_peers_v4, shared_networks_v4, hosts_v4, interfaces_v4, |
152 | 501 | 528 | ||
153 | === modified file 'src/maasserver/tests/test_dhcp.py' | |||
154 | --- src/maasserver/tests/test_dhcp.py 2016-05-12 19:07:37 +0000 | |||
155 | +++ src/maasserver/tests/test_dhcp.py 2016-07-15 15:53:19 +0000 | |||
156 | @@ -45,6 +45,7 @@ | |||
157 | 45 | from maastesting.twisted import ( | 45 | from maastesting.twisted import ( |
158 | 46 | always_fail_with, | 46 | always_fail_with, |
159 | 47 | always_succeed_with, | 47 | always_succeed_with, |
160 | 48 | TwistedLoggerFixture, | ||
161 | 48 | ) | 49 | ) |
162 | 49 | from netaddr import ( | 50 | from netaddr import ( |
163 | 50 | IPAddress, | 51 | IPAddress, |
164 | @@ -627,23 +628,78 @@ | |||
165 | 627 | 'dhcp_snippets', | 628 | 'dhcp_snippets', |
166 | 628 | ])) | 629 | ])) |
167 | 629 | 630 | ||
183 | 630 | def test__sets_dns_and_ntp_from_arguments(self): | 631 | def test__sets_ipv4_dns_from_arguments(self): |
184 | 631 | rack_controller = factory.make_RackController(interface=False) | 632 | rack_controller = factory.make_RackController(interface=False) |
185 | 632 | vlan = factory.make_VLAN() | 633 | vlan = factory.make_VLAN() |
186 | 633 | subnet = factory.make_Subnet(vlan=vlan) | 634 | subnet = factory.make_Subnet(vlan=vlan, dns_servers=[], version=4) |
187 | 634 | factory.make_Interface( | 635 | factory.make_Interface( |
188 | 635 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | 636 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) |
189 | 636 | dns = '%s %s' % ( | 637 | maas_dns = factory.make_ipv4_address() |
190 | 637 | factory.make_ipv4_address(), | 638 | ntp = factory.make_name('ntp') |
191 | 638 | factory.make_ipv6_address(), | 639 | default_domain = Domain.objects.get_default_domain() |
192 | 639 | ) | 640 | config = dhcp.make_subnet_config( |
193 | 640 | ntp = factory.make_name('ntp') | 641 | rack_controller, subnet, maas_dns, ntp, default_domain) |
194 | 641 | default_domain = Domain.objects.get_default_domain() | 642 | self.expectThat(config['dns_servers'], Equals(maas_dns)) |
195 | 642 | config = dhcp.make_subnet_config( | 643 | |
196 | 643 | rack_controller, subnet, dns, ntp, default_domain) | 644 | def test__sets_ipv6_dns_from_arguments(self): |
197 | 644 | self.expectThat(config['dns_servers'], Equals(dns)) | 645 | rack_controller = factory.make_RackController(interface=False) |
198 | 646 | vlan = factory.make_VLAN() | ||
199 | 647 | subnet = factory.make_Subnet(vlan=vlan, dns_servers=[], version=6) | ||
200 | 648 | factory.make_Interface( | ||
201 | 649 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | ||
202 | 650 | maas_dns = factory.make_ipv6_address() | ||
203 | 651 | ntp = factory.make_name('ntp') | ||
204 | 652 | default_domain = Domain.objects.get_default_domain() | ||
205 | 653 | config = dhcp.make_subnet_config( | ||
206 | 654 | rack_controller, subnet, maas_dns, ntp, default_domain) | ||
207 | 655 | self.expectThat(config['dns_servers'], Equals(maas_dns)) | ||
208 | 656 | |||
209 | 657 | def test__sets_ntp_from_arguments(self): | ||
210 | 658 | rack_controller = factory.make_RackController(interface=False) | ||
211 | 659 | vlan = factory.make_VLAN() | ||
212 | 660 | subnet = factory.make_Subnet(vlan=vlan, dns_servers=[]) | ||
213 | 661 | factory.make_Interface( | ||
214 | 662 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | ||
215 | 663 | ntp = factory.make_name('ntp') | ||
216 | 664 | default_domain = Domain.objects.get_default_domain() | ||
217 | 665 | config = dhcp.make_subnet_config( | ||
218 | 666 | rack_controller, subnet, "", ntp, default_domain) | ||
219 | 645 | self.expectThat(config['ntp_server'], Equals(ntp)) | 667 | self.expectThat(config['ntp_server'], Equals(ntp)) |
220 | 646 | 668 | ||
221 | 669 | def test__overrides_ipv4_dns_from_subnet(self): | ||
222 | 670 | rack_controller = factory.make_RackController(interface=False) | ||
223 | 671 | vlan = factory.make_VLAN() | ||
224 | 672 | subnet = factory.make_Subnet(vlan=vlan, version=4) | ||
225 | 673 | maas_dns = factory.make_ipv4_address() | ||
226 | 674 | subnet_dns_servers = ["8.8.8.8", "8.8.4.4"] | ||
227 | 675 | subnet.dns_servers = subnet_dns_servers | ||
228 | 676 | subnet.save() | ||
229 | 677 | factory.make_Interface( | ||
230 | 678 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | ||
231 | 679 | ntp = factory.make_name('ntp') | ||
232 | 680 | default_domain = Domain.objects.get_default_domain() | ||
233 | 681 | config = dhcp.make_subnet_config( | ||
234 | 682 | rack_controller, subnet, maas_dns, ntp, default_domain) | ||
235 | 683 | self.expectThat( | ||
236 | 684 | config['dns_servers'], Equals(", ".join(subnet_dns_servers))) | ||
237 | 685 | |||
238 | 686 | def test__overrides_ipv6_dns_from_subnet(self): | ||
239 | 687 | rack_controller = factory.make_RackController(interface=False) | ||
240 | 688 | vlan = factory.make_VLAN() | ||
241 | 689 | subnet = factory.make_Subnet(vlan=vlan, version=6) | ||
242 | 690 | maas_dns = factory.make_ipv6_address() | ||
243 | 691 | subnet_dns_servers = ["2001:db8::1", "2001:db8::2"] | ||
244 | 692 | subnet.dns_servers = subnet_dns_servers | ||
245 | 693 | subnet.save() | ||
246 | 694 | factory.make_Interface( | ||
247 | 695 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | ||
248 | 696 | ntp = factory.make_name('ntp') | ||
249 | 697 | default_domain = Domain.objects.get_default_domain() | ||
250 | 698 | config = dhcp.make_subnet_config( | ||
251 | 699 | rack_controller, subnet, maas_dns, ntp, default_domain) | ||
252 | 700 | self.expectThat( | ||
253 | 701 | config['dns_servers'], Equals(", ".join(subnet_dns_servers))) | ||
254 | 702 | |||
255 | 647 | def test__sets_domain_name_from_passed_domain(self): | 703 | def test__sets_domain_name_from_passed_domain(self): |
256 | 648 | rack_controller = factory.make_RackController(interface=False) | 704 | rack_controller = factory.make_RackController(interface=False) |
257 | 649 | vlan = factory.make_VLAN() | 705 | vlan = factory.make_VLAN() |
258 | @@ -1121,7 +1177,8 @@ | |||
259 | 1121 | ha_vlan = factory.make_VLAN( | 1177 | ha_vlan = factory.make_VLAN( |
260 | 1122 | dhcp_on=True, primary_rack=primary_rack, | 1178 | dhcp_on=True, primary_rack=primary_rack, |
261 | 1123 | secondary_rack=secondary_rack) | 1179 | secondary_rack=secondary_rack) |
263 | 1124 | ha_subnet = factory.make_ipv4_Subnet_with_IPRanges(vlan=ha_vlan) | 1180 | ha_subnet = factory.make_ipv4_Subnet_with_IPRanges( |
264 | 1181 | vlan=ha_vlan, dns_servers=['127.0.0.1']) | ||
265 | 1125 | ha_network = ha_subnet.get_ipnetwork() | 1182 | ha_network = ha_subnet.get_ipnetwork() |
266 | 1126 | ha_dhcp_snippets = [ | 1183 | ha_dhcp_snippets = [ |
267 | 1127 | factory.make_DHCPSnippet(subnet=ha_subnet, enabled=True) | 1184 | factory.make_DHCPSnippet(subnet=ha_subnet, enabled=True) |
268 | @@ -1136,7 +1193,8 @@ | |||
269 | 1136 | secondary_ip = factory.make_StaticIPAddress( | 1193 | secondary_ip = factory.make_StaticIPAddress( |
270 | 1137 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=ha_subnet, | 1194 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=ha_subnet, |
271 | 1138 | interface=secondary_interface) | 1195 | interface=secondary_interface) |
273 | 1139 | other_subnet = factory.make_ipv4_Subnet_with_IPRanges(vlan=ha_vlan) | 1196 | other_subnet = factory.make_ipv4_Subnet_with_IPRanges( |
274 | 1197 | vlan=ha_vlan, dns_servers=['127.0.0.1']) | ||
275 | 1140 | other_network = other_subnet.get_ipnetwork() | 1198 | other_network = other_subnet.get_ipnetwork() |
276 | 1141 | other_dhcp_snippets = [ | 1199 | other_dhcp_snippets = [ |
277 | 1142 | factory.make_DHCPSnippet(subnet=other_subnet, enabled=True) | 1200 | factory.make_DHCPSnippet(subnet=other_subnet, enabled=True) |
278 | @@ -1358,7 +1416,8 @@ | |||
279 | 1358 | return cluster, cluster.ConfigureDHCPv4, cluster.ConfigureDHCPv6 | 1416 | return cluster, cluster.ConfigureDHCPv4, cluster.ConfigureDHCPv6 |
280 | 1359 | 1417 | ||
281 | 1360 | @transactional | 1418 | @transactional |
283 | 1361 | def create_rack_controller(self, dhcp_on=True): | 1419 | def create_rack_controller( |
284 | 1420 | self, dhcp_on=True, missing_ipv4=False, missing_ipv6=False): | ||
285 | 1362 | """Create a `rack_controller` in a state that will call both | 1421 | """Create a `rack_controller` in a state that will call both |
286 | 1363 | `ConfigureDHCPv4` and `ConfigureDHCPv6` with data.""" | 1422 | `ConfigureDHCPv4` and `ConfigureDHCPv6` with data.""" |
287 | 1364 | primary_rack = factory.make_RackController(interface=False) | 1423 | primary_rack = factory.make_RackController(interface=False) |
288 | @@ -1382,18 +1441,20 @@ | |||
289 | 1382 | subnet_v6, "fd38:c341:27da:c831:0:1::", | 1441 | subnet_v6, "fd38:c341:27da:c831:0:1::", |
290 | 1383 | "fd38:c341:27da:c831:0:1:ffff:0") | 1442 | "fd38:c341:27da:c831:0:1:ffff:0") |
291 | 1384 | 1443 | ||
304 | 1385 | factory.make_StaticIPAddress( | 1444 | if not missing_ipv4: |
305 | 1386 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v4, | 1445 | factory.make_StaticIPAddress( |
306 | 1387 | interface=primary_interface) | 1446 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v4, |
307 | 1388 | factory.make_StaticIPAddress( | 1447 | interface=primary_interface) |
308 | 1389 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v4, | 1448 | factory.make_StaticIPAddress( |
309 | 1390 | interface=secondary_interface) | 1449 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v4, |
310 | 1391 | factory.make_StaticIPAddress( | 1450 | interface=secondary_interface) |
311 | 1392 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v6, | 1451 | if not missing_ipv6: |
312 | 1393 | interface=primary_interface) | 1452 | factory.make_StaticIPAddress( |
313 | 1394 | factory.make_StaticIPAddress( | 1453 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v6, |
314 | 1395 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v6, | 1454 | interface=primary_interface) |
315 | 1396 | interface=secondary_interface) | 1455 | factory.make_StaticIPAddress( |
316 | 1456 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v6, | ||
317 | 1457 | interface=secondary_interface) | ||
318 | 1397 | 1458 | ||
319 | 1398 | for _ in range(3): | 1459 | for _ in range(3): |
320 | 1399 | factory.make_DHCPSnippet(subnet=subnet_v4, enabled=True) | 1460 | factory.make_DHCPSnippet(subnet=subnet_v4, enabled=True) |
321 | @@ -1448,6 +1509,26 @@ | |||
322 | 1448 | 1509 | ||
323 | 1449 | @wait_for_reactor | 1510 | @wait_for_reactor |
324 | 1450 | @inlineCallbacks | 1511 | @inlineCallbacks |
325 | 1512 | def test__logs_DHCPConfigurationError_ipv4(self): | ||
326 | 1513 | self.patch(dhcp.settings, "DHCP_CONNECT", True) | ||
327 | 1514 | with TwistedLoggerFixture() as logger: | ||
328 | 1515 | yield deferToDatabase( | ||
329 | 1516 | self.create_rack_controller, missing_ipv4=True) | ||
330 | 1517 | self.assertDocTestMatches( | ||
331 | 1518 | "...No IPv4 interface...", logger.output) | ||
332 | 1519 | |||
333 | 1520 | @wait_for_reactor | ||
334 | 1521 | @inlineCallbacks | ||
335 | 1522 | def test__logs_DHCPConfigurationError_ipv6(self): | ||
336 | 1523 | self.patch(dhcp.settings, "DHCP_CONNECT", True) | ||
337 | 1524 | with TwistedLoggerFixture() as logger: | ||
338 | 1525 | yield deferToDatabase( | ||
339 | 1526 | self.create_rack_controller, missing_ipv6=True) | ||
340 | 1527 | self.assertDocTestMatches( | ||
341 | 1528 | "...No IPv6 interface...", logger.output) | ||
342 | 1529 | |||
343 | 1530 | @wait_for_reactor | ||
344 | 1531 | @inlineCallbacks | ||
345 | 1451 | def test__doesnt_call_configure_for_both_ipv4_and_ipv6(self): | 1532 | def test__doesnt_call_configure_for_both_ipv4_and_ipv6(self): |
346 | 1452 | rack_controller, args = yield deferToDatabase( | 1533 | rack_controller, args = yield deferToDatabase( |
347 | 1453 | self.create_rack_controller) | 1534 | self.create_rack_controller) |
Self-reviewed backport.