Merge lp:~mpontillo/maas/subnet-dhcp-dns-settings--bug-1600720 into lp:~maas-committers/maas/trunk
- subnet-dhcp-dns-settings--bug-1600720
- Merge into trunk
Proposed by
Mike Pontillo
Status: | Merged |
---|---|
Approved by: | Mike Pontillo |
Approved revision: | no longer in the source branch. |
Merged at revision: | 5169 |
Proposed branch: | lp:~mpontillo/maas/subnet-dhcp-dns-settings--bug-1600720 |
Merge into: | lp:~maas-committers/maas/trunk |
Diff against target: |
332 lines (+170/-62) 2 files modified
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email: mp+299754@code.launchpad.net |
Commit message
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.
Revision history for this message
Mike Pontillo (mpontillo) wrote : | # |
Thanks for taking a look. Some replies below.
Revision history for this message
Gavin Panella (allenap) wrote : | # |
Thanks for the explanation; it all makes sense now.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/maasserver/dhcp.py' | |||
2 | --- src/maasserver/dhcp.py 2016-04-13 13:18:40 +0000 | |||
3 | +++ src/maasserver/dhcp.py 2016-07-12 20:50:38 +0000 | |||
4 | @@ -316,10 +316,17 @@ | |||
5 | 316 | 316 | ||
6 | 317 | 317 | ||
7 | 318 | def make_subnet_config( | 318 | def make_subnet_config( |
9 | 319 | rack_controller, subnet, dns_servers, ntp_server, default_domain, | 319 | rack_controller, subnet, maas_dns_server, ntp_server, default_domain, |
10 | 320 | failover_peer=None, subnets_dhcp_snippets=[]): | 320 | failover_peer=None, subnets_dhcp_snippets=[]): |
11 | 321 | """Return DHCP subnet configuration dict for a rack interface.""" | 321 | """Return DHCP subnet configuration dict for a rack interface.""" |
12 | 322 | ip_network = subnet.get_ipnetwork() | 322 | ip_network = subnet.get_ipnetwork() |
13 | 323 | if subnet.dns_servers is not None and len(subnet.dns_servers) > 0: | ||
14 | 324 | # Replace MAAS DNS with the servers defined on the subnet. | ||
15 | 325 | dns_servers = ", ".join(subnet.dns_servers) | ||
16 | 326 | elif maas_dns_server is not None and len(maas_dns_server) > 0: | ||
17 | 327 | dns_servers = maas_dns_server | ||
18 | 328 | else: | ||
19 | 329 | dns_servers = "" | ||
20 | 323 | return { | 330 | return { |
21 | 324 | 'subnet': str(ip_network.network), | 331 | 'subnet': str(ip_network.network), |
22 | 325 | 'subnet_mask': str(ip_network.netmask), | 332 | 'subnet_mask': str(ip_network.netmask), |
23 | @@ -368,12 +375,10 @@ | |||
24 | 368 | from maasserver.dns.zonegenerator import get_dns_server_address | 375 | from maasserver.dns.zonegenerator import get_dns_server_address |
25 | 369 | 376 | ||
26 | 370 | try: | 377 | try: |
28 | 371 | dns_servers = get_dns_server_address( | 378 | maas_dns_server = get_dns_server_address( |
29 | 372 | rack_controller, ipv4=(ip_version == 4), ipv6=(ip_version == 6)) | 379 | rack_controller, ipv4=(ip_version == 4), ipv6=(ip_version == 6)) |
30 | 373 | except UnresolvableHost: | 380 | except UnresolvableHost: |
34 | 374 | # No IPv6 DNS server addresses found. As a space-separated string, | 381 | maas_dns_server = None |
32 | 375 | # that becomes the empty string. | ||
33 | 376 | dns_servers = '' | ||
35 | 377 | 382 | ||
36 | 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 |
37 | 379 | # at least has an IP address. | 384 | # at least has an IP address. |
38 | @@ -382,9 +387,10 @@ | |||
39 | 382 | interface = get_best_interface(interfaces) | 387 | interface = get_best_interface(interfaces) |
40 | 383 | if interface is None: | 388 | if interface is None: |
41 | 384 | raise DHCPConfigurationError( | 389 | raise DHCPConfigurationError( |
45 | 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 " |
46 | 386 | "subnet on VLAN '%s.%d'." % ( | 391 | "any subnet on VLAN '%s.%d'." % ( |
47 | 387 | rack_controller.hostname, vlan.fabric.name, vlan.vid)) | 392 | ip_version, rack_controller.hostname, vlan.fabric.name, |
48 | 393 | vlan.vid)) | ||
49 | 388 | 394 | ||
50 | 389 | # Generate the failover peer for this VLAN. | 395 | # Generate the failover peer for this VLAN. |
51 | 390 | if vlan.secondary_rack_id is not None: | 396 | if vlan.secondary_rack_id is not None: |
52 | @@ -406,7 +412,7 @@ | |||
53 | 406 | for subnet in subnets: | 412 | for subnet in subnets: |
54 | 407 | subnet_configs.append( | 413 | subnet_configs.append( |
55 | 408 | make_subnet_config( | 414 | make_subnet_config( |
57 | 409 | rack_controller, subnet, dns_servers, ntp_server, | 415 | rack_controller, subnet, maas_dns_server, ntp_server, |
58 | 410 | domain, peer_name, subnets_dhcp_snippets)) | 416 | domain, peer_name, subnets_dhcp_snippets)) |
59 | 411 | 417 | ||
60 | 412 | # Generate the hosts for all subnets. | 418 | # Generate the hosts for all subnets. |
61 | @@ -470,31 +476,52 @@ | |||
62 | 470 | for vlan, (subnets_v4, subnets_v6) in vlan_subnets.items(): | 476 | for vlan, (subnets_v4, subnets_v6) in vlan_subnets.items(): |
63 | 471 | # IPv4 | 477 | # IPv4 |
64 | 472 | if len(subnets_v4) > 0: | 478 | if len(subnets_v4) > 0: |
77 | 473 | failover_peer, subnets, hosts, interface = get_dhcp_configure_for( | 479 | try: |
78 | 474 | 4, rack_controller, vlan, subnets_v4, | 480 | config = get_dhcp_configure_for( |
79 | 475 | ntp_server, default_domain, dhcp_snippets) | 481 | 4, rack_controller, vlan, subnets_v4, ntp_server, |
80 | 476 | if failover_peer is not None: | 482 | default_domain, dhcp_snippets) |
81 | 477 | failover_peers_v4.append(failover_peer) | 483 | except DHCPConfigurationError as e: |
82 | 478 | shared_networks_v4.append({ | 484 | # XXX bug #1602412: this silently breaks DHCPv4, but we cannot |
83 | 479 | "name": "vlan-%d" % vlan.id, | 485 | # allow it to crash here since DHCPv6 might be able to run. |
84 | 480 | "subnets": subnets, | 486 | # This error may be irrelevant if there is an IPv4 network in |
85 | 481 | }) | 487 | # the MAAS model which is not configured on the rack, and the |
86 | 482 | hosts_v4.extend(hosts) | 488 | # user only wants to serve DHCPv6. But it is still something |
87 | 483 | interfaces_v4.add(interface) | 489 | # worth noting, so log it and continue. |
88 | 484 | 490 | log.err(e) | |
89 | 491 | else: | ||
90 | 492 | failover_peer, subnets, hosts, interface = config | ||
91 | 493 | if failover_peer is not None: | ||
92 | 494 | failover_peers_v4.append(failover_peer) | ||
93 | 495 | shared_networks_v4.append({ | ||
94 | 496 | "name": "vlan-%d" % vlan.id, | ||
95 | 497 | "subnets": subnets, | ||
96 | 498 | }) | ||
97 | 499 | hosts_v4.extend(hosts) | ||
98 | 500 | interfaces_v4.add(interface) | ||
99 | 485 | # IPv6 | 501 | # IPv6 |
100 | 486 | if len(subnets_v6) > 0: | 502 | if len(subnets_v6) > 0: |
112 | 487 | failover_peer, subnets, hosts, interface = get_dhcp_configure_for( | 503 | try: |
113 | 488 | 6, rack_controller, vlan, subnets_v6, | 504 | config = get_dhcp_configure_for( |
114 | 489 | ntp_server, default_domain, dhcp_snippets) | 505 | 6, rack_controller, vlan, subnets_v6, |
115 | 490 | if failover_peer is not None: | 506 | ntp_server, default_domain, dhcp_snippets) |
116 | 491 | failover_peers_v6.append(failover_peer) | 507 | except DHCPConfigurationError as e: |
117 | 492 | shared_networks_v6.append({ | 508 | # XXX bug #1602412: this silently breaks DHCPv6, but we cannot |
118 | 493 | "name": "vlan-%d" % vlan.id, | 509 | # allow it to crash here since DHCPv4 might be able to run. |
119 | 494 | "subnets": subnets, | 510 | # This error may be irrelevant if there is an IPv6 network in |
120 | 495 | }) | 511 | # the MAAS model which is not configured on the rack, and the |
121 | 496 | hosts_v6.extend(hosts) | 512 | # user only wants to serve DHCPv4. But it is still something |
122 | 497 | interfaces_v6.add(interface) | 513 | # worth noting, so log it and continue. |
123 | 514 | log.err(e) | ||
124 | 515 | else: | ||
125 | 516 | failover_peer, subnets, hosts, interface = config | ||
126 | 517 | if failover_peer is not None: | ||
127 | 518 | failover_peers_v6.append(failover_peer) | ||
128 | 519 | shared_networks_v6.append({ | ||
129 | 520 | "name": "vlan-%d" % vlan.id, | ||
130 | 521 | "subnets": subnets, | ||
131 | 522 | }) | ||
132 | 523 | hosts_v6.extend(hosts) | ||
133 | 524 | interfaces_v6.add(interface) | ||
134 | 498 | return ( | 525 | return ( |
135 | 499 | get_omapi_key(), | 526 | get_omapi_key(), |
136 | 500 | failover_peers_v4, shared_networks_v4, hosts_v4, interfaces_v4, | 527 | failover_peers_v4, shared_networks_v4, hosts_v4, interfaces_v4, |
137 | 501 | 528 | ||
138 | === modified file 'src/maasserver/tests/test_dhcp.py' | |||
139 | --- src/maasserver/tests/test_dhcp.py 2016-06-21 10:29:11 +0000 | |||
140 | +++ src/maasserver/tests/test_dhcp.py 2016-07-12 20:50:38 +0000 | |||
141 | @@ -45,6 +45,7 @@ | |||
142 | 45 | from maastesting.twisted import ( | 45 | from maastesting.twisted import ( |
143 | 46 | always_fail_with, | 46 | always_fail_with, |
144 | 47 | always_succeed_with, | 47 | always_succeed_with, |
145 | 48 | TwistedLoggerFixture, | ||
146 | 48 | ) | 49 | ) |
147 | 49 | from netaddr import ( | 50 | from netaddr import ( |
148 | 50 | IPAddress, | 51 | IPAddress, |
149 | @@ -627,23 +628,78 @@ | |||
150 | 627 | 'dhcp_snippets', | 628 | 'dhcp_snippets', |
151 | 628 | ])) | 629 | ])) |
152 | 629 | 630 | ||
168 | 630 | def test__sets_dns_and_ntp_from_arguments(self): | 631 | def test__sets_ipv4_dns_from_arguments(self): |
169 | 631 | rack_controller = factory.make_RackController(interface=False) | 632 | rack_controller = factory.make_RackController(interface=False) |
170 | 632 | vlan = factory.make_VLAN() | 633 | vlan = factory.make_VLAN() |
171 | 633 | subnet = factory.make_Subnet(vlan=vlan) | 634 | subnet = factory.make_Subnet(vlan=vlan, dns_servers=[], version=4) |
172 | 634 | factory.make_Interface( | 635 | factory.make_Interface( |
173 | 635 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | 636 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) |
174 | 636 | dns = '%s %s' % ( | 637 | maas_dns = factory.make_ipv4_address() |
175 | 637 | factory.make_ipv4_address(), | 638 | ntp = factory.make_name('ntp') |
176 | 638 | factory.make_ipv6_address(), | 639 | default_domain = Domain.objects.get_default_domain() |
177 | 639 | ) | 640 | config = dhcp.make_subnet_config( |
178 | 640 | ntp = factory.make_name('ntp') | 641 | rack_controller, subnet, maas_dns, ntp, default_domain) |
179 | 641 | default_domain = Domain.objects.get_default_domain() | 642 | self.expectThat(config['dns_servers'], Equals(maas_dns)) |
180 | 642 | config = dhcp.make_subnet_config( | 643 | |
181 | 643 | rack_controller, subnet, dns, ntp, default_domain) | 644 | def test__sets_ipv6_dns_from_arguments(self): |
182 | 644 | self.expectThat(config['dns_servers'], Equals(dns)) | 645 | rack_controller = factory.make_RackController(interface=False) |
183 | 646 | vlan = factory.make_VLAN() | ||
184 | 647 | subnet = factory.make_Subnet(vlan=vlan, dns_servers=[], version=6) | ||
185 | 648 | factory.make_Interface( | ||
186 | 649 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | ||
187 | 650 | maas_dns = factory.make_ipv6_address() | ||
188 | 651 | ntp = factory.make_name('ntp') | ||
189 | 652 | default_domain = Domain.objects.get_default_domain() | ||
190 | 653 | config = dhcp.make_subnet_config( | ||
191 | 654 | rack_controller, subnet, maas_dns, ntp, default_domain) | ||
192 | 655 | self.expectThat(config['dns_servers'], Equals(maas_dns)) | ||
193 | 656 | |||
194 | 657 | def test__sets_ntp_from_arguments(self): | ||
195 | 658 | rack_controller = factory.make_RackController(interface=False) | ||
196 | 659 | vlan = factory.make_VLAN() | ||
197 | 660 | subnet = factory.make_Subnet(vlan=vlan, dns_servers=[]) | ||
198 | 661 | factory.make_Interface( | ||
199 | 662 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | ||
200 | 663 | ntp = factory.make_name('ntp') | ||
201 | 664 | default_domain = Domain.objects.get_default_domain() | ||
202 | 665 | config = dhcp.make_subnet_config( | ||
203 | 666 | rack_controller, subnet, "", ntp, default_domain) | ||
204 | 645 | self.expectThat(config['ntp_server'], Equals(ntp)) | 667 | self.expectThat(config['ntp_server'], Equals(ntp)) |
205 | 646 | 668 | ||
206 | 669 | def test__overrides_ipv4_dns_from_subnet(self): | ||
207 | 670 | rack_controller = factory.make_RackController(interface=False) | ||
208 | 671 | vlan = factory.make_VLAN() | ||
209 | 672 | subnet = factory.make_Subnet(vlan=vlan, version=4) | ||
210 | 673 | maas_dns = factory.make_ipv4_address() | ||
211 | 674 | subnet_dns_servers = ["8.8.8.8", "8.8.4.4"] | ||
212 | 675 | subnet.dns_servers = subnet_dns_servers | ||
213 | 676 | subnet.save() | ||
214 | 677 | factory.make_Interface( | ||
215 | 678 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | ||
216 | 679 | ntp = factory.make_name('ntp') | ||
217 | 680 | default_domain = Domain.objects.get_default_domain() | ||
218 | 681 | config = dhcp.make_subnet_config( | ||
219 | 682 | rack_controller, subnet, maas_dns, ntp, default_domain) | ||
220 | 683 | self.expectThat( | ||
221 | 684 | config['dns_servers'], Equals(", ".join(subnet_dns_servers))) | ||
222 | 685 | |||
223 | 686 | def test__overrides_ipv6_dns_from_subnet(self): | ||
224 | 687 | rack_controller = factory.make_RackController(interface=False) | ||
225 | 688 | vlan = factory.make_VLAN() | ||
226 | 689 | subnet = factory.make_Subnet(vlan=vlan, version=6) | ||
227 | 690 | maas_dns = factory.make_ipv6_address() | ||
228 | 691 | subnet_dns_servers = ["2001:db8::1", "2001:db8::2"] | ||
229 | 692 | subnet.dns_servers = subnet_dns_servers | ||
230 | 693 | subnet.save() | ||
231 | 694 | factory.make_Interface( | ||
232 | 695 | INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller) | ||
233 | 696 | ntp = factory.make_name('ntp') | ||
234 | 697 | default_domain = Domain.objects.get_default_domain() | ||
235 | 698 | config = dhcp.make_subnet_config( | ||
236 | 699 | rack_controller, subnet, maas_dns, ntp, default_domain) | ||
237 | 700 | self.expectThat( | ||
238 | 701 | config['dns_servers'], Equals(", ".join(subnet_dns_servers))) | ||
239 | 702 | |||
240 | 647 | def test__sets_domain_name_from_passed_domain(self): | 703 | def test__sets_domain_name_from_passed_domain(self): |
241 | 648 | rack_controller = factory.make_RackController(interface=False) | 704 | rack_controller = factory.make_RackController(interface=False) |
242 | 649 | vlan = factory.make_VLAN() | 705 | vlan = factory.make_VLAN() |
243 | @@ -1121,7 +1177,8 @@ | |||
244 | 1121 | ha_vlan = factory.make_VLAN( | 1177 | ha_vlan = factory.make_VLAN( |
245 | 1122 | dhcp_on=True, primary_rack=primary_rack, | 1178 | dhcp_on=True, primary_rack=primary_rack, |
246 | 1123 | secondary_rack=secondary_rack) | 1179 | secondary_rack=secondary_rack) |
248 | 1124 | ha_subnet = factory.make_ipv4_Subnet_with_IPRanges(vlan=ha_vlan) | 1180 | ha_subnet = factory.make_ipv4_Subnet_with_IPRanges( |
249 | 1181 | vlan=ha_vlan, dns_servers=['127.0.0.1']) | ||
250 | 1125 | ha_network = ha_subnet.get_ipnetwork() | 1182 | ha_network = ha_subnet.get_ipnetwork() |
251 | 1126 | ha_dhcp_snippets = [ | 1183 | ha_dhcp_snippets = [ |
252 | 1127 | factory.make_DHCPSnippet(subnet=ha_subnet, enabled=True) | 1184 | factory.make_DHCPSnippet(subnet=ha_subnet, enabled=True) |
253 | @@ -1136,7 +1193,8 @@ | |||
254 | 1136 | secondary_ip = factory.make_StaticIPAddress( | 1193 | secondary_ip = factory.make_StaticIPAddress( |
255 | 1137 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=ha_subnet, | 1194 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=ha_subnet, |
256 | 1138 | interface=secondary_interface) | 1195 | interface=secondary_interface) |
258 | 1139 | other_subnet = factory.make_ipv4_Subnet_with_IPRanges(vlan=ha_vlan) | 1196 | other_subnet = factory.make_ipv4_Subnet_with_IPRanges( |
259 | 1197 | vlan=ha_vlan, dns_servers=['127.0.0.1']) | ||
260 | 1140 | other_network = other_subnet.get_ipnetwork() | 1198 | other_network = other_subnet.get_ipnetwork() |
261 | 1141 | other_dhcp_snippets = [ | 1199 | other_dhcp_snippets = [ |
262 | 1142 | factory.make_DHCPSnippet(subnet=other_subnet, enabled=True) | 1200 | factory.make_DHCPSnippet(subnet=other_subnet, enabled=True) |
263 | @@ -1358,7 +1416,8 @@ | |||
264 | 1358 | return cluster, cluster.ConfigureDHCPv4, cluster.ConfigureDHCPv6 | 1416 | return cluster, cluster.ConfigureDHCPv4, cluster.ConfigureDHCPv6 |
265 | 1359 | 1417 | ||
266 | 1360 | @transactional | 1418 | @transactional |
268 | 1361 | def create_rack_controller(self, dhcp_on=True): | 1419 | def create_rack_controller( |
269 | 1420 | self, dhcp_on=True, missing_ipv4=False, missing_ipv6=False): | ||
270 | 1362 | """Create a `rack_controller` in a state that will call both | 1421 | """Create a `rack_controller` in a state that will call both |
271 | 1363 | `ConfigureDHCPv4` and `ConfigureDHCPv6` with data.""" | 1422 | `ConfigureDHCPv4` and `ConfigureDHCPv6` with data.""" |
272 | 1364 | primary_rack = factory.make_RackController(interface=False) | 1423 | primary_rack = factory.make_RackController(interface=False) |
273 | @@ -1382,18 +1441,20 @@ | |||
274 | 1382 | subnet_v6, "fd38:c341:27da:c831:0:1::", | 1441 | subnet_v6, "fd38:c341:27da:c831:0:1::", |
275 | 1383 | "fd38:c341:27da:c831:0:1:ffff:0") | 1442 | "fd38:c341:27da:c831:0:1:ffff:0") |
276 | 1384 | 1443 | ||
289 | 1385 | factory.make_StaticIPAddress( | 1444 | if not missing_ipv4: |
290 | 1386 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v4, | 1445 | factory.make_StaticIPAddress( |
291 | 1387 | interface=primary_interface) | 1446 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v4, |
292 | 1388 | factory.make_StaticIPAddress( | 1447 | interface=primary_interface) |
293 | 1389 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v4, | 1448 | factory.make_StaticIPAddress( |
294 | 1390 | interface=secondary_interface) | 1449 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v4, |
295 | 1391 | factory.make_StaticIPAddress( | 1450 | interface=secondary_interface) |
296 | 1392 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v6, | 1451 | if not missing_ipv6: |
297 | 1393 | interface=primary_interface) | 1452 | factory.make_StaticIPAddress( |
298 | 1394 | factory.make_StaticIPAddress( | 1453 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v6, |
299 | 1395 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v6, | 1454 | interface=primary_interface) |
300 | 1396 | interface=secondary_interface) | 1455 | factory.make_StaticIPAddress( |
301 | 1456 | alloc_type=IPADDRESS_TYPE.AUTO, subnet=subnet_v6, | ||
302 | 1457 | interface=secondary_interface) | ||
303 | 1397 | 1458 | ||
304 | 1398 | for _ in range(3): | 1459 | for _ in range(3): |
305 | 1399 | factory.make_DHCPSnippet(subnet=subnet_v4, enabled=True) | 1460 | factory.make_DHCPSnippet(subnet=subnet_v4, enabled=True) |
306 | @@ -1448,6 +1509,26 @@ | |||
307 | 1448 | 1509 | ||
308 | 1449 | @wait_for_reactor | 1510 | @wait_for_reactor |
309 | 1450 | @inlineCallbacks | 1511 | @inlineCallbacks |
310 | 1512 | def test__logs_DHCPConfigurationError_ipv4(self): | ||
311 | 1513 | self.patch(dhcp.settings, "DHCP_CONNECT", True) | ||
312 | 1514 | with TwistedLoggerFixture() as logger: | ||
313 | 1515 | yield deferToDatabase( | ||
314 | 1516 | self.create_rack_controller, missing_ipv4=True) | ||
315 | 1517 | self.assertDocTestMatches( | ||
316 | 1518 | "...No IPv4 interface...", logger.output) | ||
317 | 1519 | |||
318 | 1520 | @wait_for_reactor | ||
319 | 1521 | @inlineCallbacks | ||
320 | 1522 | def test__logs_DHCPConfigurationError_ipv6(self): | ||
321 | 1523 | self.patch(dhcp.settings, "DHCP_CONNECT", True) | ||
322 | 1524 | with TwistedLoggerFixture() as logger: | ||
323 | 1525 | yield deferToDatabase( | ||
324 | 1526 | self.create_rack_controller, missing_ipv6=True) | ||
325 | 1527 | self.assertDocTestMatches( | ||
326 | 1528 | "...No IPv6 interface...", logger.output) | ||
327 | 1529 | |||
328 | 1530 | @wait_for_reactor | ||
329 | 1531 | @inlineCallbacks | ||
330 | 1451 | def test__doesnt_call_configure_for_both_ipv4_and_ipv6(self): | 1532 | def test__doesnt_call_configure_for_both_ipv4_and_ipv6(self): |
331 | 1452 | rack_controller, args = yield deferToDatabase( | 1533 | rack_controller, args = yield deferToDatabase( |
332 | 1453 | self.create_rack_controller) | 1534 | self.create_rack_controller) |
Several comments, but the only one I'm really concerned about is the "may be irrelevant" one. With my limited context it seems to me that it ought to be more precise.