def test_with_child_domain_yields_glue_when_needed(self): default_domain = Domain.objects.get_default_domain().name domain = factory.make_Domain(name="henry") john = factory.make_Domain(name="john.henry") subnet = factory.make_Subnet(cidr=str(IPNetwork("10/29").cidr)) sip = factory.make_StaticIPAddress(subnet=subnet) factory.make_Node_with_Interface_on_Subnet( subnet=subnet, vlan=subnet.vlan, fabric=subnet.vlan.fabric ) factory.make_DNSResource(name="ns", domain=john, ip_addresses=[sip]) factory.make_DNSData(name="@", domain=john, rrtype="NS", rrdata="ns") # We have a subdomain (john.henry) which as an NS RR of # 'ns.john.henry', and we should see glue records for it in the parent # zone, as well as the A RR in the child. zones = ZoneGenerator( domain, subnet, serial=random.randint(0, 65535) ).as_list() self.assertThat( zones, MatchesSetwise( forward_zone("henry"), reverse_zone(default_domain, "10/29"), reverse_zone(default_domain, "10/24"), ), ) expected_map = { "john": HostnameRRsetMapping( None, {(30, "NS", default_domain), (30, "NS", "ns")} ), "ns": HostnameRRsetMapping(None, {(30, "A", sip.ip)}), } self.assertEqual(expected_map, zones[0]._other_mapping)
def test_parent_of_default_domain_gets_glue(self): default_domain = Domain.objects.get_default_domain() default_domain.name = 'maas.example.com' default_domain.save() domains = [default_domain, factory.make_Domain('example.com')] self.patch(zonegenerator, 'get_dns_server_addresses').return_value = [ IPAddress('5.5.5.5') ] subnet = factory.make_Subnet(cidr=str(IPNetwork("10/29").cidr)) factory.make_StaticIPAddress(subnet=subnet) factory.make_Node_with_Interface_on_Subnet(subnet=subnet, vlan=subnet.vlan, fabric=subnet.vlan.fabric) zones = ZoneGenerator(domains, subnet, serial=random.randint(0, 65535)).as_list() self.assertThat( zones, MatchesSetwise(forward_zone(domains[0].name), forward_zone(domains[1].name), reverse_zone(domains[0].name, "10/29"), reverse_zone(domains[0].name, "10/24"))) # maas.example.com is the default zone, and has an A RR for its NS RR. # example.com has NS maas.example.com., and a glue record for that. expected_map_0 = { '@': HostnameRRsetMapping(None, {(30, 'A', '5.5.5.5')}, None) } expected_map_1 = { 'maas': HostnameRRsetMapping(None, {(30, 'A', IPAddress('5.5.5.5')), (30, 'NS', 'maas.example.com')}, None) } self.assertEqual(expected_map_0, zones[0]._other_mapping) self.assertEqual(expected_map_1, zones[1]._other_mapping)
def test_dnsdata_overrides_domain(self): # If DNSData has a ttl, we use that in preference to anything else. global_ttl = random.randint(100, 199) Config.objects.set_config("default_dns_ttl", global_ttl) subnet = factory.make_Subnet(cidr="10.0.0.0/23") domain = factory.make_Domain(ttl=random.randint(200, 299)) dnsrr = factory.make_DNSResource( no_ip_addresses=True, domain=domain, address_ttl=random.randint(400, 499), ) dnsdata = factory.make_DNSData( dnsresource=dnsrr, ttl=random.randint(500, 599) ) expected_forward = { dnsrr.name: HostnameRRsetMapping( None, {(dnsdata.ttl, dnsdata.rrtype, dnsdata.rrdata)} ) } zones = ZoneGenerator( domain, subnet, default_ttl=global_ttl, serial=random.randint(0, 65535), ).as_list() self.assertEqual(expected_forward, zones[0]._other_mapping) self.assertEqual({}, zones[0]._mapping) self.assertEqual({}, zones[1]._mapping)
def test_dnsdata_inherits_domain(self): # If there is no ttl on the DNSData, but is on Domain, then we get the # domain value. global_ttl = random.randint(100, 199) Config.objects.set_config("default_dns_ttl", global_ttl) subnet = factory.make_Subnet(cidr="10.0.0.0/23") domain = factory.make_Domain(ttl=random.randint(200, 299)) dnsrr = factory.make_DNSResource( no_ip_addresses=True, domain=domain, address_ttl=random.randint(400, 499), ) dnsdata = factory.make_DNSData(dnsresource=dnsrr) expected_forward = { dnsrr.name: HostnameRRsetMapping( None, {(domain.ttl, dnsdata.rrtype, dnsdata.rrdata)} ) } zones = ZoneGenerator( domain, subnet, default_ttl=global_ttl, serial=random.randint(0, 65535), ).as_list() self.assertEqual(expected_forward, zones[0]._other_mapping) self.assertEqual({}, zones[0]._mapping) self.assertEqual({}, zones[1]._mapping) self.assertEqual(None, dnsdata.ttl)
def make_mapping(self, dnsresource, raw_ttl=False): if dnsresource.name == "@" and dnsresource.domain.name.find(".") >= 0: h_name, d_name = dnsresource.domain.name.split(".", 1) nodes = Node.objects.filter(hostname=h_name, domain__name=d_name) else: h_name = dnsresource.name # Yes, dnsrr.name='@' and domain.name='maas' hits this, and we find # nothing, which is what we need to find. nodes = Node.objects.filter( hostname=h_name, domain=dnsresource.domain ) if nodes.exists(): node = nodes.first() system_id = node.system_id node_type = node.node_type else: system_id = None node_type = None mapping = HostnameRRsetMapping( system_id=system_id, node_type=node_type, dnsresource_id=dnsresource.id, ) for data in dnsresource.dnsdata_set.all(): if raw_ttl or data.ttl is not None: ttl = data.ttl elif dnsresource.domain.ttl is not None: ttl = dnsresource.domain.ttl else: ttl = Config.objects.get_config("default_dns_ttl") mapping.rrset.add((ttl, data.rrtype, data.rrdata, data.id)) return {dnsresource.name: mapping}
def test_get_hostname_dnsdata_mapping_contains_node_and_non_node(self): node = factory.make_Node(interface=True) dnsdata1 = factory.make_DNSData( name=node.hostname, domain=node.domain, rrtype='MX') dnsdata2 = factory.make_DNSData(domain=node.domain) ttl = random.randint(10, 300) Config.objects.set_config('default_dns_ttl', ttl) expected_mapping = { dnsdata1.dnsresource.name: HostnameRRsetMapping( node.system_id, {(ttl, dnsdata1.rrtype, dnsdata1.rrdata)}, node.node_type), dnsdata2.dnsresource.name: HostnameRRsetMapping( None, {(ttl, dnsdata2.rrtype, dnsdata2.rrdata)}, None), } actual = get_hostname_dnsdata_mapping(node.domain) self.assertItemsEqual( expected_mapping.items(), actual.items())
def test_add_delegations_adds_nsrrset_and_glue_in_depth(self): parent = factory.make_Domain() name = factory.make_name() child = factory.make_Domain(name="%s.%s" % (name, parent.name)) default_name = Domain.objects.get_default_domain().name g_name = factory.make_name() grandchild = factory.make_Domain(name="%s.%s" % (g_name, child.name)) dnsrr = factory.make_DNSResource(name="@", domain=child) nsname = factory.make_name() factory.make_DNSData( dnsresource=dnsrr, rrtype="NS", rrdata="%s.%s." % (nsname, grandchild.name), ) nsrr = factory.make_DNSResource(name=nsname, domain=grandchild) other_name = factory.make_name() factory.make_DNSResource(name=other_name, domain=parent) factory.make_DNSData( dnsresource=dnsrr, rrtype="NS", rrdata="%s.%s." % (other_name, parent.name), ) mappings = lazydict(get_hostname_dnsdata_mapping) mapping = mappings[parent] expected_map = { name: HostnameRRsetMapping( rrset={ (30, "NS", default_name), (30, "NS", "%s.%s." % (nsname, grandchild.name)), (30, "NS", "%s.%s." % (other_name, parent.name)), } ) } ns_part = "%s.%s" % (nsname, g_name) for sip in nsrr.ip_addresses.all(): if IPAddress(sip.ip).version == 6: expected_map[ns_part] = HostnameRRsetMapping( rrset={(30, "AAAA", sip.ip)} ) else: expected_map[ns_part] = HostnameRRsetMapping( rrset={(30, "A", sip.ip)} ) parent.add_delegations(mapping, default_name, [IPAddress("::1")], 30) self.assertEqual(expected_map, mapping)
def test_returns_interface_ips_but_no_nulls(self): default_domain = Domain.objects.get_default_domain().name domain = factory.make_Domain(name='henry') subnet = factory.make_Subnet(cidr=str(IPNetwork("10/29").cidr)) subnet.gateway_ip = str(IPAddress(IPNetwork(subnet.cidr).ip + 1)) subnet.save() # Create a node with two interfaces, with NULL ips node = factory.make_Node_with_Interface_on_Subnet( subnet=subnet, vlan=subnet.vlan, fabric=subnet.vlan.fabric, domain=domain, interface_count=3) dnsdata = factory.make_DNSData(domain=domain) boot_iface = node.boot_interface interfaces = list(node.interface_set.all().exclude(id=boot_iface.id)) # Now go add IP addresses to the boot interface, and one other boot_ip = factory.make_StaticIPAddress(interface=boot_iface, subnet=subnet) sip = factory.make_StaticIPAddress(interface=interfaces[0], subnet=subnet) default_ttl = random.randint(10, 300) Config.objects.set_config('default_dns_ttl', default_ttl) zones = ZoneGenerator(domain, subnet, default_ttl=default_ttl, serial=random.randint(0, 65535)).as_list() self.assertThat( zones, MatchesSetwise(forward_zone("henry"), reverse_zone(default_domain, "10/29"), reverse_zone(default_domain, "10/24"))) self.assertEqual( { node.hostname: HostnameIPMapping(node.system_id, default_ttl, {'%s' % boot_ip.ip}, node.node_type), "%s.%s" % (interfaces[0].name, node.hostname): HostnameIPMapping(node.system_id, default_ttl, {'%s' % sip.ip}, node.node_type) }, zones[0]._mapping) self.assertEqual({ dnsdata.dnsresource.name: HostnameRRsetMapping( None, {(default_ttl, dnsdata.rrtype, dnsdata.rrdata)}) }.items(), zones[0]._other_mapping.items()) self.assertEqual( { node.fqdn: HostnameIPMapping(node.system_id, default_ttl, {'%s' % boot_ip.ip}, node.node_type), '%s.%s' % (interfaces[0].name, node.fqdn): HostnameIPMapping(node.system_id, default_ttl, {'%s' % sip.ip}, node.node_type) }, zones[1]._mapping) self.assertEqual({}, zones[2]._mapping)
def test_add_delegations_allows_dots(self): parent = factory.make_Domain() name = "%s.%s" % (factory.make_name(), factory.make_name()) factory.make_Domain(name="%s.%s" % (name, parent.name)) default_name = Domain.objects.get_default_domain().name mappings = lazydict(get_hostname_dnsdata_mapping) mapping = mappings[parent] parent.add_delegations(mapping, default_name, [IPAddress("::1")], 30) expected_map = HostnameRRsetMapping(rrset={(30, 'NS', default_name)}) self.assertEqual(expected_map, mapping[name])
def test_add_delegations_adds_nsrrset_and_glue(self): parent = factory.make_Domain() name = factory.make_name() child = factory.make_Domain(name="%s.%s" % (name, parent.name)) default_name = Domain.objects.get_default_domain().name dnsrr = factory.make_DNSResource(name='@', domain=child) nsname = factory.make_name() factory.make_DNSData(dnsresource=dnsrr, rrtype='NS', rrdata="%s.%s." % (nsname, child.name)) nsrr = factory.make_DNSResource(name=nsname, domain=child) other_name = factory.make_name() factory.make_DNSResource(name=other_name, domain=parent) factory.make_DNSData(dnsresource=dnsrr, rrtype='NS', rrdata="%s.%s." % (other_name, parent.name)) mappings = lazydict(get_hostname_dnsdata_mapping) mapping = mappings[parent] parent.add_delegations(mapping, default_name, [IPAddress("::1")], 30) expected_map = { name: HostnameRRsetMapping( rrset={ (30, 'NS', default_name), (30, 'NS', "%s.%s." % (nsname, child.name)), (30, 'NS', "%s.%s." % (other_name, parent.name)), }), } for sip in nsrr.ip_addresses.all(): if IPAddress(sip.ip).version == 6: expected_map[nsname] = HostnameRRsetMapping(rrset={(30, 'AAAA', sip.ip)}) else: expected_map[nsname] = HostnameRRsetMapping(rrset={(30, 'A', sip.ip)}) self.assertEqual(expected_map, mapping)
def test_add_delegations_does_not_list_region_for_non_auth(self): parent = factory.make_Domain() name = factory.make_name() child = factory.make_Domain( name="%s.%s" % (name, parent.name), authoritative=False) default_name = Domain.objects.get_default_domain().name ns_name = "%s.%s." % (factory.make_name('h'), factory.make_name('d')) factory.make_DNSData( name='@', domain=child, rrtype='NS', rrdata=ns_name) mappings = lazydict(get_hostname_dnsdata_mapping) mapping = mappings[parent] parent.add_delegations(mapping, default_name, [IPAddress("::1")], 30) expected_map = HostnameRRsetMapping( rrset={(30, 'NS', ns_name)}) self.assertEqual(expected_map, mapping[name])
def test_with_child_domain_yields_delegation(self): default_domain = Domain.objects.get_default_domain().name domain = factory.make_Domain(name='henry') factory.make_Domain(name="john.henry") subnet = factory.make_Subnet(cidr=str(IPNetwork("10/29").cidr)) factory.make_Node_with_Interface_on_Subnet( subnet=subnet, vlan=subnet.vlan, fabric=subnet.vlan.fabric) zones = ZoneGenerator( domain, subnet, serial=random.randint(0, 65535)).as_list() self.assertThat( zones, MatchesSetwise( forward_zone("henry"), reverse_zone(default_domain, "10/29"), reverse_zone(default_domain, "10/24"))) expected_map = {'john': HostnameRRsetMapping( None, {(30, 'NS', default_domain)})} self.assertEqual(expected_map, zones[0]._other_mapping)