Spread allocations of fixed ips
The default fixed_ip allocation always does .first() out of the fixed ip pool. This leads to a pathological situation that in a rapidly changing environment we're constantly recycling the same small number of ips out of the pool. Given other racey behavior in dnsmasq around processing DHCP Release requests, we can start to get DHCP fails when a DHCP release is missed, we immediately recycle the IP and give it to a new guest. We can mitigate this by sorting the results by updated_at. This means we'll favor least recently used fixed ips. Depends-On: I27f73c1edf12218818c4d279efbd9fef5cdef672 Related-Bug: #1532809 Change-Id: I3c83bd68a0e2bbbcdd6d955722dbc9f9fc528113
This commit is contained in:
parent
34e6c0fb15
commit
32b4ce0e92
@ -1168,6 +1168,13 @@ def fixed_ip_associate(context, address, instance_uuid, network_id=None,
|
||||
@main_context_manager.writer
|
||||
def fixed_ip_associate_pool(context, network_id, instance_uuid=None,
|
||||
host=None, virtual_interface_id=None):
|
||||
"""allocate a fixed ip out of a fixed ip network pool.
|
||||
|
||||
This allocates an unallocated fixed ip out of a specified
|
||||
network. We sort by updated_at to hand out the oldest address in
|
||||
the list.
|
||||
|
||||
"""
|
||||
if instance_uuid and not uuidutils.is_uuid_like(instance_uuid):
|
||||
raise exception.InvalidUUID(uuid=instance_uuid)
|
||||
|
||||
@ -1179,6 +1186,7 @@ def fixed_ip_associate_pool(context, network_id, instance_uuid=None,
|
||||
filter_by(instance_uuid=None).\
|
||||
filter_by(host=None).\
|
||||
filter_by(leased=False).\
|
||||
order_by(asc(models.FixedIp.updated_at)).\
|
||||
first()
|
||||
|
||||
if not fixed_ip_ref:
|
||||
|
@ -4794,6 +4794,27 @@ class FixedIPTestCase(BaseInstanceTypeTestCase):
|
||||
fixed_ip = db.fixed_ip_get_by_address(self.ctxt, address)
|
||||
self.assertEqual(fixed_ip['instance_uuid'], instance_uuid)
|
||||
|
||||
def test_fixed_ip_associate_pool_order(self):
|
||||
"""Test that fixed_ip always uses oldest fixed_ip.
|
||||
|
||||
We should always be using the fixed ip with the oldest
|
||||
updated_at.
|
||||
"""
|
||||
instance_uuid = self._create_instance()
|
||||
network = db.network_create_safe(self.ctxt, {})
|
||||
self.addCleanup(timeutils.clear_time_override)
|
||||
start = timeutils.utcnow()
|
||||
for i in range(1, 4):
|
||||
now = start - datetime.timedelta(hours=i)
|
||||
timeutils.set_time_override(now)
|
||||
address = self.create_fixed_ip(
|
||||
updated_at=now,
|
||||
address='10.1.0.%d' % i,
|
||||
network_id=network['id'])
|
||||
db.fixed_ip_associate_pool(self.ctxt, network['id'], instance_uuid)
|
||||
fixed_ip = db.fixed_ip_get_by_address(self.ctxt, address)
|
||||
self.assertEqual(fixed_ip['instance_uuid'], instance_uuid)
|
||||
|
||||
def test_fixed_ip_associate_pool_succeeds_fip_ref_network_id_is_none(self):
|
||||
instance_uuid = self._create_instance()
|
||||
network = db.network_create_safe(self.ctxt, {})
|
||||
|
Loading…
Reference in New Issue
Block a user