~ubuntu-branches/ubuntu/utopic/maas/utopic-security

« back to all changes in this revision

Viewing changes to src/maasserver/tests/test_dns.py

  • Committer: Package Import Robot
  • Author(s): Julian Edwards, Julian Edwards, Andres Rodriguez
  • Date: 2014-08-21 18:38:27 UTC
  • mfrom: (1.2.34)
  • Revision ID: package-import@ubuntu.com-20140821183827-9xyb5u2o4l8g3zxj
Tags: 1.6.1+bzr2550-0ubuntu1
* New upstream bugfix release:
  - Auto-link node MACs to Networks (LP: #1341619)

[ Julian Edwards ]
* debian/maas-region-controller.postinst: Don't restart RabbitMQ on
  upgrades, just ensure it's running.  Should prevent a race with the
  cluster celery restarting.
* debian/rules: Pull upstream branch from the right place.

[ Andres Rodriguez ]
* debian/maas-region-controller.postinst: Ensure cluster celery is
  started if it also runs on the region.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
 
18
18
from itertools import islice
 
19
import random
19
20
import socket
20
21
 
21
22
from celery.task import task
26
27
    server_address,
27
28
    )
28
29
from maasserver.enum import (
 
30
    NODE_STATUS,
29
31
    NODEGROUP_STATUS,
30
32
    NODEGROUPINTERFACE_MANAGEMENT,
31
33
    )
36
38
from maasserver.testing.factory import factory
37
39
from maasserver.testing.testcase import MAASServerTestCase
38
40
from maasserver.utils import map_enum
39
 
from maastesting.celery import CeleryFixture
40
41
from maastesting.fakemethod import FakeMethod
41
 
from maastesting.matchers import MockCalledOnceWith
 
42
from maastesting.matchers import (
 
43
    MockCalledOnceWith,
 
44
    MockNotCalled,
 
45
    )
42
46
from mock import (
43
47
    ANY,
44
48
    call,
45
49
    Mock,
46
50
    )
47
51
from netaddr import (
 
52
    IPAddress,
48
53
    IPNetwork,
49
54
    IPRange,
50
55
    )
54
59
    DNSForwardZoneConfig,
55
60
    DNSReverseZoneConfig,
56
61
    DNSZoneConfigBase,
 
62
    SRVRecord,
57
63
    )
58
 
from provisioningserver.dns.utils import generated_hostname
59
64
from provisioningserver.testing.bindfixture import BINDServer
60
65
from provisioningserver.testing.tests.test_bindfixture import dig_call
61
66
from rabbitfixture.server import allocate_ports
62
 
from testresources import FixtureResource
63
67
from testtools import TestCase
64
68
from testtools.matchers import (
65
69
    IsInstance,
66
70
    MatchesAll,
67
 
    MatchesListwise,
 
71
    MatchesSetwise,
68
72
    MatchesStructure,
69
73
    )
70
74
 
132
136
            (ip, [(hostname, )]),
133
137
            (dns.get_dns_server_address(nodegroup), resolver.extract_args()))
134
138
 
 
139
    def test_warn_loopback_warns_about_IPv4_loopback(self):
 
140
        logger = self.patch(dns, 'logger')
 
141
        loopback = '127.0.0.1'
 
142
        dns.warn_loopback(loopback)
 
143
        self.assertThat(
 
144
            logger.warn, MockCalledOnceWith(dns.WARNING_MESSAGE % loopback))
 
145
 
 
146
    def test_warn_loopback_warns_about_any_IPv4_loopback(self):
 
147
        logger = self.patch(dns, 'logger')
 
148
        loopback = '127.254.100.99'
 
149
        dns.warn_loopback(loopback)
 
150
        self.assertThat(logger.warn, MockCalledOnceWith(ANY))
 
151
 
 
152
    def test_warn_loopback_warns_about_IPv6_loopback(self):
 
153
        logger = self.patch(dns, 'logger')
 
154
        loopback = '::1'
 
155
        dns.warn_loopback(loopback)
 
156
        self.assertThat(logger.warn, MockCalledOnceWith(ANY))
 
