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
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
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
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))
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()