Esempio n. 1
0
def populate_tags(tag):
    """Evaluate `tag` for all nodes.

    This returns a `Deferred` that will fire when all tags have been
    evaluated. The return value is intended FOR TESTING ONLY because:

    - You must not use the `Deferred` in the calling thread; it must only be
      manipulated in the reactor thread. Pretending it's not there is safer
      than chaining code onto it because it's easy to get wrong.

    - The call may not finish for 10 minutes or more. It is therefore not a
      good thing to be waiting for in a web request.

    """
    # This function cannot be called inside a transaction. The function manages
    # its own transaction.
    if in_transaction():
        raise TransactionManagementError(
            '`populate_tags` cannot be called inside an existing transaction.')

    logger.debug('Evaluating the "%s" tag for all nodes.', tag.name)

    clients = getAllClients()
    if len(clients) == 0:
        # We have no clients so we need to do the work locally.
        @transactional
        def _populate_tag():
            return populate_tag_for_multiple_nodes(tag, Node.objects.all())

        return _populate_tag()
    else:
        # Split the work between the connected rack controllers.
        @transactional
        def _generate_work():
            node_ids = Node.objects.all().values_list("system_id", flat=True)
            node_ids = [{"system_id": node_id} for node_id in node_ids]
            chunked_node_ids = list(chunk_list(node_ids, len(clients)))
            connected_racks = []
            for idx, client in enumerate(clients):
                rack = RackController.objects.get(system_id=client.ident)
                token = _get_or_create_auth_token(rack.owner)
                creds = convert_tuple_to_string(get_creds_tuple(token))
                if len(chunked_node_ids) > idx:
                    connected_racks.append({
                        "system_id": rack.system_id,
                        "hostname": rack.hostname,
                        "client": client,
                        "tag_name": tag.name,
                        "tag_definition": tag.definition,
                        "tag_nsmap": [
                            {"prefix": prefix, "uri": uri}
                            for prefix, uri in tag_nsmap.items()
                        ],
                        "credentials": creds,
                        "nodes": list(chunked_node_ids[idx]),
                    })
            return connected_racks

        return _do_populate_tags(_generate_work())
Esempio n. 2
0
def populate_tags(tag):
    """Send worker for all nodegroups an update_node_tags request.
    """
    items = {
        'tag_name': tag.name,
        'tag_definition': tag.definition,
        'tag_nsmap': tag_nsmap,
    }
    # Rather than using NodeGroup.objects.refresh_workers() we call
    # refresh_worker immediately before we pass the requet. This is mostly for
    # the test suite, where we need the single real worker to switch to the
    # worker for a given nodegroup, before we have that worker process the
    # request.
    logger.debug('Refreshing tag definition for %s' % (items, ))
    for nodegroup in NodeGroup.objects.all():
        refresh_worker(nodegroup)
        update_node_tags.apply_async(queue=nodegroup.work_queue, kwargs=items)
Esempio n. 3
0
    def _gen_reverse_zones(subnets, serial, ns_host_name, mappings,
                           default_ttl):
        """Generator of reverse zones, sorted by network."""

        subnets = set(subnets)
        # Generate the list of parent networks for rfc2317 glue.  Note that we
        # need to handle the case where we are controlling both the small net
        # and a bigger network containing the /24, not just a /24 network.
        rfc2317_glue = {}
        for subnet in subnets:
            network = IPNetwork(subnet.cidr)
            if subnet.rdns_mode == RDNS_MODE.RFC2317:
                # If this is a small subnet and  we are doing RFC2317 glue for
                # it, then we need to combine that with any other such subnets
                # We need to know this before we start creating reverse DNS
                # zones.
                if network.version == 4 and network.prefixlen > 24:
                    # Turn 192.168.99.32/29 into 192.168.99.0/24
                    basenet = IPNetwork(
                        "%s/24" % IPNetwork("%s/24" % network.network).network)
                    rfc2317_glue.setdefault(basenet, set()).add(network)
                elif network.version == 6 and network.prefixlen > 124:
                    basenet = IPNetwork(
                        "%s/124" %
                        IPNetwork("%s/124" % network.network).network)
                    rfc2317_glue.setdefault(basenet, set()).add(network)

        # Since get_hostname_ip_mapping(Subnet) ignores Subnet.id, so we can
        # just do it once and be happy.  LP#1600259
        if len(subnets):
            mappings['reverse'] = mappings[Subnet.objects.first()]

        # For each of the zones that we are generating (one or more per
        # subnet), compile the zone from:
        # 1. Dynamic ranges on this subnet.
        # 2. Node: ip mapping(subnet), including DNSResource records for
        #    StaticIPAddresses in this subnet.
        # All of this needs to be done smallest to largest so that we can
        # correctly gather the rfc2317 glue that we need.  Failure to sort
        # means that we wind up grabbing (and deleting) the rfc2317 glue info
        # while processing the wrong network.
        for subnet in sorted(
                subnets,
                key=lambda subnet: IPNetwork(subnet.cidr).prefixlen,
                reverse=True):
            network = IPNetwork(subnet.cidr)
            if subnet.rdns_mode == RDNS_MODE.DISABLED:
                # If we are not doing reverse dns for this subnet, then just
                # skip to the next subnet.
                logger.debug("%s disabled subnet in DNS config list" %
                             subnet.cidr)
                continue

            # 1. Figure out the dynamic ranges.
            dynamic_ranges = [
                ip_range.netaddr_iprange
                for ip_range in subnet.get_dynamic_ranges()
            ]

            # 2. Start with the map of all of the nodes, including all
            # DNSResource-associated addresses.  We will prune this to just
            # entries for the subnet when we actually generate the zonefile.
            # If we get here, then we have subnets, so we noticed that above
            # and created mappings['reverse'].  LP#1600259
            mapping = mappings['reverse']

            # Use the default_domain as the name for the NS host in the reverse
            # zones.  If this network is actually a parent rfc2317 glue
            # network, then we need to generate the glue records.
            # We need to detect the need for glue in our networks that are
            # big.
            if ((network.version == 6 and network.prefixlen < 124)
                    or network.prefixlen < 24):
                glue = set()
                # This is the reason for needing the subnets sorted in
                # increasing order of size.
                for net in rfc2317_glue.copy().keys():
                    if net in network:
                        glue.update(rfc2317_glue[net])
                        del (rfc2317_glue[net])
            elif network in rfc2317_glue:
                glue = rfc2317_glue[network]
                del (rfc2317_glue[network])
            else:
                glue = set()
            yield DNSReverseZoneConfig(
                ns_host_name,
                serial=serial,
                default_ttl=default_ttl,
                ns_host_name=ns_host_name,
                mapping=mapping,
                network=IPNetwork(subnet.cidr),
                dynamic_ranges=dynamic_ranges,
                rfc2317_ranges=glue,
            )
        # Now provide any remaining rfc2317 glue networks.
        for network, ranges in rfc2317_glue.items():
            yield DNSReverseZoneConfig(
                ns_host_name,
                serial=serial,
                default_ttl=default_ttl,
                network=network,
                ns_host_name=ns_host_name,
                rfc2317_ranges=ranges,
            )