Merge "Revert resize: wait for events according to hybrid plug" into stable/rocky
This commit is contained in:
commit
dbe35cc27a
|
@ -4144,6 +4144,49 @@ class ComputeManager(manager.Manager):
|
|||
self.compute_rpcapi.finish_revert_resize(context, instance,
|
||||
migration, migration.source_compute)
|
||||
|
||||
def _finish_revert_resize_network_migrate_finish(self, context, instance,
|
||||
migration):
|
||||
"""Causes port binding to be updated. In some Neutron or port
|
||||
configurations - see NetworkModel.get_bind_time_events() - we
|
||||
expect the vif-plugged event from Neutron immediately and wait for it.
|
||||
The rest of the time, the event is expected further along in the
|
||||
virt driver, so we don't wait here.
|
||||
|
||||
:param context: The request context.
|
||||
:param instance: The instance undergoing the revert resize.
|
||||
:param migration: The Migration object of the resize being reverted.
|
||||
:raises: eventlet.timeout.Timeout or
|
||||
exception.VirtualInterfacePlugException.
|
||||
"""
|
||||
network_info = instance.get_network_info()
|
||||
events = []
|
||||
deadline = CONF.vif_plugging_timeout
|
||||
if deadline and utils.is_neutron() and network_info:
|
||||
events = network_info.get_bind_time_events(migration)
|
||||
if events:
|
||||
LOG.debug('Will wait for bind-time events: %s', events)
|
||||
error_cb = self._neutron_failed_migration_callback
|
||||
try:
|
||||
with self.virtapi.wait_for_instance_event(instance, events,
|
||||
deadline=deadline,
|
||||
error_callback=error_cb):
|
||||
# NOTE(hanrong): we need to change migration.dest_compute to
|
||||
# source host temporarily.
|
||||
# "network_api.migrate_instance_finish" will setup the network
|
||||
# for the instance on the destination host. For revert resize,
|
||||
# the instance will back to the source host, the setup of the
|
||||
# network for instance should be on the source host. So set
|
||||
# the migration.dest_compute to source host at here.
|
||||
with utils.temporary_mutation(
|
||||
migration, dest_compute=migration.source_compute):
|
||||
self.network_api.migrate_instance_finish(context,
|
||||
instance,
|
||||
migration)
|
||||
except eventlet.timeout.Timeout:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error('Timeout waiting for Neutron events: %s', events,
|
||||
instance=instance)
|
||||
|
||||
@wrap_exception()
|
||||
@reverts_task_state
|
||||
@wrap_instance_event(prefix='compute')
|
||||
|
@ -4182,17 +4225,8 @@ class ComputeManager(manager.Manager):
|
|||
|
||||
self.network_api.setup_networks_on_host(context, instance,
|
||||
migration.source_compute)
|
||||
# NOTE(hanrong): we need to change migration.dest_compute to
|
||||
# source host temporarily. "network_api.migrate_instance_finish"
|
||||
# will setup the network for the instance on the destination host.
|
||||
# For revert resize, the instance will back to the source host, the
|
||||
# setup of the network for instance should be on the source host.
|
||||
# So set the migration.dest_compute to source host at here.
|
||||
with utils.temporary_mutation(
|
||||
migration, dest_compute=migration.source_compute):
|
||||
self.network_api.migrate_instance_finish(context,
|
||||
instance,
|
||||
migration)
|
||||
self._finish_revert_resize_network_migrate_finish(
|
||||
context, instance, migration)
|
||||
network_info = self.network_api.get_instance_nw_info(context,
|
||||
instance)
|
||||
|
||||
|
@ -6322,8 +6356,8 @@ class ComputeManager(manager.Manager):
|
|||
return migrate_data
|
||||
|
||||
@staticmethod
|
||||
def _neutron_failed_live_migration_callback(event_name, instance):
|
||||
msg = ('Neutron reported failure during live migration '
|
||||
def _neutron_failed_migration_callback(event_name, instance):
|
||||
msg = ('Neutron reported failure during migration '
|
||||
'with %(event)s for instance %(uuid)s')
|
||||
msg_args = {'event': event_name, 'uuid': instance.uuid}
|
||||
if CONF.vif_plugging_is_fatal:
|
||||
|
@ -6401,7 +6435,7 @@ class ComputeManager(manager.Manager):
|
|||
disk = None
|
||||
|
||||
deadline = CONF.vif_plugging_timeout
|
||||
error_cb = self._neutron_failed_live_migration_callback
|
||||
error_cb = self._neutron_failed_migration_callback
|
||||
# In order to avoid a race with the vif plugging that the virt
|
||||
# driver does on the destination host, we register our events
|
||||
# to wait for before calling pre_live_migration. Then if the
|
||||
|
|
|
@ -456,6 +456,17 @@ class VIF(Model):
|
|||
'ips': ips}
|
||||
return []
|
||||
|
||||
def has_bind_time_event(self, migration):
|
||||
"""Returns whether this VIF's network-vif-plugged external event will
|
||||
be sent by Neutron at "bind-time" - in other words, as soon as the port
|
||||
binding is updated. This is in the context of updating the port binding
|
||||
to a host that already has the instance in a shutoff state - in
|
||||
practice, this means reverting either a cold migration or a
|
||||
non-same-host resize.
|
||||
"""
|
||||
return (self.is_hybrid_plug_enabled() and not
|
||||
migration.is_same_host())
|
||||
|
||||
def is_hybrid_plug_enabled(self):
|
||||
return self['details'].get(VIF_DETAILS_OVS_HYBRID_PLUG, False)
|
||||
|
||||
|
@ -513,6 +524,20 @@ class NetworkInfo(list):
|
|||
def json(self):
|
||||
return jsonutils.dumps(self)
|
||||
|
||||
def get_bind_time_events(self, migration):
|
||||
"""Returns whether any of our VIFs have "bind-time" events. See
|
||||
has_bind_time_event() docstring for more details.
|
||||
"""
|
||||
return [('network-vif-plugged', vif['id'])
|
||||
for vif in self if vif.has_bind_time_event(migration)]
|
||||
|
||||
def get_plug_time_events(self, migration):
|
||||
"""Complementary to get_bind_time_events(), any event that does not
|
||||
fall in that category is a plug-time event.
|
||||
"""
|
||||
return [('network-vif-plugged', vif['id'])
|
||||
for vif in self if not vif.has_bind_time_event(migration)]
|
||||
|
||||
|
||||
class NetworkInfoAsyncWrapper(NetworkInfo):
|
||||
"""Wrapper around NetworkInfo that allows retrieving NetworkInfo
|
||||
|
|
|
@ -176,6 +176,9 @@ class Migration(base.NovaPersistentObject, base.NovaObject,
|
|||
def instance(self, instance):
|
||||
self._cached_instance = instance
|
||||
|
||||
def is_same_host(self):
|
||||
return self.source_compute == self.dest_compute
|
||||
|
||||
|
||||
@base.NovaObjectRegistry.register
|
||||
class MigrationList(base.ObjectListBase, base.NovaObject):
|
||||
|
|
|
@ -5941,7 +5941,9 @@ class ComputeTestCase(BaseTestCase,
|
|||
old_vm_state = vm_states.ACTIVE
|
||||
else:
|
||||
old_vm_state = vm_states.STOPPED
|
||||
params = {'vm_state': old_vm_state}
|
||||
params = {'vm_state': old_vm_state,
|
||||
'info_cache': objects.InstanceInfoCache(
|
||||
network_info=network_model.NetworkInfo([]))}
|
||||
instance = self._create_fake_instance_obj(params)
|
||||
|
||||
self.stub_out('nova.virt.fake.FakeDriver.finish_migration', fake)
|
||||
|
@ -6091,7 +6093,9 @@ class ComputeTestCase(BaseTestCase,
|
|||
def fake(*args, **kwargs):
|
||||
pass
|
||||
|
||||
instance = self._create_fake_instance_obj()
|
||||
params = {'info_cache': objects.InstanceInfoCache(
|
||||
network_info=network_model.NetworkInfo([]))}
|
||||
instance = self._create_fake_instance_obj(params)
|
||||
|
||||
self.stub_out('nova.virt.fake.FakeDriver.finish_migration', fake)
|
||||
self.stub_out('nova.virt.fake.FakeDriver.finish_revert_migration',
|
||||
|
|
|
@ -4936,6 +4936,97 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
|
|||
self.context, fake_instance, fake_bdm)
|
||||
block_stats.assert_called_once_with(fake_instance, 'vda')
|
||||
|
||||
def _test_finish_revert_resize_network_migrate_finish(
|
||||
self, vifs, events, migration=None):
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
instance.info_cache = objects.InstanceInfoCache(
|
||||
network_info=network_model.NetworkInfo(vifs))
|
||||
if migration is None:
|
||||
migration = objects.Migration(
|
||||
source_compute='fake-source',
|
||||
dest_compute='fake-dest')
|
||||
|
||||
def fake_migrate_instance_finish(context, instance, migration):
|
||||
# NOTE(artom) This looks weird, but it's checking that the
|
||||
# temporaty_mutation() context manager did its job.
|
||||
self.assertEqual(migration.dest_compute, migration.source_compute)
|
||||
|
||||
with test.nested(
|
||||
mock.patch.object(self.compute.virtapi,
|
||||
'wait_for_instance_event'),
|
||||
mock.patch.object(self.compute.network_api,
|
||||
'migrate_instance_finish',
|
||||
side_effect=fake_migrate_instance_finish)
|
||||
) as (mock_wait, mock_migrate_instance_finish):
|
||||
self.compute._finish_revert_resize_network_migrate_finish(
|
||||
self.context, instance, migration)
|
||||
mock_wait.assert_called_once_with(
|
||||
instance, events, deadline=CONF.vif_plugging_timeout,
|
||||
error_callback=self.compute._neutron_failed_migration_callback)
|
||||
mock_migrate_instance_finish.assert_called_once_with(
|
||||
self.context, instance, migration)
|
||||
|
||||
def test_finish_revert_resize_network_migrate_finish_wait(self):
|
||||
"""Test that we wait for bind-time events if we have a hybrid-plugged
|
||||
VIF.
|
||||
"""
|
||||
self._test_finish_revert_resize_network_migrate_finish(
|
||||
[network_model.VIF(id=uuids.hybrid_vif,
|
||||
details={'ovs_hybrid_plug': True}),
|
||||
network_model.VIF(id=uuids.normal_vif,
|
||||
details={'ovs_hybrid_plug': False})],
|
||||
[('network-vif-plugged', uuids.hybrid_vif)])
|
||||
|
||||
def test_finish_revert_resize_network_migrate_finish_same_host(self):
|
||||
"""Test that we're not waiting for any events if its a same host
|
||||
resize revert.
|
||||
"""
|
||||
migration = objects.Migration(
|
||||
source_compute='fake-source', dest_compute='fake-source')
|
||||
|
||||
self._test_finish_revert_resize_network_migrate_finish(
|
||||
[network_model.VIF(id=uuids.hybrid_vif,
|
||||
details={'ovs_hybrid_plug': True}),
|
||||
network_model.VIF(id=uuids.normal_vif,
|
||||
details={'ovs_hybrid_plug': False})],
|
||||
[], migration=migration
|
||||
)
|
||||
|
||||
def test_finish_revert_resize_network_migrate_finish_dont_wait(self):
|
||||
"""Test that we're not waiting for any events if we don't have any
|
||||
hybrid-plugged VIFs.
|
||||
"""
|
||||
self._test_finish_revert_resize_network_migrate_finish(
|
||||
[network_model.VIF(id=uuids.hybrid_vif,
|
||||
details={'ovs_hybrid_plug': False}),
|
||||
network_model.VIF(id=uuids.normal_vif,
|
||||
details={'ovs_hybrid_plug': False})],
|
||||
[])
|
||||
|
||||
def test_finish_revert_resize_network_migrate_finish_no_vif_timeout(self):
|
||||
"""Test that we're not waiting for any events if vif_plugging_timeout
|
||||
is 0.
|
||||
"""
|
||||
self.flags(vif_plugging_timeout=0)
|
||||
self._test_finish_revert_resize_network_migrate_finish(
|
||||
[network_model.VIF(id=uuids.hybrid_vif,
|
||||
details={'ovs_hybrid_plug': True}),
|
||||
network_model.VIF(id=uuids.normal_vif,
|
||||
details={'ovs_hybrid_plug': True})],
|
||||
[])
|
||||
|
||||
@mock.patch.object(utils, 'is_neutron', return_value=False)
|
||||
def test_finish_revert_resize_network_migrate_finish_not_neutron(self, _):
|
||||
"""Test that we're not waiting for any events if we're not using
|
||||
Neutron.
|
||||
"""
|
||||
self._test_finish_revert_resize_network_migrate_finish(
|
||||
[network_model.VIF(id=uuids.hybrid_vif,
|
||||
details={'ovs_hybrid_plug': True}),
|
||||
network_model.VIF(id=uuids.normal_vif,
|
||||
details={'ovs_hybrid_plug': True})],
|
||||
[])
|
||||
|
||||
|
||||
class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -18,8 +18,10 @@ from oslo_config import cfg
|
|||
|
||||
from nova import exception
|
||||
from nova.network import model
|
||||
from nova import objects
|
||||
from nova import test
|
||||
from nova.tests.unit import fake_network_cache_model
|
||||
from nova.tests import uuidsentinel as uuids
|
||||
from nova.virt import netutils
|
||||
|
||||
|
||||
|
@ -857,6 +859,34 @@ iface eth1 inet static
|
|||
libvirt_virt_type='lxc')
|
||||
self.assertEqual(expected, template)
|
||||
|
||||
def test_get_events(self):
|
||||
network_info = model.NetworkInfo([
|
||||
model.VIF(
|
||||
id=uuids.hybrid_vif,
|
||||
details={'ovs_hybrid_plug': True}),
|
||||
model.VIF(
|
||||
id=uuids.normal_vif,
|
||||
details={'ovs_hybrid_plug': False})])
|
||||
same_host = objects.Migration(source_compute='fake-host',
|
||||
dest_compute='fake-host')
|
||||
diff_host = objects.Migration(source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
# Same-host migrations will have all events be plug-time.
|
||||
self.assertItemsEqual(
|
||||
[('network-vif-plugged', uuids.normal_vif),
|
||||
('network-vif-plugged', uuids.hybrid_vif)],
|
||||
network_info.get_plug_time_events(same_host))
|
||||
# Same host migration will have no plug-time events.
|
||||
self.assertEqual([], network_info.get_bind_time_events(same_host))
|
||||
# Diff-host migration + OVS hybrid plug = bind-time events
|
||||
self.assertEqual(
|
||||
[('network-vif-plugged', uuids.hybrid_vif)],
|
||||
network_info.get_bind_time_events(diff_host))
|
||||
# Diff-host migration + normal OVS = plug-time events
|
||||
self.assertEqual(
|
||||
[('network-vif-plugged', uuids.normal_vif)],
|
||||
network_info.get_plug_time_events(diff_host))
|
||||
|
||||
|
||||
class TestNetworkMetadata(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -276,6 +276,14 @@ class _TestMigrationObject(object):
|
|||
mig = objects.Migration.get_by_id(self.context, db_mig.id)
|
||||
self.assertEqual(uuid, mig.uuid)
|
||||
|
||||
def test_is_same_host(self):
|
||||
same_host = objects.Migration(source_compute='fake-host',
|
||||
dest_compute='fake-host')
|
||||
diff_host = objects.Migration(source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
self.assertTrue(same_host.is_same_host())
|
||||
self.assertFalse(diff_host.is_same_host())
|
||||
|
||||
|
||||
class TestMigrationObject(test_objects._LocalTest,
|
||||
_TestMigrationObject):
|
||||
|
|
|
@ -16916,8 +16916,9 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
self.assertEqual(0, domain.resume.call_count)
|
||||
|
||||
def _test_create_with_network_events(self, neutron_failure=None,
|
||||
power_on=True):
|
||||
power_on=True, events=None):
|
||||
generated_events = []
|
||||
events_passed_to_prepare = []
|
||||
|
||||
def wait_timeout():
|
||||
event = mock.MagicMock()
|
||||
|
@ -16935,6 +16936,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
m.event_name = '%s-%s' % (name, tag)
|
||||
m.wait.side_effect = wait_timeout
|
||||
generated_events.append(m)
|
||||
events_passed_to_prepare.append((name, tag))
|
||||
return m
|
||||
|
||||
virtapi = manager.ComputeVirtAPI(mock.MagicMock())
|
||||
|
@ -16954,7 +16956,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
def test_create(cleanup, create, fw_driver, plug_vifs):
|
||||
domain = drvr._create_domain_and_network(self.context, 'xml',
|
||||
instance, vifs,
|
||||
power_on=power_on)
|
||||
power_on=power_on,
|
||||
external_events=events)
|
||||
plug_vifs.assert_called_with(instance, vifs)
|
||||
|
||||
pause = self._get_pause_flag(drvr, vifs, power_on=power_on)
|
||||
|
@ -16969,7 +16972,9 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
|
||||
test_create()
|
||||
|
||||
if utils.is_neutron() and CONF.vif_plugging_timeout and power_on:
|
||||
if events and utils.is_neutron() and CONF.vif_plugging_timeout:
|
||||
self.assertEqual(events_passed_to_prepare, events)
|
||||
elif utils.is_neutron() and CONF.vif_plugging_timeout and power_on:
|
||||
prepare.assert_has_calls([
|
||||
mock.call(instance, 'network-vif-plugged', uuids.vif_1),
|
||||
mock.call(instance, 'network-vif-plugged', uuids.vif_2)])
|
||||
|
@ -16982,6 +16987,22 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
else:
|
||||
self.assertEqual(0, prepare.call_count)
|
||||
|
||||
@mock.patch('nova.utils.is_neutron', new=mock.Mock(return_value=True))
|
||||
def test_create_with_network_events_passed_in(self):
|
||||
self._test_create_with_network_events(
|
||||
events=[('network-vif-plugged', uuids.fake_vif)])
|
||||
|
||||
@mock.patch('nova.utils.is_neutron', new=mock.Mock(return_value=False))
|
||||
def test_create_with_network_events_passed_in_nova_net(self):
|
||||
self._test_create_with_network_events(
|
||||
events=[('network-vif-plugged', uuids.fake_vif)])
|
||||
|
||||
@mock.patch('nova.utils.is_neutron', new=mock.Mock(return_value=True))
|
||||
def test_create_with_network_events_passed_in_0_timeout(self):
|
||||
self.flags(vif_plugging_timeout=0)
|
||||
self._test_create_with_network_events(
|
||||
events=[('network-vif-plugged', uuids.fake_vif)])
|
||||
|
||||
@mock.patch('nova.utils.is_neutron', return_value=True)
|
||||
def test_create_with_network_events_neutron(self, is_neutron):
|
||||
self._test_create_with_network_events()
|
||||
|
@ -18926,7 +18947,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
def test_finish_migration_power_off(self):
|
||||
self._test_finish_migration(power_on=False)
|
||||
|
||||
def _test_finish_revert_migration(self, power_on):
|
||||
def _test_finish_revert_migration(self, power_on, migration):
|
||||
"""Test for nova.virt.libvirt.libvirt_driver.LivirtConnection
|
||||
.finish_revert_migration.
|
||||
"""
|
||||
|
@ -18942,10 +18963,13 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
|
||||
def fake_create_domain(context, xml, instance, network_info,
|
||||
block_device_info=None, power_on=None,
|
||||
vifs_already_plugged=None):
|
||||
vifs_already_plugged=None,
|
||||
external_events=None):
|
||||
self.fake_create_domain_called = True
|
||||
self.assertEqual(powered_on, power_on)
|
||||
self.assertFalse(vifs_already_plugged)
|
||||
self.assertEqual(self.events_passed_to_fake_create,
|
||||
external_events)
|
||||
return mock.MagicMock()
|
||||
|
||||
def fake_enable_hairpin():
|
||||
|
@ -18979,6 +19003,8 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
ins_ref = self._create_instance()
|
||||
ins_ref.migration_context = objects.MigrationContext(
|
||||
migration_id=migration.id)
|
||||
os.mkdir(os.path.join(tmpdir, ins_ref['name']))
|
||||
libvirt_xml_path = os.path.join(tmpdir,
|
||||
ins_ref['name'],
|
||||
|
@ -18986,16 +19012,50 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
f = open(libvirt_xml_path, 'w')
|
||||
f.close()
|
||||
|
||||
self.drvr.finish_revert_migration(
|
||||
context.get_admin_context(), ins_ref,
|
||||
[], None, power_on)
|
||||
network_info = network_model.NetworkInfo(
|
||||
[network_model.VIF(id=uuids.normal_vif),
|
||||
network_model.VIF(id=uuids.hybrid_vif,
|
||||
details={'ovs_hybrid_plug': True})])
|
||||
if migration.is_same_host():
|
||||
# Same host is all plug-time
|
||||
self.events_passed_to_fake_create = [
|
||||
('network-vif-plugged', uuids.normal_vif),
|
||||
('network-vif-plugged', uuids.hybrid_vif)]
|
||||
else:
|
||||
# For different host migration only non-hybrid plug
|
||||
# ("normal") VIFs "emit" plug-time events.
|
||||
self.events_passed_to_fake_create = [
|
||||
('network-vif-plugged', uuids.normal_vif)]
|
||||
|
||||
with mock.patch.object(objects.Migration, 'get_by_id_and_instance',
|
||||
return_value=migration) as mock_get_mig:
|
||||
self.drvr.finish_revert_migration(
|
||||
context.get_admin_context(), ins_ref,
|
||||
network_info, None, power_on)
|
||||
mock_get_mig.assert_called_with(mock.ANY, migration.id,
|
||||
ins_ref.uuid)
|
||||
|
||||
self.assertTrue(self.fake_create_domain_called)
|
||||
|
||||
def test_finish_revert_migration_power_on(self):
|
||||
self._test_finish_revert_migration(True)
|
||||
migration = objects.Migration(id=42, source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
self._test_finish_revert_migration(power_on=True, migration=migration)
|
||||
|
||||
def test_finish_revert_migration_power_off(self):
|
||||
self._test_finish_revert_migration(False)
|
||||
migration = objects.Migration(id=42, source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
self._test_finish_revert_migration(power_on=False, migration=migration)
|
||||
|
||||
def test_finish_revert_migration_same_host(self):
|
||||
migration = objects.Migration(id=42, source_compute='fake-host',
|
||||
dest_compute='fake-host')
|
||||
self._test_finish_revert_migration(power_on=True, migration=migration)
|
||||
|
||||
def test_finish_revert_migration_diff_host(self):
|
||||
migration = objects.Migration(id=42, source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
self._test_finish_revert_migration(power_on=True, migration=migration)
|
||||
|
||||
def _test_finish_revert_migration_after_crash(self, backup_made=True,
|
||||
del_inst_failed=False):
|
||||
|
@ -19005,6 +19065,10 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
drvr.image_backend.by_name.return_value = drvr.image_backend
|
||||
context = 'fake_context'
|
||||
ins_ref = self._create_instance()
|
||||
ins_ref.migration_context = objects.MigrationContext(
|
||||
migration_id=42)
|
||||
migration = objects.Migration(source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
|
||||
with test.nested(
|
||||
mock.patch.object(os.path, 'exists', return_value=backup_made),
|
||||
|
@ -19014,13 +19078,17 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
mock.patch.object(drvr, '_get_guest_xml'),
|
||||
mock.patch.object(shutil, 'rmtree'),
|
||||
mock.patch.object(loopingcall, 'FixedIntervalLoopingCall'),
|
||||
mock.patch.object(objects.Migration, 'get_by_id_and_instance',
|
||||
return_value=migration)
|
||||
) as (mock_stat, mock_path, mock_rename, mock_cdn, mock_ggx,
|
||||
mock_rmtree, mock_looping_call):
|
||||
mock_rmtree, mock_looping_call, mock_get_mig):
|
||||
mock_path.return_value = '/fake/foo'
|
||||
if del_inst_failed:
|
||||
mock_rmtree.side_effect = OSError(errno.ENOENT,
|
||||
'test exception')
|
||||
drvr.finish_revert_migration(context, ins_ref, [])
|
||||
drvr.finish_revert_migration(context, ins_ref,
|
||||
network_model.NetworkInfo())
|
||||
mock_get_mig.assert_called_with(mock.ANY, 42, ins_ref.uuid)
|
||||
if backup_made:
|
||||
mock_rename.assert_called_once_with('/fake/foo_resize',
|
||||
'/fake/foo')
|
||||
|
@ -19049,6 +19117,10 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
image_meta = {"disk_format": "raw",
|
||||
"properties": {"hw_disk_bus": "ide"}}
|
||||
instance = self._create_instance()
|
||||
instance.migration_context = objects.MigrationContext(
|
||||
migration_id=42)
|
||||
migration = objects.Migration(source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
|
||||
|
@ -19058,22 +19130,37 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
mock.patch.object(utils, 'get_image_from_system_metadata',
|
||||
return_value=image_meta),
|
||||
mock.patch.object(drvr, '_get_guest_xml',
|
||||
side_effect=fake_get_guest_xml)):
|
||||
drvr.finish_revert_migration('', instance, None, power_on=False)
|
||||
side_effect=fake_get_guest_xml),
|
||||
mock.patch.object(objects.Migration, 'get_by_id_and_instance',
|
||||
return_value=migration)
|
||||
) as (mock_img_bkend, mock_cdan, mock_gifsm, mock_ggxml, mock_get_mig):
|
||||
drvr.finish_revert_migration('', instance,
|
||||
network_model.NetworkInfo(),
|
||||
power_on=False)
|
||||
mock_get_mig.assert_called_with(mock.ANY, 42, instance.uuid)
|
||||
|
||||
def test_finish_revert_migration_snap_backend(self):
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
drvr.image_backend = mock.Mock()
|
||||
drvr.image_backend.by_name.return_value = drvr.image_backend
|
||||
ins_ref = self._create_instance()
|
||||
ins_ref.migration_context = objects.MigrationContext(
|
||||
migration_id=42)
|
||||
migration = objects.Migration(source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
|
||||
with test.nested(
|
||||
mock.patch.object(utils, 'get_image_from_system_metadata'),
|
||||
mock.patch.object(drvr, '_create_domain_and_network'),
|
||||
mock.patch.object(drvr, '_get_guest_xml')) as (
|
||||
mock_image, mock_cdn, mock_ggx):
|
||||
mock.patch.object(drvr, '_get_guest_xml'),
|
||||
mock.patch.object(objects.Migration, 'get_by_id_and_instance',
|
||||
return_value=migration)) as (
|
||||
mock_image, mock_cdn, mock_ggx, mock_get_mig):
|
||||
mock_image.return_value = {'disk_format': 'raw'}
|
||||
drvr.finish_revert_migration('', ins_ref, None, power_on=False)
|
||||
drvr.finish_revert_migration('', ins_ref,
|
||||
network_model.NetworkInfo(),
|
||||
power_on=False)
|
||||
mock_get_mig.assert_called_with(mock.ANY, 42, ins_ref.uuid)
|
||||
|
||||
drvr.image_backend.rollback_to_snap.assert_called_once_with(
|
||||
libvirt_utils.RESIZE_SNAPSHOT_NAME)
|
||||
|
@ -19105,17 +19192,26 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
drvr.image_backend.by_name.return_value = drvr.image_backend
|
||||
drvr.image_backend.exists.return_value = False
|
||||
ins_ref = self._create_instance()
|
||||
ins_ref.migration_context = objects.MigrationContext(
|
||||
migration_id=42)
|
||||
migration = objects.Migration(source_compute='fake-host1',
|
||||
dest_compute='fake-host2')
|
||||
|
||||
with test.nested(
|
||||
mock.patch.object(rbd_utils, 'RBDDriver'),
|
||||
mock.patch.object(utils, 'get_image_from_system_metadata'),
|
||||
mock.patch.object(drvr, '_create_domain_and_network'),
|
||||
mock.patch.object(drvr, '_get_guest_xml')) as (
|
||||
mock_rbd, mock_image, mock_cdn, mock_ggx):
|
||||
mock.patch.object(drvr, '_get_guest_xml'),
|
||||
mock.patch.object(objects.Migration, 'get_by_id_and_instance',
|
||||
return_value=migration)) as (
|
||||
mock_rbd, mock_image, mock_cdn, mock_ggx, mock_get_mig):
|
||||
mock_image.return_value = {'disk_format': 'raw'}
|
||||
drvr.finish_revert_migration('', ins_ref, None, power_on=False)
|
||||
drvr.finish_revert_migration('', ins_ref,
|
||||
network_model.NetworkInfo(),
|
||||
power_on=False)
|
||||
self.assertFalse(drvr.image_backend.rollback_to_snap.called)
|
||||
self.assertFalse(drvr.image_backend.remove_snap.called)
|
||||
mock_get_mig.assert_called_with(mock.ANY, 42, ins_ref.uuid)
|
||||
|
||||
def test_cleanup_failed_migration(self):
|
||||
self.mox.StubOutWithMock(shutil, 'rmtree')
|
||||
|
|
|
@ -5639,14 +5639,15 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
block_device_info=None, power_on=True,
|
||||
vifs_already_plugged=False,
|
||||
post_xml_callback=None,
|
||||
destroy_disks_on_failure=False):
|
||||
destroy_disks_on_failure=False,
|
||||
external_events=None):
|
||||
|
||||
"""Do required network setup and create domain."""
|
||||
timeout = CONF.vif_plugging_timeout
|
||||
if (self._conn_supports_start_paused and
|
||||
utils.is_neutron() and not
|
||||
vifs_already_plugged and power_on and timeout):
|
||||
events = self._get_neutron_events(network_info)
|
||||
if (self._conn_supports_start_paused and utils.is_neutron() and not
|
||||
vifs_already_plugged and power_on and timeout):
|
||||
events = (external_events if external_events
|
||||
else self._get_neutron_events(network_info))
|
||||
else:
|
||||
events = []
|
||||
|
||||
|
@ -8542,9 +8543,24 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
xml = self._get_guest_xml(context, instance, network_info, disk_info,
|
||||
instance.image_meta,
|
||||
block_device_info=block_device_info)
|
||||
self._create_domain_and_network(context, xml, instance, network_info,
|
||||
block_device_info=block_device_info,
|
||||
power_on=power_on)
|
||||
# NOTE(artom) In some Neutron or port configurations we've already
|
||||
# waited for vif-plugged events in the compute manager's
|
||||
# _finish_revert_resize_network_migrate_finish(), right after updating
|
||||
# the port binding. For any ports not covered by those "bind-time"
|
||||
# events, we wait for "plug-time" events here.
|
||||
# TODO(artom) This DB lookup is done for backportability. A subsequent
|
||||
# patch will remove it and change the finish_revert_migration() method
|
||||
# signature to pass is the migration object.
|
||||
migration = objects.Migration.get_by_id_and_instance(
|
||||
context, instance.migration_context.migration_id, instance.uuid)
|
||||
events = network_info.get_plug_time_events(migration)
|
||||
if events:
|
||||
LOG.debug('Instance is using plug-time events: %s', events,
|
||||
instance=instance)
|
||||
self._create_domain_and_network(
|
||||
context, xml, instance, network_info,
|
||||
block_device_info=block_device_info, power_on=power_on,
|
||||
external_events=events)
|
||||
|
||||
if power_on:
|
||||
timer = loopingcall.FixedIntervalLoopingCall(
|
||||
|
|
Loading…
Reference in New Issue