Hyper-V: Fixes snapshoting inexistent VM issue
Instance destroy and Instance snapshot are locking operations, meaning that they can only occur sequentially. This is the result of the commit 6d8903b5d9609305d63aba0067a032a66f5ce3ee The problem is that the destroy instance can occur before snapshoting, resulting in a VM NotFound exception being raised while snapshoting, as the VM no longer exists. In the logs it can be observed that the lock was being held by "do_terminate_instance", which was then aquired by "instance_synchronized_snapshot". Nova ComputeManager expects an InstanceNotFound exception during the snapshot operation. Changes exception raised by VMUtils._check_lookup_vm to InstanceNotFound. Change-Id: I3e4d4f1874c6ee4b410e8bda7412d49f079b5b8f Closes-Bug: #1486458
This commit is contained in:
@@ -122,7 +122,7 @@ class InstanceEventHandler(object):
|
||||
"will be ignored."),
|
||||
instance_name)
|
||||
return instance_uuid
|
||||
except exception.NotFound:
|
||||
except exception.InstanceNotFound:
|
||||
# The instance has been deleted.
|
||||
pass
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class LiveMigrationUtils(object):
|
||||
vms = conn_v2.Msvm_ComputerSystem(ElementName=vm_name)
|
||||
n = len(vms)
|
||||
if not n:
|
||||
raise exception.NotFound(_('VM not found: %s') % vm_name)
|
||||
raise exception.InstanceNotFound(_('VM not found: %s') % vm_name)
|
||||
elif n > 1:
|
||||
raise vmutils.HyperVException(_('Duplicate VM name found: %s')
|
||||
% vm_name)
|
||||
|
||||
@@ -637,7 +637,7 @@ class VMOps(object):
|
||||
|
||||
self._set_vm_state(instance,
|
||||
constants.HYPERV_VM_STATE_DISABLED)
|
||||
except exception.NotFound:
|
||||
except exception.InstanceNotFound:
|
||||
pass
|
||||
|
||||
def power_on(self, instance, block_device_info=None, network_info=None):
|
||||
|
||||
@@ -194,7 +194,7 @@ class VMUtils(object):
|
||||
|
||||
vm = self._lookup_vm(vm_name)
|
||||
if not vm:
|
||||
raise exception.NotFound(_('VM not found: %s') % vm_name)
|
||||
raise exception.InstanceNotFound(_('VM not found: %s') % vm_name)
|
||||
return vm
|
||||
|
||||
def _lookup_vm(self, vm_name):
|
||||
|
||||
@@ -139,7 +139,7 @@ class EventHandlerTestCase(test_base.HyperVBaseTestCase):
|
||||
side_effect = (mock.sentinel.instance_uuid
|
||||
if not missing_uuid else None, )
|
||||
else:
|
||||
side_effect = exception.NotFound
|
||||
side_effect = exception.InstanceNotFound('fake_instance_uuid')
|
||||
mock_get_uuid = self._event_handler._vmutils.get_instance_uuid
|
||||
mock_get_uuid.side_effect = side_effect
|
||||
|
||||
|
||||
@@ -14,14 +14,17 @@
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from nova import exception
|
||||
|
||||
from hyperv.nova import livemigrationutils
|
||||
from hyperv.nova import vmutils
|
||||
from hyperv.tests import test
|
||||
|
||||
|
||||
class LiveMigrationUtilsTestCase(test.NoDBTestCase):
|
||||
"""Unit tests for the Hyper-V LiveMigrationUtils class."""
|
||||
|
||||
_FAKE_VM_NAME = 'fake_vm_name'
|
||||
_FAKE_RET_VAL = 0
|
||||
|
||||
_RESOURCE_TYPE_VHD = 31
|
||||
@@ -51,6 +54,30 @@ class LiveMigrationUtilsTestCase(test.NoDBTestCase):
|
||||
self.liveutils.check_live_migration_config()
|
||||
self.assertTrue(mock_migr_svc.associators.called)
|
||||
|
||||
def test_get_vm(self):
|
||||
expected_vm = mock.MagicMock()
|
||||
mock_conn_v2 = mock.MagicMock()
|
||||
mock_conn_v2.Msvm_ComputerSystem.return_value = [expected_vm]
|
||||
|
||||
found_vm = self.liveutils._get_vm(mock_conn_v2, self._FAKE_VM_NAME)
|
||||
|
||||
self.assertEqual(expected_vm, found_vm)
|
||||
|
||||
def test_get_vm_duplicate(self):
|
||||
mock_vm = mock.MagicMock()
|
||||
mock_conn_v2 = mock.MagicMock()
|
||||
mock_conn_v2.Msvm_ComputerSystem.return_value = [mock_vm, mock_vm]
|
||||
|
||||
self.assertRaises(vmutils.HyperVException, self.liveutils._get_vm,
|
||||
mock_conn_v2, self._FAKE_VM_NAME)
|
||||
|
||||
def test_get_vm_not_found(self):
|
||||
mock_conn_v2 = mock.MagicMock()
|
||||
mock_conn_v2.Msvm_ComputerSystem.return_value = []
|
||||
|
||||
self.assertRaises(exception.InstanceNotFound, self.liveutils._get_vm,
|
||||
mock_conn_v2, self._FAKE_VM_NAME)
|
||||
|
||||
@mock.patch.object(livemigrationutils.LiveMigrationUtils,
|
||||
'_destroy_planned_vm')
|
||||
def test_check_existing_planned_vm_found(self, mock_destroy_planned_vm):
|
||||
|
||||
@@ -926,7 +926,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
mock_set_vm_state.assert_called_once_with(
|
||||
mock_instance, constants.HYPERV_VM_STATE_ENABLED)
|
||||
|
||||
def _test_power_off(self, timeout):
|
||||
def _test_power_off(self, timeout, set_state_expected=True):
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
with mock.patch.object(self._vmops, '_set_vm_state') as mock_set_state:
|
||||
self._vmops.power_off(instance, timeout)
|
||||
@@ -934,8 +934,9 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
serialops = self._vmops._serial_console_ops
|
||||
serialops.stop_console_handler.assert_called_once_with(
|
||||
instance.name)
|
||||
mock_set_state.assert_called_once_with(
|
||||
instance, constants.HYPERV_VM_STATE_DISABLED)
|
||||
if set_state_expected:
|
||||
mock_set_state.assert_called_once_with(
|
||||
instance, constants.HYPERV_VM_STATE_DISABLED)
|
||||
|
||||
def test_power_off_hard(self):
|
||||
self._test_power_off(timeout=0)
|
||||
@@ -945,6 +946,12 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
mock_soft_shutdown.return_value = False
|
||||
self._test_power_off(timeout=1)
|
||||
|
||||
@mock.patch("hyperv.nova.vmops.VMOps._soft_shutdown")
|
||||
def test_power_off_unexisting_instance(self, mock_soft_shutdown):
|
||||
mock_soft_shutdown.side_effect = (
|
||||
exception.InstanceNotFound('fake_instance_uuid'))
|
||||
self._test_power_off(timeout=1, set_state_expected=False)
|
||||
|
||||
@mock.patch("hyperv.nova.vmops.VMOps._set_vm_state")
|
||||
@mock.patch("hyperv.nova.vmops.VMOps._soft_shutdown")
|
||||
def test_power_off_soft(self, mock_soft_shutdown, mock_set_state):
|
||||
|
||||
@@ -119,7 +119,7 @@ class VMUtilsTestCase(test.NoDBTestCase):
|
||||
|
||||
def test_lookup_vm_none(self):
|
||||
self._vmutils._conn.Msvm_ComputerSystem.return_value = []
|
||||
self.assertRaises(exception.NotFound,
|
||||
self.assertRaises(exception.InstanceNotFound,
|
||||
self._vmutils._lookup_vm_check,
|
||||
self._FAKE_VM_NAME)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user