157
 
 
158
    def test_warn_loopback_does_not_warn_about_sensible_IPv4(self):
 
159
        logger = self.patch(dns, 'logger')
 
160
        dns.warn_loopback('10.1.2.3')
 
161
        self.assertThat(logger.warn, MockNotCalled())
 
162
 
 
163
    def test_warn_loopback_does_not_warn_about_sensible_IPv6(self):
 
164
        logger = self.patch(dns, 'logger')
 
165
        dns.warn_loopback('1::9')
 
166
        self.assertThat(logger.warn, MockNotCalled())
 
167
 
135
168
 
136
169
class TestLazyDict(TestCase):
137
170
    """Tests for `lazydict`."""
164
197
        self.assertEqual({key1: key1, key2: key2}, value_dict)
165
198
 
166
199
 
167
 
class TestDNSConfigModifications(MAASServerTestCase):
168
 
 
169
 
    resources = (
170
 
        ("celery", FixtureResource(CeleryFixture())),
171
 
        )
 
200
class TestGetHostnameIPMapping(MAASServerTestCase):
 
201
    """Test for `get_hostname_ip_mapping`."""
 
202
 
 
203
    def test_get_hostname_ip_mapping_combines_mappings(self):
 
204
        nodegroup = factory.make_node_group()
 
205
        # Create dynamic mapping for an allocated node.
 
206
        node1 = factory.make_node(
 
207
            nodegroup=nodegroup, status=NODE_STATUS.ALLOCATED)
 
208
        mac = factory.make_mac_address(node=node1)
 
209
        lease = factory.make_dhcp_lease(
 
210
            nodegroup=nodegroup, mac=mac.mac_address)
 
211
        # Create static mapping for an allocated node.
 
212
        node2 = factory.make_node_with_mac_attached_to_nodegroupinterface(
 
213
            nodegroup=nodegroup)
 
214
        staticip = factory.make_staticipaddress(mac=node2.get_primary_mac())
 
215
 
 
216
        expected_mapping = {
 
217
            node1.hostname: lease.ip,
 
218
            node2.hostname: staticip.ip,
 
219
        }
 
220
        self.assertEqual(
 
221
            expected_mapping, dns.get_hostname_ip_mapping(nodegroup))
 
222
 
 
223
    def test_get_hostname_ip_mapping_gives_precedence_to_static_mappings(self):
 
224
        nodegroup = factory.make_node_group()
 
225
        # Create dynamic mapping for an allocated node.
 
226
        node = factory.make_node(
 
227
            nodegroup=nodegroup, status=NODE_STATUS.ALLOCATED)
 
228
        mac = factory.make_mac_address(node=node)
 
229
        factory.make_dhcp_lease(
 
230
            nodegroup=nodegroup, mac=mac.mac_address)
 
231
        # Create static mapping for the *same* node.
 
232
        staticip = factory.make_staticipaddress(mac=node.get_primary_mac())
 
233
 
 
234
        expected_mapping = {
 
235
            node.hostname: staticip.ip,
 
236
        }
 
237
        self.assertEqual(
 
238
            expected_mapping, dns.get_hostname_ip_mapping(nodegroup))
 
239
 
 
240
 
 
241
class TestDNSServer(MAASServerTestCase):
 
242
    """A base class to perform real-world DNS-related tests.
 
243
 
 
244
    The class starts a BINDServer for every test and provides a set of
 
245
    helper methods to perform DNS queries.
 
246
 
 
247
    Because of the overhead added by starting and stopping the DNS
 
248
    server, new tests in this class and its descendants are expensive.
 
249
    """
172
250
 
173
251
    def setUp(self):
174
 
        super(TestDNSConfigModifications, self).setUp()
 
252
        super(TestDNSServer, self).setUp()
175
253
        self.bind = self.useFixture(BINDServer())
176
254
        self.patch(conf, 'DNS_CONFIG_DIR', self.bind.config.homedir)
177
255
 
189
267
        # Reload BIND.
190
268
        self.bind.runner.rndc('reload')
