Merge "Raise InstanceFaultRollback for UnableToMigrateToSelf from _prep_resize" into stable/stein

This commit is contained in:
Zuul
2019-06-28 19:16:58 +00:00
committed by Gerrit Code Review
3 changed files with 78 additions and 4 deletions

View File

@@ -4370,8 +4370,12 @@ class ComputeManager(manager.Manager):
# check driver whether support migrate to same host
if not self.driver.capabilities.get(
'supports_migrate_to_same_host', False):
raise exception.UnableToMigrateToSelf(
instance_id=instance.uuid, host=self.host)
# Raise InstanceFaultRollback so that the
# _error_out_instance_on_exception context manager in
# prep_resize will set the instance.vm_state properly.
raise exception.InstanceFaultRollback(
inner_exception=exception.UnableToMigrateToSelf(
instance_id=instance.uuid, host=self.host))
# NOTE(danms): Stash the new instance_type to avoid having to
# look it up in the database later
@@ -4445,8 +4449,13 @@ class ComputeManager(manager.Manager):
if node is None:
node = self._get_nodename(instance, refresh=True)
with self._error_out_instance_on_exception(context, instance), \
errors_out_migration_ctxt(migration):
# Pass instance_state=instance.vm_state because we can resize
# a STOPPED server and we don't want to set it back to ACTIVE
# in case _prep_resize fails.
instance_state = instance.vm_state
with self._error_out_instance_on_exception(
context, instance, instance_state=instance_state),\
errors_out_migration_ctxt(migration):
self._send_prep_resize_notifications(
context, instance, fields.NotificationPhase.START,
instance_type)

View File

@@ -8850,6 +8850,68 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
doit()
def test_prep_resize_fails_unable_to_migrate_to_self(self):
"""Asserts that _prep_resize handles UnableToMigrateToSelf when
_prep_resize is called on the host on which the instance lives and
the flavor is not changing.
"""
instance = fake_instance.fake_instance_obj(
self.context, host=self.compute.host,
expected_attrs=['system_metadata', 'flavor'])
migration = mock.MagicMock(spec='nova.objects.Migration')
with mock.patch.dict(self.compute.driver.capabilities,
{'supports_migrate_to_same_host': False}):
ex = self.assertRaises(
exception.InstanceFaultRollback, self.compute._prep_resize,
self.context, instance.image_meta, instance, instance.flavor,
filter_properties={}, node=instance.node, migration=migration)
self.assertIsInstance(
ex.inner_exception, exception.UnableToMigrateToSelf)
@mock.patch('nova.compute.utils.notify_usage_exists')
@mock.patch('nova.compute.manager.ComputeManager.'
'_notify_about_instance_usage')
@mock.patch('nova.compute.utils.notify_about_resize_prep_instance')
@mock.patch('nova.objects.Instance.save')
@mock.patch('nova.compute.manager.ComputeManager._revert_allocation')
@mock.patch('nova.compute.manager.ComputeManager.'
'_reschedule_resize_or_reraise')
@mock.patch('nova.compute.utils.add_instance_fault_from_exc')
def test_prep_resize_fails_rollback(
self, add_instance_fault_from_exc, _reschedule_resize_or_reraise,
_revert_allocation, mock_instance_save,
notify_about_resize_prep_instance, _notify_about_instance_usage,
notify_usage_exists):
"""Tests that if _prep_resize raises InstanceFaultRollback, the
instance.vm_state is reset properly in _error_out_instance_on_exception
"""
instance = fake_instance.fake_instance_obj(
self.context, host=self.compute.host, vm_state=vm_states.STOPPED,
expected_attrs=['system_metadata', 'flavor'])
migration = mock.MagicMock(spec='nova.objects.Migration')
request_spec = mock.MagicMock(spec='nova.objects.RequestSpec')
ex = exception.InstanceFaultRollback(
inner_exception=exception.UnableToMigrateToSelf(
instance_id=instance.uuid, host=instance.host))
def fake_reschedule_resize_or_reraise(*args, **kwargs):
raise ex
_reschedule_resize_or_reraise.side_effect = (
fake_reschedule_resize_or_reraise)
with mock.patch.object(self.compute, '_prep_resize', side_effect=ex):
self.assertRaises(
# _error_out_instance_on_exception should reraise the
# UnableToMigrateToSelf inside InstanceFaultRollback.
exception.UnableToMigrateToSelf, self.compute.prep_resize,
self.context, instance.image_meta, instance, instance.flavor,
request_spec, filter_properties={}, node=instance.node,
clean_shutdown=True, migration=migration, host_list=[])
# The instance.vm_state should remain unchanged
# (_error_out_instance_on_exception will set to ACTIVE by default).
self.assertEqual(vm_states.STOPPED, instance.vm_state)
def test_get_updated_nw_info_with_pci_mapping(self):
old_dev = objects.PciDevice(address='0000:04:00.2')
new_dev = objects.PciDevice(address='0000:05:00.3')

View File

@@ -132,6 +132,9 @@ def fake_instance_obj(context, obj_instance_class=None, **updates):
inst.vcpus = flavor.vcpus
if 'memory_mb' in flavor and 'memory_mb' not in updates:
inst.memory_mb = flavor.memory_mb
if ('instance_type_id' not in inst or inst.instance_type_id is None
and 'id' in flavor):
inst.instance_type_id = flavor.id
inst.old_flavor = None
inst.new_flavor = None
inst.obj_reset_changes()