summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2022-09-07 02:20:50 +0000
committerGerrit Code Review <review@openstack.org>2022-09-07 02:20:50 +0000
commit5633be211f4c2e656a585b4ff5ce94035a0df767 (patch)
treef957c4d8754e3bf682ac943bb409f75ea9b4d41d
parent5e8f34ca380493bc2a57e0ad14eb7b4a431872b6 (diff)
parentfc20dc2ea23d511a0f741901d7f03135bb269165 (diff)
downloadnova-5633be211f4c2e656a585b4ff5ce94035a0df767.tar.gz
Merge "Avoid unbound instance_uuid var during delete" into stable/wallaby
-rw-r--r--nova/compute/api.py10
-rw-r--r--nova/tests/unit/compute/test_api.py28
2 files changed, 34 insertions, 4 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index d938a910e5..774eb538c0 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -2231,6 +2231,12 @@ class API(base.Base):
# Normal delete should be attempted.
may_have_ports_or_volumes = compute_utils.may_have_ports_or_volumes(
instance)
+
+ # Save a copy of the instance UUID early, in case
+ # _lookup_instance returns instance = None, to pass to
+ # _local_delete_cleanup if needed.
+ instance_uuid = instance.uuid
+
if not instance.host and not may_have_ports_or_volumes:
try:
if self._delete_while_booting(context, instance):
@@ -2244,10 +2250,6 @@ class API(base.Base):
# full Instance or None if not found. If not found then it's
# acceptable to skip the rest of the delete processing.
- # Save a copy of the instance UUID early, in case
- # _lookup_instance returns instance = None, to pass to
- # _local_delete_cleanup if needed.
- instance_uuid = instance.uuid
cell, instance = self._lookup_instance(context, instance.uuid)
if cell and instance:
try:
diff --git a/nova/tests/unit/compute/test_api.py b/nova/tests/unit/compute/test_api.py
index 822bfc1a15..809ed3b295 100644
--- a/nova/tests/unit/compute/test_api.py
+++ b/nova/tests/unit/compute/test_api.py
@@ -1620,6 +1620,34 @@ class _ComputeAPIUnitTestMixIn(object):
self.compute_api.notifier, self.context, instance)
destroy_mock.assert_called_once_with()
+ def test_delete_instance_while_booting_host_changes_lookup_fails(self):
+ """Tests the case where the instance become scheduled while being
+ destroyed but then the final lookup fails.
+ """
+ instance = self._create_instance_obj({'host': None})
+
+ with test.nested(
+ mock.patch.object(
+ self.compute_api, '_delete_while_booting',
+ side_effect=exception.ObjectActionError(
+ action="delete", reason="reason")),
+ mock.patch.object(
+ self.compute_api, '_lookup_instance',
+ return_value=(None, None)),
+ mock.patch.object(self.compute_api, '_local_delete_cleanup')
+ ) as (
+ _delete_while_booting, _lookup_instance, _local_delete_cleanup
+ ):
+ self.compute_api._delete(
+ self.context, instance, 'delete', mock.NonCallableMock())
+
+ _delete_while_booting.assert_called_once_with(
+ self.context, instance)
+ _lookup_instance.assert_called_once_with(
+ self.context, instance.uuid)
+ _local_delete_cleanup.assert_called_once_with(
+ self.context, instance.uuid)
+
@mock.patch.object(context, 'target_cell')
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid',
side_effect=exception.InstanceMappingNotFound(