diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 454d54cabbdc..b9faa61ad269 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -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: diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py index 6a1d8ac25ff0..601e2d9fdad0 100644 --- a/nova/tests/unit/db/test_db_api.py +++ b/nova/tests/unit/db/test_db_api.py @@ -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, {})