191
269
 
192
 
    def create_managed_nodegroup(self):
 
270
    def create_managed_nodegroup(self, network=None):
 
271
        if network is None:
 
272
            network = IPNetwork('192.168.0.1/24')
193
273
        return factory.make_node_group(
194
 
            network=IPNetwork('192.168.0.1/24'),
 
274
            network=network,
195
275
            status=NODEGROUP_STATUS.ACCEPTED,
196
276
            management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS)
197
277
 
198
 
    def create_nodegroup_with_lease(self, lease_number=1, nodegroup=None):
 
278
    def create_nodegroup_with_static_ip(self, lease_number=1, nodegroup=None):
199
279
        if nodegroup is None:
200
280
            nodegroup = self.create_managed_nodegroup()
201
281
        [interface] = nodegroup.get_managed_interfaces()
202
282
        node = factory.make_node(
203
283
            nodegroup=nodegroup)
204
 
        mac = factory.make_mac_address(node=node)
205
 
        ips = IPRange(interface.ip_range_low, interface.ip_range_high)
206
 
        lease_ip = unicode(islice(ips, lease_number, lease_number + 1).next())
207
 
        lease = factory.make_dhcp_lease(
208
 
            nodegroup=nodegroup, mac=mac.mac_address, ip=lease_ip)
209
 
        # Simulate that this lease was created by
210
 
        # DHCPLease.objects.update_leases: update its DNS config.
 
284
        mac = factory.make_mac_address(node=node, cluster_interface=interface)
 
285
        ips = IPRange(
 
286
            interface.static_ip_range_low, interface.static_ip_range_high)
 
287
        static_ip = unicode(islice(ips, lease_number, lease_number + 1).next())
 
288
        staticaddress = factory.make_staticipaddress(ip=static_ip, mac=mac)
211
289
        dns.change_dns_zones([nodegroup])
212
 
        return nodegroup, node, lease
 
290
        return nodegroup, node, staticaddress
213
291
 
214
 
    def dig_resolve(self, fqdn):
 
292
    def dig_resolve(self, fqdn, version=4):
215
293
        """Resolve `fqdn` using dig.  Returns a list of results."""
 
294
        # Using version=6 has two effects:
 
295
        # - it changes the type of query from 'A' to 'AAAA';
 
296
        # - it forces dig to only use IPv6 query transport.
 
297
        record_type = 'AAAA' if version == 6 else 'A'
 
298
        commands = [fqdn, '+short', '-%i' % version, record_type]
216
299
        return dig_call(
217
300
            port=self.bind.config.port,
218
 
            commands=[fqdn, '+short']).split('\n')
 
301
            commands=commands).split('\n')
219
302
 
220
 
    def dig_reverse_resolve(self, ip):
 
303
    def dig_reverse_resolve(self, ip, version=4):
221
304
        """Reverse resolve `ip` using dig.  Returns a list of results."""
222
305
        return dig_call(
223
306
            port=self.bind.config.port,
224
 
            commands=['-x', ip, '+short']).split('\n')
 
307
            commands=['-x', ip, '+short', '-%i' % version]).split('\n')
225
308
 
226
 
    def assertDNSMatches(self, hostname, domain, ip):
 
309
    def assertDNSMatches(self, hostname, domain, ip, version=4):
 
310
        # A forward lookup on the hostname returns the IP address.
227
311
        fqdn = "%s.%s" % (hostname, domain)
228
 
        autogenerated_hostname = '%s.' % generated_hostname(ip, domain)
229
 
        forward_lookup_result = self.dig_resolve(fqdn)
230
 
        if '%s.' % fqdn == autogenerated_hostname:
231
 
            # If the fqdn is an autogenerated hostname, it resolves to the IP
232
 
            # address (A record).
233
 
            expected_results = [ip]
234
 
        else:
235
 
            # If the fqdn is a custom hostname, it resolves to the
236
 
            # autogenerated hostname (CNAME record) and the IP address
237
 
            # (A record).
238
 
            expected_results = [autogenerated_hostname, ip]
 
