Avoid propagating wmi exceptions for soft shutdown

The soft shutdown operation is expected to fail while the VM is
still booting. The issue is that in some cases, os-win will
propagate a wmi exception that Nova cannot handle:

http://paste.openstack.org/raw/800833/

That's because of Msvm_ShutdownComponent.InitiateShutdown, an
asynchronous WMI method that can sometimes throw a wmi exception
right away.

For now, we're taking care of this specific WMI call only. If needed,
we may consider handling all async WMI methods by introducing a new
decorator or helper function.

Change-Id: I9263b14c3c343db6453645152cb9274e38864b48
Closes-Bug: #1907270
This commit is contained in:
Lucian Petrut 2020-12-08 16:59:33 +02:00
parent 954693f5ff
commit fa9061f31d
2 changed files with 31 additions and 11 deletions

View File

@ -233,6 +233,19 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
self._vmutils._jobutils.check_ret_val.assert_called_once_with(
self._FAKE_RET_VAL, None)
def test_soft_shutdown_vm_wmi_exc(self):
self._lookup_vm()
mock_shutdown = mock.MagicMock()
mock_shutdown.InitiateShutdown.side_effect = exceptions.x_wmi
self._vmutils._conn.Msvm_ShutdownComponent.return_value = [
mock_shutdown]
# We ensure that the wmi exception gets converted.
self.assertRaises(
exceptions.HyperVException,
self._vmutils.soft_shutdown_vm,
self._FAKE_VM_NAME)
def test_soft_shutdown_vm_no_component(self):
mock_vm = self._lookup_vm()
self._vmutils._conn.Msvm_ShutdownComponent.return_value = []

View File

@ -662,19 +662,26 @@ class VMUtils(baseutils.BaseUtilsVirt):
return [nic.ElementName for nic in nics]
def soft_shutdown_vm(self, vm_name):
vm = self._lookup_vm_check(vm_name, as_vssd=False)
shutdown_component = self._conn.Msvm_ShutdownComponent(
SystemName=vm.Name)
try:
vm = self._lookup_vm_check(vm_name, as_vssd=False)
shutdown_component = self._conn.Msvm_ShutdownComponent(
SystemName=vm.Name)
if not shutdown_component:
# If no shutdown_component is found, it means the VM is already
# in a shutdown state.
return
if not shutdown_component:
# If no shutdown_component is found, it means the VM is already
# in a shutdown state.
return
reason = 'Soft shutdown requested by OpenStack Nova.'
(ret_val, ) = shutdown_component[0].InitiateShutdown(Force=False,
Reason=reason)
self._jobutils.check_ret_val(ret_val, None)
reason = 'Soft shutdown requested by OpenStack Nova.'
(ret_val, ) = shutdown_component[0].InitiateShutdown(Force=False,
Reason=reason)
self._jobutils.check_ret_val(ret_val, None)
except exceptions.x_wmi as ex:
# This operation is expected to fail while the instance is booting.
# In some cases, InitiateShutdown immediately throws an error
# instead of returning an asynchronous job reference.
msg = _("Soft shutdown failed. VM name: %s. Error: %s.")
raise exceptions.HyperVException(msg % (vm_name, ex))
@_utils.retry_decorator(exceptions=exceptions.WMIJobFailed)
def set_vm_state(self, vm_name, req_state):