summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorMatthew Sherborne <msherborne@gmail.com>2013-04-20 19:08:07 +1000
committerMatthew Sherborne <msherborne@gmail.com>2013-04-23 22:22:05 +1000
commit40692574bbdefbdfa4a6f3366bec524fd4612400 (patch)
tree80e666e59702888e79422e7c7477089c83e63842 /nova
parentbfc3a3ccb2811cc8a96a15987528e6639ec029bf (diff)
downloadnova-40692574bbdefbdfa4a6f3366bec524fd4612400.tar.gz
nova-40692574bbdefbdfa4a6f3366bec524fd4612400.tar.xz
nova-40692574bbdefbdfa4a6f3366bec524fd4612400.zip
If rescue fails don't error the instance
If a rescue attempt fails, the VM's state should return to what it was before the rescue attempt started, and the user should be notified of the failure. Fixes bug: 1170328 Change-Id: If5e97d06a3617adad83a4bba2ac6320616bbe83b
Diffstat (limited to 'nova')
-rwxr-xr-xnova/compute/manager.py9
-rw-r--r--nova/tests/compute/test_compute.py28
2 files changed, 35 insertions, 2 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 5da050f60..f1ab1629e 100755
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -2007,7 +2007,6 @@ class ComputeManager(manager.SchedulerDependentManager):
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@reverts_task_state
@wrap_instance_event
- @wrap_instance_fault
def rescue_instance(self, context, instance, rescue_password=None):
"""
Rescue an instance on this host.
@@ -2028,10 +2027,16 @@ class ComputeManager(manager.SchedulerDependentManager):
else:
rescue_image_meta = {}
- with self._error_out_instance_on_exception(context, instance['uuid']):
+ try:
self.driver.rescue(context, instance,
self._legacy_nw_info(network_info),
rescue_image_meta, admin_password)
+ except Exception as e:
+ LOG.exception(_("Error trying to Rescue Instance"),
+ instance=instance)
+ raise exception.InstanceNotRescuable(
+ instance_id=instance['uuid'],
+ reason=_("Driver Error: %s") % unicode(e))
current_power_state = self._get_power_state(context, instance)
self._instance_update(context,
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index 6bf612eee..e3db2cdba 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -22,6 +22,7 @@ import base64
import copy
import datetime
import sys
+import testtools
import time
import traceback
import uuid
@@ -1265,6 +1266,33 @@ class ComputeTestCase(BaseTestCase):
self.compute.terminate_instance(self.context, instance=instance)
+ def test_rescue_handle_err(self):
+ # If the driver fails to rescue, instance state should remain the same
+ # and the exception should be converted to InstanceNotRescuable
+ instance = jsonutils.to_primitive(self._create_fake_instance())
+ self.mox.StubOutWithMock(self.compute, '_get_rescue_image_ref')
+ self.mox.StubOutWithMock(nova.virt.fake.FakeDriver, 'rescue')
+
+ self.compute._get_rescue_image_ref(
+ mox.IgnoreArg(), instance).AndReturn('resc_image_ref')
+ nova.virt.fake.FakeDriver.rescue(
+ mox.IgnoreArg(), instance, [], mox.IgnoreArg(), 'password'
+ ).AndRaise(RuntimeError("Try again later"))
+
+ self.mox.ReplayAll()
+
+ expected_message = ('Instance %s cannot be rescued: '
+ 'Driver Error: Try again later' % instance['uuid'])
+ instance['vm_state'] = 'some_random_state'
+
+ with testtools.ExpectedException(
+ exception.InstanceNotRescuable, expected_message):
+ self.compute.rescue_instance(
+ self.context, instance=instance,
+ rescue_password='password')
+
+ self.assertEqual('some_random_state', instance['vm_state'])
+
def test_power_on(self):
# Ensure instance can be powered on.