312
        forward_lookup_result = self.dig_resolve(fqdn, version=version)
239
313
        self.assertEqual(
240
 
            expected_results, forward_lookup_result,
 
314
            [ip], forward_lookup_result,
241
315
            "Failed to resolve '%s' (results: '%s')." % (
242
316
                fqdn, ','.join(forward_lookup_result)))
243
 
        # A reverse lookup on the IP returns the autogenerated
244
 
        # hostname.
245
 
        reverse_lookup_result = self.dig_reverse_resolve(ip)
 
317
        # A reverse lookup on the IP address returns the hostname.
 
318
        reverse_lookup_result = self.dig_reverse_resolve(
 
319
            ip, version=version)
246
320
        self.assertEqual(
247
 
            [autogenerated_hostname], reverse_lookup_result,
 
321
            ["%s." % fqdn], reverse_lookup_result,
248
322
            "Failed to reverse resolve '%s' (results: '%s')." % (
249
323
                fqdn, ','.join(reverse_lookup_result)))
250
324
 
 
325
 
 
326
class TestDNSConfigModifications(TestDNSServer):
 
327
 
251
328
    def test_add_zone_loads_dns_zone(self):
252
 
        nodegroup, node, lease = self.create_nodegroup_with_lease()
 
329
        nodegroup, node, static = self.create_nodegroup_with_static_ip()
253
330
        self.patch(settings, 'DNS_CONNECT', True)
254
331
        dns.add_zone(nodegroup)
255
 
        self.assertDNSMatches(node.hostname, nodegroup.name, lease.ip)
 
332
        self.assertDNSMatches(node.hostname, nodegroup.name, static.ip)
256
333
 
257
334
    def test_change_dns_zone_changes_dns_zone(self):
258
 
        nodegroup, _, _ = self.create_nodegroup_with_lease()
 
335
        nodegroup, _, _ = self.create_nodegroup_with_static_ip()
259
336
        self.patch(settings, 'DNS_CONNECT', True)
260
337
        dns.write_full_dns_config()
