~allenap/maas/xxx-a-thon

« back to all changes in this revision

Viewing changes to src/maasserver/dns/zonegenerator.py

  • Committer: Gavin Panella
  • Date: 2016-03-22 21:14:34 UTC
  • mfrom: (4657.1.157 maas)
  • Revision ID: gavin.panella@canonical.com-20160322211434-xzuovio86zvzo2js
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
94
94
    "The DNS server will use the address '%s',  which is inside the "
95
95
    "loopback network.  This may not be a problem if you're not using "
96
96
    "MAAS's DNS features or if you don't rely on this information. "
97
 
    "Consult the 'maas-region-admin local_config_set --maas-url' command "
 
97
    "Consult the 'maas-region local_config_set --maas-url' command "
98
98
    "for details on how to set the MAAS URL.")
99
99
 
100
100
 
108
108
    """Return the DNS server's IP address.
109
109
 
110
110
    That address is derived from the config maas_url or rack_controller.url.
111
 
    Consult the 'maas-region-admin local_config_set --maas-url' command for
 
111
    Consult the 'maas-region local_config_set --maas-url' command for
112
112
    details on how to set the MAAS URL.
113
113
 
114
114
    :param rack_controller: Optional rack controller to which the DNS server
127
127
            "Unable to find MAAS server IP address: %s. MAAS's DNS server "
128
128
            "requires this IP address for the NS records in its zone files. "
129
129
            "Make sure that the configuration setting for the MAAS URL has "
130
 
            "the correct hostname. Consult the 'maas-region-admin "
 
130
            "the correct hostname. Consult the 'maas-region "
131
131
            "local_config_set --maas-url' command."
132
132
            % e.strerror)
133
133
 
152
152
    We generate zones for the domains (forward), and subnets (reverse) passed.
153
153
    """
154
154
 
155
 
    def __init__(self, domains, subnets, default_ttl=None,
156
 
                 serial=None, serial_generator=None):
 
155
    def __init__(self, domains, subnets, default_ttl=None, serial=None):
157
156
        """
158
157
        :param serial: A serial number to reuse when creating zones in bulk.
159
 
        :param serial_generator: As an alternative to `serial`, a callback
160
 
            that returns a fresh serial number on every call.
161
158
        """
162
159
        self.domains = sequence(domains)
163
160
        self.subnets = sequence(subnets)
166
163
        else:
167
164
            self.default_ttl = default_ttl
168
165
        self.serial = serial
169
 
        self.serial_generator = serial_generator
170
166
 
171
167
    @staticmethod
172
168
    def _get_mappings():
230
226
        """Generator of reverse zones, sorted by network."""
231
227
 
232
228
        subnets = set(subnets)
233
 
        # For each of the zones that we are generating (one or more per
234
 
        # subnet), compile the zone from:
235
 
        # 1. Dynamic ranges on this subnet.
236
 
        # 2. Node: ip mapping(subnet), including DNSResource records for
237
 
        #    StaticIPAddresses in this subnet.
238
 
        # 3. Interfaces on any node that have IP addresses in this subnet.
 
229
        # Generate the list of parent networks for rfc2317 glue.  Note that we
 
230
        # need to handle the case where we are controlling both the small net
 
231
        # and a bigger network containing the /24, not just a /24 network.
239
232
        rfc2317_glue = {}
240
233
        for subnet in subnets:
241
234
            network = IPNetwork(subnet.cidr)
242
 
            # If this is a small subnet and  we are doing RFC2317 glue for it,
243
 
            # then we need to combine that with any other such subnets
244
 
            # We need to know this before we start creating reverse DNS zones.
245
235
            if subnet.rdns_mode == RDNS_MODE.RFC2317:
 
236
                # If this is a small subnet and  we are doing RFC2317 glue for
 
237
                # it, then we need to combine that with any other such subnets
 
238
                # We need to know this before we start creating reverse DNS
 
239
                # zones.
246
240
                if network.version == 4 and network.prefixlen > 24:
247
241
                    # Turn 192.168.99.32/29 into 192.168.99.0/24
248
242
                    basenet = IPNetwork(
255
249
                        IPNetwork("%s/124" % network.network).network)
