def test_ipv6_text(self): ipv4 = factory.make_ipv6_address() self.expectThat(get_ip_based_hostname(ipv4), Equals(ipv4.replace(":", "-"))) self.expectThat( get_ip_based_hostname("2001:67c:1562::15"), Equals("2001-67c-1562--15"), )
def test_ipv4_text(self): ipv4 = factory.make_ipv4_address() self.expectThat( get_ip_based_hostname(ipv4), Equals(ipv4.replace(".", "-")) ) self.expectThat( get_ip_based_hostname("172.16.0.1"), Equals("172-16-0-1") )
def _get_special_mappings(self, domain, raw_ttl=False): """Get the special mappings, possibly limited to a single Domain. This function is responsible for creating these mappings: - any USER_RESERVED IP that has no name (dnsrr or node), - any IP not associated with a Node, - any IP associated with a DNSResource. Addresses that are associated with both a Node and a DNSResource behave thusly: - Both forward mappings include the address - The reverse mapping points only to the Node (and is the responsibility of the caller.) The caller is responsible for addresses otherwise derived from nodes. Because of how the get hostname_ip_mapping code works, we actually need to fetch ALL of the entries for subnets, but forward mappings are domain-specific. :param domain: limit return to just the given Domain. If anything other than a Domain is passed in (e.g., a Subnet or None), we return all of the reverse mappings. :param raw_ttl: Boolean, if True then just return the address_ttl, otherwise, coalesce the address_ttl to be the correct answer for zone generation. :return: a (default) dict of hostname: HostnameIPMapping entries. """ default_ttl = "%d" % Config.objects.get_config("default_dns_ttl") # raw_ttl says that we don't coalesce, but we need to pick one, so we # go with DNSResource if it is involved. if raw_ttl: ttl_clause = """COALESCE(dnsrr.address_ttl, node.address_ttl)""" else: ttl_clause = (""" COALESCE( dnsrr.address_ttl, dnsrr.ttl, node.address_ttl, node.ttl, %s)""" % default_ttl) # And here is the SQL query of doom. Build up inner selects to get the # view of a DNSResource (and Node) that we need, and finally use # domain2 to handle the case where an FQDN is also the name of a domain # that we know. sql_query = (""" SELECT COALESCE(dnsrr.fqdn, node.fqdn) AS fqdn, node.system_id, node.node_type, staticip.user_id, """ + ttl_clause + """ AS ttl, staticip.ip, dnsrr.id AS dnsresource_id FROM maasserver_staticipaddress AS staticip LEFT JOIN ( /* Create a dnsrr that has what we need. */ SELECT CASE WHEN dnsrr.name = '@' THEN dom.name ELSE CONCAT(dnsrr.name, '.', dom.name) END AS fqdn, dom.name as dom_name, dnsrr.domain_id, dnsrr.address_ttl, dom.ttl, dia.staticipaddress_id AS dnsrr_sip_id, dom2.id AS dom2_id, dnsrr.id AS id FROM maasserver_dnsresource_ip_addresses AS dia JOIN maasserver_dnsresource AS dnsrr ON dia.dnsresource_id = dnsrr.id JOIN maasserver_domain AS dom ON dnsrr.domain_id = dom.id LEFT JOIN maasserver_domain AS dom2 ON CONCAT(dnsrr.name, '.', dom.name) = dom2.name OR ( dnsrr.name = '@' AND dom.name SIMILAR TO CONCAT('[-A-Za-z0-9]*.', dom2.name) ) ) AS dnsrr ON dnsrr_sip_id = staticip.id LEFT JOIN ( /* Create a node that has what we need. */ SELECT CONCAT(nd.hostname, '.', dom.name) AS fqdn, dom.name as dom_name, nd.system_id, nd.node_type, nd.owner_id AS user_id, nd.domain_id, nd.address_ttl, dom.ttl, iia.staticipaddress_id AS node_sip_id, dom2.id AS dom2_id FROM maasserver_interface_ip_addresses AS iia JOIN maasserver_interface AS iface ON iia.interface_id = iface.id JOIN maasserver_node AS nd ON iface.node_id = nd.id JOIN maasserver_domain AS dom ON nd.domain_id = dom.id LEFT JOIN maasserver_domain AS dom2 ON CONCAT(nd.hostname, '.', dom.name) = dom2.name ) AS node ON node_sip_id = staticip.id WHERE (staticip.ip IS NOT NULL AND host(staticip.ip) != '' AND staticip.temp_expires_on IS NULL) AND """) query_parms = [] if isinstance(domain, Domain): if domain.is_default(): # The default domain is extra special, since it needs to have # A/AAAA RRs for any USER_RESERVED addresses that have no name # otherwise attached to them. # We need to get all of the entries that are: # - in this domain and have a dnsrr associated, OR # - are USER_RESERVED and have NO fqdn associated at all. sql_query += """ (( staticip.alloc_type = %s AND dnsrr.fqdn IS NULL AND node.fqdn IS NULL ) OR ( dnsrr.fqdn IS NOT NULL AND ( dnsrr.dom2_id = %s OR node.dom2_id = %s OR dnsrr.domain_id = %s OR node.domain_id = %s)))""" query_parms += [IPADDRESS_TYPE.USER_RESERVED] else: # For domains, we only need answers for the domain we were # given. These can can possibly come from either the child or # the parent for glue. Anything with a node associated will be # found inside of get_hostname_ip_mapping() - we need any # entries that are: # - in this domain and have a dnsrr associated. sql_query += """ ( dnsrr.fqdn IS NOT NULL AND ( dnsrr.dom2_id = %s OR node.dom2_id = %s OR dnsrr.domain_id = %s OR node.domain_id = %s))""" query_parms += [domain.id, domain.id, domain.id, domain.id] else: # In the subnet map, addresses attached to nodes only map back to # the node, since some things don't like multiple PTR RRs in # answers from the DNS. # Since that is handled in get_hostname_ip_mapping, we exclude # anything where the node also has a link to the address. domain = None sql_query += """ (( node.fqdn IS NULL AND dnsrr.fqdn IS NOT NULL ) OR ( staticip.alloc_type = %s AND dnsrr.fqdn IS NULL AND node.fqdn IS NULL))""" query_parms += [IPADDRESS_TYPE.USER_RESERVED] default_domain = Domain.objects.get_default_domain() mapping = defaultdict(HostnameIPMapping) cursor = connection.cursor() cursor.execute(sql_query, query_parms) for result in cursor.fetchall(): result = SpecialMappingQueryResult(*result) if result.fqdn is None or result.fqdn == "": fqdn = "%s.%s" % ( get_ip_based_hostname(result.ip), default_domain.name, ) else: fqdn = result.fqdn # It is possible that there are both Node and DNSResource entries # for this fqdn. If we have any system_id, preserve it. Ditto for # TTL. It is left as an exercise for the admin to make sure that # the any non-default TTL applied to the Node and DNSResource are # equal. entry = mapping[fqdn] if result.system_id is not None: entry.node_type = result.node_type entry.system_id = result.system_id if result.ttl is not None: entry.ttl = result.ttl if result.user_id is not None: entry.user_id = result.user_id entry.ips.add(result.ip) entry.dnsresource_id = result.dnsresource_id return mapping
def test_ipv4_numeric(self): self.expectThat(get_ip_based_hostname(2130706433), Equals("127-0-0-1")) self.expectThat( get_ip_based_hostname(int(pow(2, 32) - 1)), Equals("255-255-255-255"), )