261
 
        nodegroup, new_node, new_lease = (
262
 
            self.create_nodegroup_with_lease(
 
338
        nodegroup, new_node, new_static = (
 
339
            self.create_nodegroup_with_static_ip(
263
340
                nodegroup=nodegroup, lease_number=2))
264
341
        dns.change_dns_zones(nodegroup)
265
 
        self.assertDNSMatches(new_node.hostname, nodegroup.name, new_lease.ip)
 
342
        self.assertDNSMatches(new_node.hostname, nodegroup.name, new_static.ip)
266
343
 
267
344
    def test_is_dns_enabled_return_false_if_DNS_CONNECT_False(self):
268
345
        self.patch(settings, 'DNS_CONNECT', False)
280
357
        self.assertTrue(dns.is_dns_in_use())
281
358
 
282
359
    def test_write_full_dns_loads_full_dns_config(self):
283
 
        nodegroup, node, lease = self.create_nodegroup_with_lease()
 
360
        nodegroup, node, static = self.create_nodegroup_with_static_ip()
284
361
        self.patch(settings, 'DNS_CONNECT', True)
285
362
        dns.write_full_dns_config()
286
 
        self.assertDNSMatches(node.hostname, nodegroup.name, lease.ip)
 
363
        self.assertDNSMatches(node.hostname, nodegroup.name, static.ip)
287
364
 
288
365
    def test_write_full_dns_passes_reload_retry_parameter(self):
289
366
        self.patch(settings, 'DNS_CONNECT', True)
317
394
    def test_dns_config_has_NS_record(self):
318
395
        ip = factory.getRandomIPAddress()
319
396
        self.patch(settings, 'DEFAULT_MAAS_URL', 'http://%s/' % ip)
320
 
        nodegroup, node, lease = self.create_nodegroup_with_lease()
 
397
        nodegroup, node, static = self.create_nodegroup_with_static_ip()
321
398
        self.patch(settings, 'DNS_CONNECT', True)
322
399
        dns.write_full_dns_config()
323
400
        # Get the NS record for the zone 'nodegroup.name'.
329
406
            port=self.bind.config.port, commands=[ns_record, '+short'])
330
407
        self.assertEqual(ip, ip_of_ns_record)
331
408
 
332
 
    def test_add_nodegroup_creates_DNS_zone(self):
333
 
        self.patch(settings, "DNS_CONNECT", True)
334
 
        network = IPNetwork('192.168.7.1/24')
335
 
        ip = factory.getRandomIPInNetwork(network)
336
 
        nodegroup = factory.make_node_group(
337
 
            network=network, status=NODEGROUP_STATUS.ACCEPTED,
338
 
            management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS)
339
 
        self.assertDNSMatches(generated_hostname(ip), nodegroup.name, ip)
340
 
 
341
409
    def test_edit_nodegroupinterface_updates_DNS_zone(self):
342
410
        self.patch(settings, "DNS_CONNECT", True)
343
411
        old_network = IPNetwork('192.168.7.1/24')
344
 
        old_ip = factory.getRandomIPInNetwork(old_network)
345
412
        nodegroup = factory.make_node_group(
346
413
            network=old_network, status=NODEGROUP_STATUS.ACCEPTED,
347
414
            management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS)
348
415
        [interface] = nodegroup.get_managed_interfaces()
 
416
        _, node, lease = self.create_nodegroup_with_static_ip(
 
417
            nodegroup=nodegroup)
 
418
        self.assertEqual(
 
419
            ["%s." % node.fqdn], self.dig_reverse_resolve(lease.ip))
349
420
        # Edit nodegroup's network information to '192.168.44.1/24'
350
421
        interface.ip = '192.168.44.7'
351
422
        interface.router_ip = '192.168.44.14'
352
423
        interface.broadcast_ip = '192.168.44.255'
353
424
        interface.netmask = '255.255.255.0'
354
425
        interface.ip_range_low = '192.168.44.0'
355
 
        interface.ip_range_high = '192.168.44.255'
 
426
        interface.ip_range_high = '192.168.44.128'
 
427
        interface.static_ip_range_low = '192.168.44.129'
 
428
        interface.static_ip_range_high = '192.168.44.255'
356
429
        interface.save()
357
 
        ip = factory.getRandomIPInNetwork(IPNetwork('192.168.44.1/24'))
358
 
        # The ip from the old network does not resolve anymore.
359
 
        self.assertEqual([''], self.dig_resolve(generated_hostname(old_ip)))
360
 
        self.assertEqual([''], self.dig_reverse_resolve(old_ip))
361
 
        # The ip from the new network resolves.
362
 
        self.assertDNSMatches(generated_hostname(ip), nodegroup.name, ip)
 
430
        # The IP from the old network does not resolve anymore.
 
431
        self.assertEqual([''], self.dig_reverse_resolve(lease.ip))
 
432
        # A lease in the new network resolves.
 
433
        _, node, lease = self.create_nodegroup_with_static_ip(
 
434
            nodegroup=nodegroup)
 
435
        self.assertTrue(
 
436
            IPAddress(lease.ip) in interface.network,
 
437
            "The lease IP Address is not in the new network")
 
438
        self.assertEqual(
 
439
            ["%s." % node.fqdn], self.dig_reverse_resolve(lease.ip))
363
440
 
364
441
    def test_changing_interface_management_updates_DNS_zone(self):
365
442
        self.patch(settings, "DNS_CONNECT", True)
371
448
        [interface] = nodegroup.get_managed_interfaces()
372
449
        interface.management = NODEGROUPINTERFACE_MANAGEMENT.UNMANAGED
373
450
        interface.save()
374
 
        self.assertEqual([''], self.dig_resolve(generated_hostname(ip)))
375
451
        self.assertEqual([''], self.dig_reverse_resolve(ip))
376
452
 
377
453
    def test_delete_nodegroup_disables_DNS_zone(self):
382
458
            network=network, status=NODEGROUP_STATUS.ACCEPTED,
383
459
            management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS)
384
460
        nodegroup.delete()