256
250
                    rfc2317_glue.setdefault(basenet, set()).add(network)
257
251
 
 
252
        # For each of the zones that we are generating (one or more per
 
253
        # subnet), compile the zone from:
 
254
        # 1. Dynamic ranges on this subnet.
 
255
        # 2. Node: ip mapping(subnet), including DNSResource records for
 
256
        #    StaticIPAddresses in this subnet.
 
257
        # 3. Interfaces on any node that have IP addresses in this subnet.
 
258
        # All of this needs to be done smallest to largest so that we can
 
259
        # correctly gather the rfc2317 glue that we need.  Failure to sort
 
260
        # means that we wind up grabbing (and deleting) the rfc2317 glue info
 
261
        # while processing the wrong network.
 
262
        for subnet in sorted(
 
263
                subnets,
 
264
                key=lambda subnet: IPNetwork(subnet.cidr).prefixlen,
 
265
                reverse=True):
 
266
            network = IPNetwork(subnet.cidr)
 
267
            if subnet.rdns_mode == RDNS_MODE.DISABLED:
 
268
                # If we are not doing reverse dns for this subnet, then just
 
269
                # skip to the next subnet.
 
270
                logger.debug(
 
271
                    "%s disabled subnet in DNS config list" % subnet.cidr)
 
272
                continue
 
273
 
258
274
            # 1. Figure out the dynamic ranges.
259
275
            dynamic_ranges = [
260
276
                ip_range.netaddr_iprange
283
299
                else:
284
300
                    ttl = default_ttl
285
301
                for iface in node.interface_set.all():
286
 
                    iface_map = HostnameIPMapping(
287
 
                        node.system_id, ttl, {
288
 
                            ip.ip
289
 
                            for ip in iface.ip_addresses.all()
290
 
                            if (
291
 
                                ip.ip is not None and
292
 
                                ip.subnet_id == subnet.id)})
293
 
                    if len(iface_map.ips) > 0:
 
302
                    ips_in_subnet = {
 
303
                        ip.ip
 
304
                        for ip in iface.ip_addresses.all()
 
305
                        if (ip.ip is not None and ip.subnet_id == subnet.id)}
 
306
                    if len(ips_in_subnet) > 0:
 
307
                        iface_map = HostnameIPMapping(
 
308
                            node.system_id, ttl, ips_in_subnet, node.node_type)
294
309
                        mapping.update({
295
310
                            "%s.%s" % (iface.name, iface.node.fqdn): iface_map
296
311
                        })
298
313
            # Use the default_domain as the name for the NS host in the reverse
299
314
            # zones.  If this network is actually a parent rfc2317 glue
300
315
            # network, then we need to generate the glue records.
301
 
            if network in rfc2317_glue:
 
316
            # We need to detect the need for glue in our networks that are
 
317
            # big.
 
318
            if ((network.version == 6 and network.prefixlen < 124) or
 
319
                    network.prefixlen < 24):
 
320
                glue = set()
 
321
                # This is the reason for needing the subnets sorted in
 
322
                # increasing order of size.
 
323
                for net in rfc2317_glue.copy().keys():
 
324
                    if net in network:
 
325
                        glue.update(rfc2317_glue[net])
 
326
                        del(rfc2317_glue[net])
 
327
            elif network in rfc2317_glue:
302
328
                glue = rfc2317_glue[network]
303
329
                del(rfc2317_glue[network])
304
330
            else:
326
352
        """
327
353
        # For testing and such it's fine if we don't have a serial, but once
328
354
        # we get to this point, we really need one.
329
 
        assert not (self.serial is None and self.serial_generator is None), (
330
 
            "No serial number or serial number generator specified.")
 
355
        assert not (self.serial is None), ("No serial number specified.")
331
356
 
332
357
        mappings = self._get_mappings()
333
358
        rrset_mappings = self._get_rrset_mappings()
334
 
        serial = self.serial or self.serial_generator()
 
359
        serial = self.serial
335
360
        default_ttl = self.default_ttl
336
361
        return chain(
337
362
            self._gen_forward_zones(