Esempio n. 1
0
 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"),
     )
Esempio n. 2
0
 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")
     )
Esempio n. 3
0
    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
Esempio n. 4
0
 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"),
     )