summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorChris Behrens <cbehrens@codestud.com>2012-07-07 21:38:36 -0700
committerChris Behrens <cbehrens@codestud.com>2012-07-08 05:43:48 +0000
commita97de51e017c9c07eaa3e4a9ddde4193e9528373 (patch)
tree51a88ab226de81c38120796880fe061ee7190c18 /nova
parent642ec634c3beeb69175d0df12bcec8833e7efae5 (diff)
Make reboot work for halted xenapi instances
Fixes bug 1022199 This also will catch exceptions and make sure to reset the task_state, while still generating an instance fault. Change-Id: I122a1422b8e5731bc484414736ab44e60d4c9830
Diffstat (limited to 'nova')
-rw-r--r--nova/compute/manager.py11
-rw-r--r--nova/tests/test_xenapi.py35
-rw-r--r--nova/virt/xenapi/fake.py12
-rw-r--r--nova/virt/xenapi/vmops.py18
4 files changed, 69 insertions, 7 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index afd422253..aacfdf7a7 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -959,8 +959,15 @@ class ComputeManager(manager.SchedulerDependentManager):
context=context, instance_uuid=instance_uuid)
network_info = self._get_instance_nw_info(context, instance)
- self.driver.reboot(instance, self._legacy_nw_info(network_info),
- reboot_type)
+ try:
+ self.driver.reboot(instance, self._legacy_nw_info(network_info),
+ reboot_type)
+ except Exception, exc:
+ LOG.error(_('Cannot reboot instance: %(exc)s'), locals(),
+ context=context, instance_uuid=instance_uuid)
+ self.add_instance_fault_from_exc(context, instance_uuid, exc,
+ sys.exc_info())
+ # Fall through and reset task_state to None
current_power_state = self._get_power_state(context, instance)
self._instance_update(context,
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index 3138ef0b9..aeacf1fa6 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -807,6 +807,33 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
conn.finish_revert_migration(instance, None)
self.assertTrue(conn._vmops.finish_revert_migration_called)
+ def test_reboot_hard(self):
+ instance = self._create_instance()
+ conn = xenapi_conn.XenAPIDriver(False)
+ conn.reboot(instance, None, "HARD")
+
+ def test_reboot_soft(self):
+ instance = self._create_instance()
+ conn = xenapi_conn.XenAPIDriver(False)
+ conn.reboot(instance, None, "SOFT")
+
+ def test_reboot_halted(self):
+ session = xenapi_conn.XenAPISession('test_url', 'root', 'test_pass')
+ instance = self._create_instance(spawn=False)
+ conn = xenapi_conn.XenAPIDriver(False)
+ xenapi_fake.create_vm(instance.name, 'Halted')
+ conn.reboot(instance, None, "SOFT")
+ vm_ref = vm_utils.lookup(session, instance.name)
+ vm = xenapi_fake.get_record('VM', vm_ref)
+ self.assertEquals(vm['power_state'], 'Running')
+
+ def test_reboot_unknown_state(self):
+ instance = self._create_instance(spawn=False)
+ conn = xenapi_conn.XenAPIDriver(False)
+ xenapi_fake.create_vm(instance.name, 'Unknown')
+ self.assertRaises(xenapi_fake.Failure, conn.reboot, instance,
+ None, "SOFT")
+
def _create_instance(self, instance_id=1, spawn=True):
"""Creates and spawns a test instance."""
instance_values = {
@@ -938,6 +965,14 @@ class XenAPIMigrateInstance(stubs.XenAPITestBase):
conn.migrate_disk_and_power_off(self.context, instance,
'127.0.0.1', instance_type, None)
+ def test_migrate_disk_and_power_off(self):
+ instance = db.instance_create(self.context, self.instance_values)
+ xenapi_fake.create_vm(instance.name, 'Running')
+ instance_type = db.instance_type_get_by_name(self.context, 'm1.large')
+ conn = xenapi_conn.XenAPIDriver(False)
+ conn.migrate_disk_and_power_off(self.context, instance,
+ '127.0.0.1', instance_type, None)
+
def test_migrate_disk_and_power_off_passes_exceptions(self):
instance = db.instance_create(self.context, self.instance_values)
xenapi_fake.create_vm(instance.name, 'Running')
diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py
index 72008a69d..050b696f0 100644
--- a/nova/virt/xenapi/fake.py
+++ b/nova/virt/xenapi/fake.py
@@ -536,8 +536,18 @@ class SessionBase(object):
VDI_resize = VDI_resize_online
+ def _VM_reboot(self, session, vm_ref):
+ db_ref = _db_content['VM'][vm_ref]
+ if db_ref['power_state'] != 'Running':
+ raise Failure(['VM_BAD_POWER_STATE',
+ 'fake-opaque-ref', db_ref['power_state'].lower(), 'halted'])
+ db_ref['power_state'] = 'Running'
+
def VM_clean_reboot(self, session, vm_ref):
- pass
+ return self._VM_reboot(session, vm_ref)
+
+ def VM_hard_reboot(self, session, vm_ref):
+ return self._VM_reboot(session, vm_ref)
def VM_hard_shutdown(self, session, vm_ref):
db_ref = _db_content['VM'][vm_ref]
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 6af2ac9e0..5d445e0a6 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -843,10 +843,20 @@ class VMOps(object):
# remove existing filters
vm_ref = self._get_vm_opaque_ref(instance)
- if reboot_type == "HARD":
- self._session.call_xenapi('VM.hard_reboot', vm_ref)
- else:
- self._session.call_xenapi('VM.clean_reboot', vm_ref)
+ try:
+ if reboot_type == "HARD":
+ self._session.call_xenapi('VM.hard_reboot', vm_ref)
+ else:
+ self._session.call_xenapi('VM.clean_reboot', vm_ref)
+ except self._session.XenAPI.Failure, exc:
+ details = exc.details
+ if (details[0] == 'VM_BAD_POWER_STATE' and
+ details[-1] == 'halted'):
+ LOG.info(_("Starting halted instance found during reboot"),
+ instance=instance)
+ self._session.call_xenapi('VM.start', vm_ref, False, False)
+ return
+ raise
def _get_agent_version(self, instance):
"""Get the version of the agent running on the VM instance."""