diff options
| -rwxr-xr-x | nova/compute/manager.py | 39 | ||||
| -rw-r--r-- | nova/tests/compute/test_compute.py | 30 |
2 files changed, 58 insertions, 11 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 2390eb3c3..998be6f76 100755 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1297,6 +1297,16 @@ class ComputeManager(manager.SchedulerDependentManager): admin_password, is_first_time, node, instance) do_run_instance() + def _try_deallocate_network(self, context, instance): + try: + # tear down allocated network structure + self._deallocate_network(context, instance) + except Exception: + with excutils.save_and_reraise_exception(): + LOG.error(_('Failed to deallocate network for instance.'), + instance=instance) + self._set_instance_error_state(context, instance['uuid']) + def _shutdown_instance(self, context, instance, bdms): """Shutdown an instance on this host.""" context = context.elevated() @@ -1311,21 +1321,28 @@ class ComputeManager(manager.SchedulerDependentManager): except exception.NetworkNotFound: network_info = network_model.NetworkInfo() - try: - # tear down allocated network structure - self._deallocate_network(context, instance) - except Exception: - with excutils.save_and_reraise_exception(): - LOG.error(_('Failed to deallocate network for instance.'), - instance=instance) - self._set_instance_error_state(context, instance['uuid']) - # NOTE(vish) get bdms before destroying the instance vol_bdms = self._get_volume_bdms(bdms) block_device_info = self._get_instance_volume_block_device_info( context, instance, bdms=bdms) - self.driver.destroy(instance, self._legacy_nw_info(network_info), - block_device_info) + + # NOTE(melwitt): attempt driver destroy before releasing ip, may + # want to keep ip allocated for certain failures + try: + self.driver.destroy(instance, self._legacy_nw_info(network_info), + block_device_info) + except exception.InstancePowerOffFailure: + # if the instance can't power off, don't release the ip + with excutils.save_and_reraise_exception(): + pass + except Exception: + with excutils.save_and_reraise_exception(): + # deallocate ip and fail without proceeding to + # volume api calls, preserving current behavior + self._try_deallocate_network(context, instance) + + self._try_deallocate_network(context, instance) + for bdm in vol_bdms: try: # NOTE(vish): actual driver detach done in driver.destroy, so diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index fc3e0126b..724635475 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -2337,6 +2337,36 @@ class ComputeTestCase(BaseTestCase): instance=jsonutils.to_primitive(instance), bdms={}) + def test_delete_instance_keeps_net_on_power_off_fail(self): + self.mox.StubOutWithMock(self.compute.driver, 'destroy') + self.mox.StubOutWithMock(self.compute, '_deallocate_network') + exp = exception.InstancePowerOffFailure(reason='') + self.compute.driver.destroy(mox.IgnoreArg(), mox.IgnoreArg(), + mox.IgnoreArg()).AndRaise(exp) + # mox will detect if _deallocate_network gets called unexpectedly + self.mox.ReplayAll() + instance = self._create_fake_instance() + self.assertRaises(exception.InstancePowerOffFailure, + self.compute._delete_instance, + self.context, + instance=jsonutils.to_primitive(instance), + bdms={}) + + def test_delete_instance_loses_net_on_other_fail(self): + self.mox.StubOutWithMock(self.compute.driver, 'destroy') + self.mox.StubOutWithMock(self.compute, '_deallocate_network') + exp = test.TestingException() + self.compute.driver.destroy(mox.IgnoreArg(), mox.IgnoreArg(), + mox.IgnoreArg()).AndRaise(exp) + self.compute._deallocate_network(mox.IgnoreArg(), mox.IgnoreArg()) + self.mox.ReplayAll() + instance = self._create_fake_instance() + self.assertRaises(test.TestingException, + self.compute._delete_instance, + self.context, + instance=jsonutils.to_primitive(instance), + bdms={}) + def test_delete_instance_deletes_console_auth_tokens(self): instance = self._create_fake_instance() self.flags(vnc_enabled=True) |
