Skip to content

Commit 26da441

Browse files
committed
Deal with cross-cell resize in _remove_deleted_instances_allocations
When reverting a cross-cell resize, conductor will: 1. clean up the destination host 2. set instance.hidden=True and destroy the instance in the target cell database 3. finish the revert on the source host which will revert the allocations on the source host held by the migration record so the instance will hold those again and drop the allocations against the dest host which were held by the instance. If the ResourceTracker.update_available_resource periodic task runs between steps 2 and 3 it could see that the instance is deleted from the target cell but there are still allocations held by it and delete them. Step 3 is what handles deleting those allocations for the destination node, so we want to leave it that way and take the ResourceTracker out of the flow. This change simply checks the instance.hidden value on the deleted instance and if hidden=True, assumes the allocations will be cleaned up elsehwere (finish_revert_snapshot_based_resize_at_source). Ultimately this is probably not something we *have* to have since finish_revert_snapshot_based_resize_at_source is going to drop the destination node allocations anyway, but it is good to keep clear which actor is doing what in this process. Part of blueprint cross-cell-resize Change-Id: Idb82b056c39fd167864cadd205d624cb87cbe9cb
1 parent 11b7bcd commit 26da441

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

nova/compute/resource_tracker.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,11 +1506,17 @@ def _remove_deleted_instances_allocations(self, context, cn,
15061506
exc_info=False)
15071507
continue
15081508

1509-
if instance.deleted:
1509+
# NOTE(mriedem): A cross-cell migration will work with instance
1510+
# records across two cells once the migration is confirmed/reverted
1511+
# one of them will be deleted but the instance still exists in the
1512+
# other cell. Before the instance is destroyed from the old cell
1513+
# though it is marked hidden=True so if we find a deleted hidden
1514+
# instance with allocations against this compute node we just
1515+
# ignore it since the migration operation will handle cleaning up
1516+
# those allocations.
1517+
if instance.deleted and not instance.hidden:
15101518
# The instance is gone, so we definitely want to remove
15111519
# allocations associated with it.
1512-
# NOTE(jaypipes): This will not be true if/when we support
1513-
# cross-cell migrations...
15141520
LOG.debug("Instance %s has been deleted (perhaps locally). "
15151521
"Deleting allocations that remained for this "
15161522
"instance against this compute host: %s.",

nova/tests/unit/compute/test_resource_tracker.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3355,7 +3355,7 @@ def test_remove_deleted_instances_allocations_deleted_instance(self,
33553355
return_value=allocs)
33563356
rc.delete_allocation_for_instance = mock.MagicMock()
33573357
mock_inst_get.return_value = objects.Instance(
3358-
uuid=uuids.deleted, deleted=True)
3358+
uuid=uuids.deleted, deleted=True, hidden=False)
33593359
cn = self.rt.compute_nodes[_NODENAME]
33603360
ctx = mock.MagicMock()
33613361
# Call the method.
@@ -3370,6 +3370,35 @@ def test_remove_deleted_instances_allocations_deleted_instance(self,
33703370
expected_attrs=[])
33713371
ctx.elevated.assert_called_once_with(read_deleted='yes')
33723372

3373+
@mock.patch('nova.objects.Instance.get_by_uuid')
3374+
def test_remove_deleted_instances_allocations_deleted_hidden_instance(self,
3375+
mock_inst_get):
3376+
"""Tests the scenario where there are allocations against the local
3377+
compute node held by a deleted instance but it is hidden=True so the
3378+
ResourceTracker does not delete the allocations because it assumes
3379+
the cross-cell resize flow will handle the allocations.
3380+
"""
3381+
rc = self.rt.reportclient
3382+
allocs = report.ProviderAllocInfo(
3383+
allocations={uuids.deleted: "fake_deleted_instance"})
3384+
rc.get_allocations_for_resource_provider = mock.MagicMock(
3385+
return_value=allocs)
3386+
rc.delete_allocation_for_instance = mock.MagicMock()
3387+
cn = self.rt.compute_nodes[_NODENAME]
3388+
mock_inst_get.return_value = objects.Instance(
3389+
uuid=uuids.deleted, deleted=True, hidden=True,
3390+
host=cn.host, node=cn.hypervisor_hostname,
3391+
task_state=task_states.RESIZE_MIGRATING)
3392+
ctx = mock.MagicMock()
3393+
# Call the method.
3394+
self.rt._remove_deleted_instances_allocations(ctx, cn, [], {})
3395+
# Only one call should be made to delete allocations, and that should
3396+
# be for the first instance created above
3397+
rc.delete_allocation_for_instance.assert_not_called()
3398+
mock_inst_get.assert_called_once_with(
3399+
ctx.elevated.return_value, uuids.deleted, expected_attrs=[])
3400+
ctx.elevated.assert_called_once_with(read_deleted='yes')
3401+
33733402
@mock.patch('nova.objects.Instance.get_by_uuid')
33743403
def test_remove_deleted_instances_allocations_building_instance(self,
33753404
mock_inst_get):
@@ -3401,7 +3430,7 @@ def test_remove_deleted_instances_allocations_ignores_migrations(self,
34013430
return_value=allocs)
34023431
rc.delete_allocation_for_instance = mock.MagicMock()
34033432
mock_inst_get.return_value = objects.Instance(
3404-
uuid=uuids.deleted, deleted=True)
3433+
uuid=uuids.deleted, deleted=True, hidden=False)
34053434
cn = self.rt.compute_nodes[_NODENAME]
34063435
ctx = mock.MagicMock()
34073436
# Call the method.

0 commit comments

Comments
 (0)