From 5a20996405c5788855a2457283bbbe7d78140a9c Mon Sep 17 00:00:00 2001 From: Matt Riedemann Date: Tue, 29 Oct 2019 12:10:08 -0400 Subject: [PATCH] Reset instance to current vm_state if rolling back in resize_instance You can resize a stopped instance and if the compute driver raises InstanceFaultRollback from migrate_disk_and_power_off, the _error_out_instance_on_exception decorator, used in the _resize_instance method, will by default reset the instance vm_state to ACTIVE even though the guest is stopped. The driver could raise InstanceFaultRollback if you try resizing the root disk down on a non-volume-backed instance. This builds on [1] and does the same thing as prep_resize [2] for making sure the original vm_state is reset on InstanceFaultRollback. [1] Ie4f9177f4d54cbc7dbcf58bd107fd5f24c60d8bb [2] I17543ecb572934ecc7d0bbc7a4ad2f537fa499bc Change-Id: Iff1f9f28a1e4ecf00368cbcac27b7687a5eb0dcf Closes-Bug: #1551703 --- nova/compute/manager.py | 7 ++++++- nova/tests/unit/compute/test_compute_mgr.py | 22 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 79fc3058eb9c..6584edb3abd9 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -5032,7 +5032,12 @@ class ComputeManager(manager.Manager): def _resize_instance(self, context, instance, image, migration, instance_type, clean_shutdown, request_spec): - with self._error_out_instance_on_exception(context, instance), \ + # Pass instance_state=instance.vm_state because we can resize + # a STOPPED server and we don't want to set it back to ACTIVE + # in case migrate_disk_and_power_off raises InstanceFaultRollback. + instance_state = instance.vm_state + with self._error_out_instance_on_exception( + context, instance, instance_state=instance_state), \ errors_out_migration_ctxt(migration): network_info = self.network_api.get_instance_nw_info(context, instance) diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index 0712767f85cb..94a9bb0d9894 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -7829,6 +7829,28 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase, # Assert that we set the migration to an error state self.assertEqual("error", self.migration.status) + def test_resize_instance_fail_rollback_stays_stopped(self): + """Tests that when the driver's migrate_disk_and_power_off method + raises InstanceFaultRollback that the instance vm_state is preserved + rather than reset to ACTIVE which would be wrong if resizing a STOPPED + server. + """ + with self._mock_resize_instance() as ( + migrate_disk_and_power_off, notify): + migrate_disk_and_power_off.side_effect = \ + exception.InstanceFaultRollback( + exception.ResizeError(reason='unable to resize disk down')) + self.instance.vm_state = vm_states.STOPPED + self.assertRaises( + exception.ResizeError, self.compute.resize_instance, + context=self.context, instance=self.instance, image=self.image, + migration=self.migration, + instance_type='type', clean_shutdown=True, + request_spec=objects.RequestSpec()) + + # Assert the instance vm_state was unchanged. + self.assertEqual(vm_states.STOPPED, self.instance.vm_state) + def test_resize_instance_notify_failure(self): # Raise an exception sending the end notification, which is after we # cast the migration to the destination host