385
 
        self.assertEqual([''], self.dig_resolve(generated_hostname(ip)))
386
461
        self.assertEqual([''], self.dig_reverse_resolve(ip))
387
462
 
388
463
    def test_add_node_updates_zone(self):
389
464
        self.patch(settings, "DNS_CONNECT", True)
390
 
        nodegroup, node, lease = self.create_nodegroup_with_lease()
391
 
        self.assertDNSMatches(node.hostname, nodegroup.name, lease.ip)
 
465
        nodegroup, node, static = self.create_nodegroup_with_static_ip()
 
466
        self.assertDNSMatches(node.hostname, nodegroup.name, static.ip)
392
467
 
393
468
    def test_delete_node_updates_zone(self):
394
469
        self.patch(settings, "DNS_CONNECT", True)
395
 
        nodegroup, node, lease = self.create_nodegroup_with_lease()
 
470
        nodegroup, node, static = self.create_nodegroup_with_static_ip()
396
471
        # Prevent omshell task dispatch.
397
472
        self.patch(node_module, "remove_dhcp_host_map")
398
473
        node.delete()
401
476
 
402
477
    def test_change_node_hostname_updates_zone(self):
403
478
        self.patch(settings, "DNS_CONNECT", True)
404
 
        nodegroup, node, lease = self.create_nodegroup_with_lease()
 
479
        nodegroup, node, static = self.create_nodegroup_with_static_ip()
405
480
        node.hostname = factory.make_name('hostname')
406
481
        node.save()
407
 
        self.assertDNSMatches(node.hostname, nodegroup.name, lease.ip)
 
482
        self.assertDNSMatches(node.hostname, nodegroup.name, static.ip)
408
483
 
409
484
    def test_change_node_other_field_does_not_update_zone(self):
410
485
        self.patch(settings, "DNS_CONNECT", True)
411
 
        nodegroup, node, lease = self.create_nodegroup_with_lease()
 
486
        nodegroup, node, static = self.create_nodegroup_with_static_ip()
412
487
        recorder = FakeMethod()
413
488
        self.patch(DNSZoneConfigBase, 'write_config', recorder)
414
489
        node.error = factory.getRandomString()
416
491
        self.assertEqual(0, recorder.call_count)
417
492
 
418
493
 
419
 
def forward_zone(domain, *networks):
 
494
class TestDNSBackwardCompat(TestDNSServer):
 
495
    """Allocated nodes with IP addresses in the dynamic range get a DNS
 
496
    record.
 
497
    """
 
498
 
 
499
    def test_bind_configuration_includes_dynamic_ips_of_allocated_nodes(self):
 
500
        self.patch(settings, "DNS_CONNECT", True)
 
501
        network = IPNetwork('192.168.7.1/24')
 
502
        nodegroup = self.create_managed_nodegroup(network=network)
 
503
        [interface] = nodegroup.get_managed_interfaces()
 
504
        node = factory.make_node(
 
505
            nodegroup=nodegroup, status=NODE_STATUS.ALLOCATED)
 
506
        mac = factory.make_mac_address(node=node, cluster_interface=interface)
 
507
        # Get an IP in the dynamic range.
 
508
        ip_range = IPRange(
 
509
            interface.ip_range_low, interface.ip_range_high)
 
510
        ip = "%s" % random.choice(ip_range)
 
511
        lease = factory.make_dhcp_lease(
 
512
            nodegroup=nodegroup, mac=mac.mac_address, ip=ip)
 
513
        dns.change_dns_zones([nodegroup])
 
514
        self.assertDNSMatches(node.hostname, nodegroup.name, lease.ip)
 
515
 
 
516
 
 
517
class TestIPv6DNS(TestDNSServer):
 
518
 
 
519
    def test_bind_configuration_includes_ipv6_zone(self):
 
520
        self.patch(settings, "DNS_CONNECT", True)
 
521
        network = IPNetwork('fe80::/64')
 
522
        nodegroup = self.create_managed_nodegroup(network=network)
 
523
        nodegroup, node, static = self.create_nodegroup_with_static_ip(
 
524
            nodegroup=nodegroup)
 
