Merge "Update the processing of assigned addresses when assigning addresses" into stable/queens
This commit is contained in:
commit
d9e11a36b6
|
@ -159,9 +159,16 @@ class NeutronDbSubnet(ipam_base.Subnet):
|
||||||
|
|
||||||
def _generate_ips(self, context, prefer_next=False, num_addresses=1):
|
def _generate_ips(self, context, prefer_next=False, num_addresses=1):
|
||||||
"""Generate a set of IPs from the set of available addresses."""
|
"""Generate a set of IPs from the set of available addresses."""
|
||||||
ip_allocations = netaddr.IPSet()
|
allocated_ips = []
|
||||||
for ipallocation in self.subnet_manager.list_allocations(context):
|
requested_num_addresses = num_addresses
|
||||||
ip_allocations.add(ipallocation.ip_address)
|
|
||||||
|
allocations = self.subnet_manager.list_allocations(context)
|
||||||
|
# It is better not to use 'netaddr.IPSet.add',
|
||||||
|
# because _compact_single_network in 'IPSet.add'
|
||||||
|
# is quite time consuming.
|
||||||
|
ip_allocations = netaddr.IPSet(
|
||||||
|
[netaddr.IPAddress(allocation.ip_address)
|
||||||
|
for allocation in allocations])
|
||||||
|
|
||||||
for ip_pool in self.subnet_manager.list_pools(context):
|
for ip_pool in self.subnet_manager.list_pools(context):
|
||||||
ip_set = netaddr.IPSet()
|
ip_set = netaddr.IPSet()
|
||||||
|
@ -170,34 +177,53 @@ class NeutronDbSubnet(ipam_base.Subnet):
|
||||||
if av_set.size == 0:
|
if av_set.size == 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if av_set.size < num_addresses:
|
if av_set.size < requested_num_addresses:
|
||||||
# Not enough addresses in pool to perform validation
|
# All addresses of the address pool are allocated
|
||||||
# TODO(njohnston): How to handle when there are enough IPs but
|
# for the first time and the remaining addresses
|
||||||
# not enough in a single pool to satisfy the request?
|
# will be allocated in the next address pools.
|
||||||
continue
|
allocated_num_addresses = av_set.size
|
||||||
|
else:
|
||||||
|
# All expected addresses can be assigned in this loop.
|
||||||
|
allocated_num_addresses = requested_num_addresses
|
||||||
|
|
||||||
if prefer_next:
|
if prefer_next:
|
||||||
allocated_ip_pool = list(itertools.islice(av_set,
|
allocated_ip_pool = list(itertools.islice(av_set,
|
||||||
num_addresses))
|
allocated_num_addresses))
|
||||||
return [str(allocated_ip)
|
allocated_ips.extend([str(allocated_ip)
|
||||||
for allocated_ip in allocated_ip_pool]
|
for allocated_ip in allocated_ip_pool])
|
||||||
|
|
||||||
|
requested_num_addresses -= allocated_num_addresses
|
||||||
|
if requested_num_addresses:
|
||||||
|
# More addresses need to be allocated in the next loop.
|
||||||
|
continue
|
||||||
|
return allocated_ips
|
||||||
|
|
||||||
window = min(av_set.size, MAX_WIN)
|
window = min(av_set.size, MAX_WIN)
|
||||||
|
|
||||||
# NOTE(gryf): If there is more than one address, make the window
|
# NOTE(gryf): If there is more than one address, make the window
|
||||||
# bigger, so that are chances to fulfill demanded amount of IPs.
|
# bigger, so that are chances to fulfill demanded amount of IPs.
|
||||||
if num_addresses > 1:
|
if allocated_num_addresses > 1:
|
||||||
window = min(av_set.size, num_addresses * MULTIPLIER,
|
window = min(av_set.size,
|
||||||
|
allocated_num_addresses * MULTIPLIER,
|
||||||
MAX_WIN_MULTI)
|
MAX_WIN_MULTI)
|
||||||
|
|
||||||
if window < num_addresses:
|
if window < allocated_num_addresses:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
# Maximize randomness by using the random module's built in
|
# Maximize randomness by using the random module's built in
|
||||||
# sampling function
|
# sampling function
|
||||||
av_ips = list(itertools.islice(av_set, 0, window))
|
av_ips = list(itertools.islice(av_set, 0, window))
|
||||||
allocated_ip_pool = random.sample(av_ips, num_addresses)
|
allocated_ip_pool = random.sample(av_ips,
|
||||||
return [str(allocated_ip) for allocated_ip in allocated_ip_pool]
|
allocated_num_addresses)
|
||||||
|
allocated_ips.extend([str(allocated_ip)
|
||||||
|
for allocated_ip in allocated_ip_pool])
|
||||||
|
|
||||||
|
requested_num_addresses -= allocated_num_addresses
|
||||||
|
if requested_num_addresses:
|
||||||
|
# More addresses need to be allocated in the next loop.
|
||||||
|
continue
|
||||||
|
|
||||||
|
return allocated_ips
|
||||||
|
|
||||||
raise ipam_exc.IpAddressGenerationFailure(
|
raise ipam_exc.IpAddressGenerationFailure(
|
||||||
subnet_id=self.subnet_manager.neutron_id)
|
subnet_id=self.subnet_manager.neutron_id)
|
||||||
|
|
|
@ -381,6 +381,31 @@ class TestNeutronDbIpamSubnet(testlib_api.SqlTestCase,
|
||||||
ipam_subnet.bulk_allocate,
|
ipam_subnet.bulk_allocate,
|
||||||
ipam_req.BulkAddressRequest(target_ip_count))
|
ipam_req.BulkAddressRequest(target_ip_count))
|
||||||
|
|
||||||
|
def test_bulk_allocate_multiple_address_pools(self):
|
||||||
|
target_ip_count = 10
|
||||||
|
# 11 addresses available
|
||||||
|
allocation_pools = [{'start': '192.168.0.5', 'end': '192.168.0.9'},
|
||||||
|
{'start': '192.168.0.15', 'end': '192.168.0.20'}]
|
||||||
|
ipam_subnet = self._create_and_allocate_ipam_subnet(
|
||||||
|
'192.168.0.0/24', allocation_pools=allocation_pools,
|
||||||
|
ip_version=constants.IP_VERSION_4)[0]
|
||||||
|
ip_addresses = ipam_subnet.bulk_allocate(
|
||||||
|
ipam_req.BulkAddressRequest(target_ip_count))
|
||||||
|
self.assertEqual(target_ip_count, len(ip_addresses))
|
||||||
|
self.assertRaises(ipam_exc.IpAddressGenerationFailure,
|
||||||
|
ipam_subnet.bulk_allocate,
|
||||||
|
ipam_req.BulkAddressRequest(2))
|
||||||
|
|
||||||
|
def test_prefernext_allocate_multiple_address_pools(self):
|
||||||
|
ipam_subnet = self._create_and_allocate_ipam_subnet(
|
||||||
|
'192.168.0.0/30', ip_version=constants.IP_VERSION_4)[0]
|
||||||
|
|
||||||
|
ipam_subnet.allocate(ipam_req.PreferNextAddressRequest())
|
||||||
|
# The second address generation request on a /30 for v4 net must fail
|
||||||
|
self.assertRaises(ipam_exc.IpAddressGenerationFailure,
|
||||||
|
ipam_subnet.allocate,
|
||||||
|
ipam_req.PreferNextAddressRequest)
|
||||||
|
|
||||||
def _test_deallocate_address(self, cidr, ip_version):
|
def _test_deallocate_address(self, cidr, ip_version):
|
||||||
ipam_subnet = self._create_and_allocate_ipam_subnet(
|
ipam_subnet = self._create_and_allocate_ipam_subnet(
|
||||||
cidr, ip_version=ip_version)[0]
|
cidr, ip_version=ip_version)[0]
|
||||||
|
|
Loading…
Reference in New Issue