示例#1
0
def free_topology(tid):
    """Deletes the topology associated with tid, as well as any IPAssignment,
    MACAssignment, TopologySourceIPFilter, TopologyUserFilter, and
    IPBlockAllocation objects belonging to it."""
    def run():
        try:
            topo = db.Topology.objects.get(pk=tid)
            db.TopologySourceIPFilter.objects.filter(topology=topo).delete()
            db.TopologyUserFilter.objects.filter(topology=topo).delete()
            db.IPAssignment.objects.filter(topology=topo).delete()
            db.MACAssignment.objects.filter(topology=topo).delete()
            db.IPBlockAllocation.objects.filter(topology=topo).delete()
            topo.delete()
            logging.info('freed topology %d' % tid)
        except db.Topology.DoesNotExist:
            logging.warning('asked to free non-existent topology %d' % tid)
    DBService.run_background(run)
示例#2
0
def __realloc_if_available_work(ra, ip_block_from):
    # Start a database query for the IP block allocations which we'll need later
    closest_pre_alloc_wait = DBService.run_background(lambda:db.IPBlockAllocation.objects.filter(start_addr__lte=ra.start_addr).order_by('-start_addr')[0])
    print closest_pre_alloc_wait
    
    # the recent allocation must be from the block we're trying to allocate from
    start_addr = struct.unpack('>I', inet_aton(ra.start_addr))[0]
    start_addr_from = struct.unpack('>I', inet_aton(ip_block_from.subnet))[0]
    if not is_overlapping(start_addr, ra.mask, start_addr_from, ip_block_from.mask):
        return None

    # the recent allocation must not be in use
    try:
        # does the closest active allocation BEFORE the recent alloc overlap it?
        closest_pre_alloc = closest_pre_alloc_wait()
        sa_pre = struct.unpack('>I', inet_aton(closest_pre_alloc.start_addr))[0]
        if is_overlapping(start_addr, ra.mask, sa_pre, closest_pre_alloc.mask):
            return None

        # does the closest active allocation AFTER to the recent alloc overlap it?
        closest_post_alloc = DBService.run_and_wait(lambda:db.IPBlockAllocation.objects.filter(start_addr__gte=ra.start_addr).order_by('start_addr')[0])
        sa_post = struct.unpack('>I', inet_aton(closest_post_alloc.start_addr))[0]
        if is_overlapping(start_addr, ra.mask, sa_post, closest_post_alloc.mask):
            return None
    except IndexError:
        pass

    # it isn't in use => allocate it
    new_alloc = db.IPBlockAllocation()
    new_alloc.block_from = ip_block_from
    new_alloc.topology = None
    new_alloc.start_addr = ra.start_addr
    new_alloc.mask = ra.mask
    DBService.run_and_wait(new_alloc.save)
    logging.info('RE-allocated new block of addresses: %s' % new_alloc)
    return new_alloc
示例#3
0
def allocate_to_topology(topo, ip_block_from, owner, use_first_available=False, use_recent_alloc_logic=True):
    """Allocates IP addresses to an existing topology.  If the topology already
    has IPs assigned, this does nothing.
    @param topo The Topology to allocate IPs to
    @param ip_block_from The IPBlock from which to allocate addresses
    @param use_first_available If True, use the first available IP addresses
    rather than a random block
    @param owner The user who has caused this allocation to take place
    @exception IPError If there are not enough IPs to allocate"""

    # Check we don't have any IPs already
    try:
        _ = DBService.run_and_wait(lambda:db.IPBlockAllocation.objects.get(topology=topo))
    except db.IPBlockAllocation.DoesNotExist:
        pass
    else:
        # We already have an IP block allocation - do nothing
        return

    # Get the template this topology was created from, and the topology's source
    # filters
    template = topo.template
    filters = DBService.run_and_wait(lambda:db.TopologySourceIPFilter.objects.filter(topology=topo))
    src_filters = [(sif.ip, sif.mask) for sif in filters]

    # build a depth-first "tree" of the topology from the port connected to the gateway
    root = template.get_root_port()
    if not root:
        return ("template '%s' has no ports" % template.name,)
    try:
        tree = root.get_tree(True)
        num_addrs = tree.compute_subnet_size()
    except:
        # topology graph has cycles - just make each link its own /31
        tree = None
        links = DBService.run_and_wait(lambda:db.Link.objects.filter(port1__node__template=template))
        num_addrs = len(links) * 2

    # try to give the user the allocation they most recently had
    alloc = __realloc_if_available(owner, template, ip_block_from) if use_recent_alloc_logic else None
    if not alloc:
        # allocate a subblock of IPs for the new topology
        allocs = allocate_ip_block(ip_block_from, 1, num_addrs, src_filters, use_first_available)
        if not allocs:
            raise IPError("Not enough IP addresses to allocate for topology %d" % topo.id)
        alloc = allocs[0]

    # Assign IP addresses
    start_addr = struct.unpack('>I', inet_aton(alloc.start_addr))[0]
    if tree:
        assignments = tree.assign_addr(start_addr, alloc.size())
    else:
        assignments = []
        for i,link in enumerate(links):
            assignments.append((link.port1, start_addr+2*i,   31))
            assignments.append((link.port2, start_addr+2*i+1, 31))

    # Add the allocation to the database
    alloc.topology = topo
    alloc.save()

    # Add the allocation to the list of recently allocated blocks
    if use_recent_alloc_logic:
        ra = db.RecentIPBlockAllocation()
        ra.user = owner
        ra.template = template
        ra.start_addr = alloc.start_addr
        ra.mask = alloc.mask
        # Save and wait for it - we wait because we need the ID for the next bit
        DBService.run_and_wait(ra.save)

    # Add the assignments to the database
    wait_for = []
    for port, ip, mask_sz in assignments:
        ipa = db.IPAssignment()
        ipa.topology = topo
        ipa.port = port
        ipa.ip = inet_ntoa(struct.pack('>I', ip))
        ipa.mask = mask_sz
        waiter = DBService.run_background(ipa.save)
        wait_for.append(waiter)
        logging.info('IP assignment for topology %d: %s' % (topo.id, ipa))

    # Wait for all the DB transactions to complete
    for waiter in wait_for:
        waiter()