525
        self.assertDNSMatches(
 
526
            node.hostname, nodegroup.name, static.ip, version=6)
 
527
 
 
528
 
 
529
def forward_zone(domain):
420
530
    """
421
531
    Returns a matcher for a :class:`DNSForwardZoneConfig` with the given
422
 
    domain and networks.
 
532
    domain.
423
533
    """
424
 
    networks = {IPNetwork(network) for network in networks}
425
534
    return MatchesAll(
426
535
        IsInstance(DNSForwardZoneConfig),
427
 
        MatchesStructure.byEquality(
428
 
            domain=domain, _networks=networks))
 
536
        MatchesStructure.byEquality(domain=domain))
429
537
 
430
538
 
431
539
def reverse_zone(domain, network):
564
672
            },
565
673
            networks_dict)
566
674
 
 
675
    def test_get_srv_mappings_returns_empty_list_when_no_windows_kms(self):
 
676
        Config.objects.set_config("windows_kms_host", None)
 
677
        self.assertItemsEqual([], dns.ZoneGenerator._get_srv_mappings())
 
678
 
 
679
    def test_get_srv_mappings_returns_kms_srv_record(self):
 
680
        hostname = factory.make_name('hostname')
 
681
        Config.objects.set_config("windows_kms_host", hostname)
 
682
        srv = SRVRecord(
 
683
            service='_vlmcs._tcp', port=1688, target=hostname,
 
684
            priority=0, weight=0)
 
685
        self.assertItemsEqual([srv], dns.ZoneGenerator._get_srv_mappings())
 
686
 
567
687
    def test_with_no_nodegroups_yields_nothing(self):
568
688
        self.assertEqual([], dns.ZoneGenerator(()).as_list())
569
689
 
572
692
            name="henry", network=IPNetwork("10/32"))
573
693
        zones = dns.ZoneGenerator(nodegroup).as_list()
574
694
        self.assertThat(
575
 
            zones, MatchesListwise(
576
 
                (forward_zone("henry", "10/32"),
577
 
                 reverse_zone("henry", "10/32"))))
 
695
            zones, MatchesSetwise(
 
696
                forward_zone("henry"),
 
697
                reverse_zone("henry", "10/32")))
578
698
 
579
699
    def test_two_managed_interfaces_yields_one_forward_two_reverse_zones(self):
580
700
        nodegroup = self.make_node_group()
584
704
        [interface1, interface2] = nodegroup.get_managed_interfaces()
585
705
 
586
706
        expected_zones = [
587
 
            forward_zone(
588
 
                nodegroup.name, interface1.network, interface2.network),
 
707
            forward_zone(nodegroup.name),
589
708
            reverse_zone(nodegroup.name, interface1.network),
590
709
            reverse_zone(nodegroup.name, interface2.network),
591
710
            ]
592
711
        self.assertThat(
593
712
            dns.ZoneGenerator([nodegroup]).as_list(),
594
 
            MatchesListwise(expected_zones))
 
713
            MatchesSetwise(*expected_zones))
595
714
 
596
715
    def test_with_many_nodegroups_yields_many_zones(self):
597
716
        # This demonstrates ZoneGenerator in all-singing all-dancing mode.
609
728
            # For the forward zones, all nodegroups sharing a domain name,
610
729
            # even those not passed into ZoneGenerator, are consolidated into
611
730
            # a single forward zone description.
612
 
            forward_zone("one", "10/32", "11/32", "12/32"),
613
 
            forward_zone("two", "20/32", "21/32", "22/32"),
 
731
            forward_zone("one"),
 
732
            forward_zone("two"),
614
733
            # For the reverse zones, a single reverse zone description is
615
734
            # generated for each nodegroup passed in, in network order.
616
735
            reverse_zone("one", "10/32"),
620
739
            )
621
740
        self.assertThat(
622
741
            dns.ZoneGenerator(nodegroups).as_list(),
623
 
            MatchesListwise(expected_zones))
 
742
            MatchesSetwise(*expected_zones))