Skip to content

Commit

Permalink
Allow VMs to be resumed after a hypervisor reboot
Browse files Browse the repository at this point in the history
Fixes bug 1052696.

Update the compute manager to pass network_info and block_device_info
to the driver.resume() and update all virtualization drivers to accept
the new arguments.

For libvirt, change resume() to use _create_domain_and_network()
rather than _create_domain(). This eliminates the assumption that the
network and block device connections remained in place from the period
between the VM being suspended and resumed.  Instead, all the
networking and block connections will be rebuilt on resume (in case
they are missing) as is the case after a hypervisor reboot.

Change-Id: I6e19ec42f7e929678abce8f276c0a6e91f1fa8af
  • Loading branch information
rmk40 committed Nov 20, 2012
1 parent e984c20 commit 99b5e96
Show file tree
Hide file tree
Showing 11 changed files with 29 additions and 15 deletions.
8 changes: 7 additions & 1 deletion nova/compute/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2145,7 +2145,13 @@ def resume_instance(self, context, instance):
"""Resume the given suspended instance."""
context = context.elevated()
LOG.audit(_('Resuming'), context=context, instance=instance)
self.driver.resume(instance)

network_info = self._get_instance_nw_info(context, instance)
block_device_info = self._get_instance_volume_block_device_info(
context, instance['uuid'])

self.driver.resume(instance, self._legacy_nw_info(network_info),
block_device_info)

current_power_state = self._get_power_state(context, instance)
self._instance_update(context,
Expand Down
6 changes: 6 additions & 0 deletions nova/tests/test_hypervapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,18 @@ def test_suspend_already_suspended(self):
constants.HYPERV_VM_STATE_SUSPENDED,
constants.HYPERV_VM_STATE_SUSPENDED)

# NOTE (rmk): Resume now takes 3 mandatory args. These tests need to
# be updated but cannot be without involvement from the maintainers
# of the HyperV driver/tests.
def test_resume(self):
self.skipTest("Requires updating.")
self._test_vm_state_change(self._conn.resume,
constants.HYPERV_VM_STATE_SUSPENDED,
constants.HYPERV_VM_STATE_ENABLED)

# NOTE: (rmk): See comment for test_resume().
def test_resume_already_running(self):
self.skipTest("Requires updating.")
self._test_vm_state_change(self._conn.resume, None,
constants.HYPERV_VM_STATE_ENABLED)

Expand Down
4 changes: 2 additions & 2 deletions nova/tests/test_virt_drivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,13 +340,13 @@ def test_suspend(self):
@catch_notimplementederror
def test_resume_unsuspended_instance(self):
instance_ref, network_info = self._get_running_instance()
self.connection.resume(instance_ref)
self.connection.resume(instance_ref, network_info)

@catch_notimplementederror
def test_resume_suspended_instance(self):
instance_ref, network_info = self._get_running_instance()
self.connection.suspend(instance_ref)
self.connection.resume(instance_ref)
self.connection.resume(instance_ref, network_info)

@catch_notimplementederror
def test_destroy_instance_nonexistent(self):
Expand Down
6 changes: 3 additions & 3 deletions nova/tests/test_vmwareapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,21 +215,21 @@ def test_resume(self):
self.conn.suspend(self.instance)
info = self.conn.get_info({'name': 1})
self._check_vm_info(info, power_state.PAUSED)
self.conn.resume(self.instance)
self.conn.resume(self.instance, self.network_info)
info = self.conn.get_info({'name': 1})
self._check_vm_info(info, power_state.RUNNING)

def test_resume_non_existent(self):
self._create_instance_in_the_db()
self.assertRaises(exception.InstanceNotFound, self.conn.resume,
self.instance)
self.instance, self.network_info)

def test_resume_not_suspended(self):
self._create_vm()
info = self.conn.get_info({'name': 1})
self._check_vm_info(info, power_state.RUNNING)
self.assertRaises(exception.InstanceResumeFailure, self.conn.resume,
self.instance)
self.instance, self.network_info)

def test_get_info(self):
self._create_vm()
Expand Down
2 changes: 1 addition & 1 deletion nova/virt/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def suspend(self, instance):
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()

def resume(self, instance):
def resume(self, instance, network_info, block_device_info=None):
"""resume the specified instance"""
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
Expand Down
2 changes: 1 addition & 1 deletion nova/virt/fake.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def unpause(self, instance):
def suspend(self, instance):
pass

def resume(self, instance):
def resume(self, instance, network_info, block_device_info=None):
pass

def destroy(self, instance, network_info, block_device_info=None):
Expand Down
2 changes: 1 addition & 1 deletion nova/virt/hyperv/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def unpause(self, instance):
def suspend(self, instance):
self._vmops.suspend(instance)

def resume(self, instance):
def resume(self, instance, network_info, block_device_info=None):
self._vmops.resume(instance)

def power_off(self, instance):
Expand Down
8 changes: 5 additions & 3 deletions nova/virt/libvirt/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -998,10 +998,12 @@ def suspend(self, instance):
dom.managedSave(0)

@exception.wrap_exception()
def resume(self, instance):
def resume(self, instance, network_info, block_device_info=None):
"""resume the specified instance"""
dom = self._lookup_by_name(instance['name'])
self._create_domain(domain=dom)
xml = self._get_domain_xml(instance, network_info,
block_device_info=None)
self._create_domain_and_network(xml, instance, network_info,
block_device_info)

@exception.wrap_exception()
def resume_state_on_host_boot(self, context, instance, network_info,
Expand Down
2 changes: 1 addition & 1 deletion nova/virt/powervm/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def suspend(self, instance):
"""suspend the specified instance"""
pass

def resume(self, instance):
def resume(self, instance, network_info, block_device_info=None):
"""resume the specified instance"""
pass

Expand Down
2 changes: 1 addition & 1 deletion nova/virt/vmwareapi/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def suspend(self, instance):
"""Suspend the specified instance."""
self._vmops.suspend(instance)

def resume(self, instance):
def resume(self, instance, network_info, block_device_info=None):
"""Resume the suspended VM instance."""
self._vmops.resume(instance)

Expand Down
2 changes: 1 addition & 1 deletion nova/virt/xenapi/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def suspend(self, instance):
"""suspend the specified instance"""
self._vmops.suspend(instance)

def resume(self, instance):
def resume(self, instance, network_info, block_device_info=None):
"""resume the specified instance"""
self._vmops.resume(instance)

Expand Down

0 comments on commit 99b5e96

Please sign in to comment.