Exemple #1
0
    def unassign_address(self, pool, address):
        """
        Deprecated in favor of release_ips()

        Unassign an IP from a pool.
        :param IPPool or IPNetwork pool: The pool that the assignment is from.
        If the pool is None, get the pool from datastore
        :param IPAddress address: The address to unassign.
        :return: True if the address was unassigned, false otherwise. An
        exception is thrown for any error conditions.
        :rtype: bool
        """
        pool = pool or self.get_pool(address)
        if pool is None:
            raise PoolNotFound("IP address %s does not belong to any "
                               "configured pools" % address)

        if isinstance(pool, IPPool):
            pool = pool.cidr
        assert isinstance(pool, IPNetwork)
        assert isinstance(address, IPAddress)

        err = self.release_ips({address})
        if err:
            return False
        else:
            return True
Exemple #2
0
    def assign_address(self, pool, address):
        """
        Deprecated in favor of assign_ip().

        Attempt to assign an IPAddress in a pool.
        Fails if the address is already assigned.
        The directory for storing assignments in this pool must already exist.
        :param IPPool or IPNetwork pool: The pool that the assignment is from.
        If pool is None, get the pool from datastore
        :param IPAddress address: The address to assign.
        :return: True if the allocation succeeds, false otherwise. An
        exception is thrown for any error conditions.
        :rtype: bool
        """
        pool = pool or self.get_pool(address)
        if pool is None:
            raise PoolNotFound("IP address %s does not belong to any "
                               "configured pools" % address)

        if isinstance(pool, IPPool):
            pool = pool.cidr
        assert isinstance(pool, IPNetwork)
        assert isinstance(address, IPAddress)

        try:
            self.assign_ip(address, None, {})
            return True
        except AlreadyAssignedError:
            return False
Exemple #3
0
    def _random_blocks(self, excluded_ids, version, pool):
        """
        Get an list of block CIDRs, in random order.

        :param excluded_ids: List of IDs that should be excluded.
        :param version: The IP version 4, or 6.
        :param pool: IPPool to get blocks from, or None to use all pools
        :return: An iterator of block CIDRs.
        """

        # Get the pools and verify we got a valid one, or none.
        ip_pools = self.get_ip_pools(version, ipam=True)
        if pool is not None:
            if pool not in ip_pools:
                raise PoolNotFound("Requested pool %s is not configured or has"
                                   "wrong attributes" % pool)
            # Confine search to only the one pool.
            ip_pools = [pool]

        random_blocks = []
        i = 0
        for pool in ip_pools:
            for block_cidr in pool.cidr.subnet(BLOCK_PREFIXLEN[version]):
                if block_cidr not in excluded_ids:
                    # add this block.  We use an "inside-out" Fisher-Yates
                    # shuffle to randomize the list as we create it.  See
                    # http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
                    j = random.randint(0, i)
                    if j != i:
                        random_blocks.append(random_blocks[j])
                        random_blocks[j] = block_cidr
                    else:
                        random_blocks.append(block_cidr)
                    i += 1
        return random_blocks
Exemple #4
0
    def assign_ip(self, address, handle_id, attributes, host=None):
        """
        Assign the given address.  Throws AlreadyAssignedError if the address
        is taken.

        :param address: IPAddress to assign.
        :param handle_id: allocation handle ID for this request.  You can
        query this key using get_assignments_by_handle() or release all
        addresses with this handle_id using release_by_handle().
        :param attributes: Contents of this dict will be stored with the
        assignment and can be queried using get_assignment_attributes().  Must
        be JSON serializable.
        :param host: (optional) The host ID to use for affinity in assigning IP
        addresses.  Defaults to the hostname returned by get_hostname().
        :return: None.
        """
        assert isinstance(handle_id, str) or handle_id is None
        assert isinstance(address, IPAddress)
        if not host:
            host = get_hostname()
        block_cidr = get_block_cidr_for_address(address)

        for _ in xrange(RETRIES):
            try:
                block = self._read_block(block_cidr)
            except KeyError:
                _log.debug("Block %s doesn't exist.", block_cidr)
                pools = self.get_ip_pools(address.version, ipam=True)
                if any([address in pool for pool in pools]):
                    _log.debug("Create and claim block %s.", block_cidr)
                    try:
                        self._claim_block_affinity(host, block_cidr)
                    except HostAffinityClaimedError:
                        _log.debug("Someone else claimed block %s before us.",
                                   block_cidr)
                        continue
                    # Block exists now, retry writing to it.
                    _log.debug("Claimed block %s", block_cidr)
                    continue
                else:
                    raise PoolNotFound("%s is not in any configured pool" %
                                       address)

            # Try to assign.  Throws exception if already assigned -- let it.
            block.assign(address, handle_id, attributes)

            # If using a handle, increment by one IP
            if handle_id is not None:
                self._increment_handle(handle_id, block_cidr, 1)

            # Try to commit.
            try:
                self._compare_and_swap_block(block)
                return  # Success!
            except CASError:
                _log.debug("CAS failed on block %s", block_cidr)
                if handle_id is not None:
                    self._decrement_handle(handle_id, block_cidr, 1)
        raise RuntimeError("Hit max retries.")
 def test_request_address_ip_supplied_no_pool(self, m_assign):
     """
     Test request_address when the supplied address is not in a pool.
     """
     ip = IPAddress("1.2.3.4")
     request_data = {"PoolID": "CalicoPoolIPv4", "Address": str(ip)}
     m_assign.side_effect = PoolNotFound(ip)
     rv = self.app.post('/IpamDriver.RequestAddress',
                        data=json.dumps(request_data))
     self.assertTrue("Err" in json.loads(rv.data))
Exemple #6
0
    def _new_affine_block(self, host, version, pool):
        """
        Create and register a new affine block for the host.

        :param host: The host ID to get a block for.
        :param version: 4 for IPv4, 6 for IPv6.
        :param pool: Limit blocks to a specific pool, or pass None to find all
        blocks for the specified version.
        :return: The block CIDR of the new block.
        """
        # Get the pools and verify we got a valid one, or none.
        ip_pools = self.get_ip_pools(version, ipam=True)
        if pool is not None:
            if pool not in ip_pools:
                raise PoolNotFound("Requested pool %s is not configured or has"
                                   "wrong attributes" % pool)
            # Confine search to only the one pool.
            ip_pools = [pool]

        for pool in ip_pools:
            for block_cidr in pool.cidr.subnet(BLOCK_PREFIXLEN[version]):
                block_id = str(block_cidr)
                _log.debug("Checking if block %s is free.", block_id)
                key = _block_datastore_key(block_cidr)
                try:
                    _ = self.etcd_client.read(key, quorum=True)
                except EtcdKeyNotFound:
                    _log.debug("Found block %s free.", block_id)
                    try:
                        self._claim_block_affinity(host, block_cidr)
                    except HostAffinityClaimedError:
                        # Failed to claim the block because some other host
                        # has it.
                        _log.debug("Failed to claim block %s", block_cidr)
                        continue
                    # Success!
                    return block_cidr
        raise NoFreeBlocksError()