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
(cherry picked from commit 32b4ce0e92
)
This commit is contained in:
parent
686e342f16
commit
65d0ef8b69
@ -1139,6 +1139,13 @@ def fixed_ip_associate(context, address, instance_uuid, network_id=None,
|
||||
retry_on_request=True)
|
||||
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)
|
||||
|
||||
@ -1152,6 +1159,7 @@ def fixed_ip_associate_pool(context, network_id, instance_uuid=None,
|
||||
filter_by(reserved=False).\
|
||||
filter_by(instance_uuid=None).\
|
||||
filter_by(host=None).\
|
||||
order_by(asc(models.FixedIp.updated_at)).\
|
||||
first()
|
||||
|
||||
if not fixed_ip_ref:
|
||||
|
@ -4588,6 +4588,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