Skip to content

Commit

Permalink
Make reboot work for halted xenapi instances
Browse files Browse the repository at this point in the history
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
  • Loading branch information
comstud committed Jul 8, 2012
1 parent 642ec63 commit a97de51
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 7 deletions.
11 changes: 9 additions & 2 deletions nova/compute/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -959,8 +959,15 @@ def reboot_instance(self, context, instance_uuid, reboot_type="SOFT"):
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,
Expand Down
35 changes: 35 additions & 0 deletions nova/tests/test_xenapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,33 @@ def finish_revert_migration(self, instance):
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 = {
Expand Down Expand Up @@ -938,6 +965,14 @@ def test_migrate_disk_and_power_off(self):
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')
Expand Down
12 changes: 11 additions & 1 deletion nova/virt/xenapi/fake.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,18 @@ def VDI_resize_online(self, *args):

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]
Expand Down
18 changes: 14 additions & 4 deletions nova/virt/xenapi/vmops.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,10 +843,20 @@ def reboot(self, instance, reboot_type):
# 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."""
Expand Down

0 comments on commit a97de51

Please sign in to comment.