Merge "libvirt: Provide VIR_MIGRATE_PARAM_PERSIST_XML during live migration" into stable/rocky

This commit is contained in:
Zuul 2020-09-03 15:15:47 +00:00 committed by Gerrit Code Review
commit 0d1fd02b30
4 changed files with 105 additions and 9 deletions

View File

@ -9736,6 +9736,76 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'instance', data, block_device_info=bdi)) 'instance', data, block_device_info=bdi))
self.assertEqual(0, mock_get_instance_disk_info.call_count) self.assertEqual(0, mock_get_instance_disk_info.call_count)
@mock.patch.object(fakelibvirt.virDomain, "migrateToURI3")
@mock.patch('nova.virt.libvirt.migration.get_updated_guest_xml')
@mock.patch.object(fakelibvirt.Connection, 'getLibVersion')
def test_live_migration_persistent_xml(
self, mock_get_version, mock_get_updated_xml, mock_migrateToURI3):
"""Assert that persistent_xml only provided when libvirt is >= v1.3.4
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
instance = self.test_instance
dest = '127.0.0.1'
block_migration = False
migrate_data = objects.LibvirtLiveMigrateData(
graphics_listen_addr_vnc='10.0.0.1',
graphics_listen_addr_spice='10.0.0.2',
serial_listen_addr='127.0.0.1',
target_connect_addr='127.0.0.1',
bdms=[],
block_migration=block_migration)
guest = libvirt_guest.Guest(fakelibvirt.virDomain)
device_names = ['vda']
mock_get_updated_xml.return_value = mock.sentinel.dest_xml
# persistent_xml was introduced in v1.3.4 so provide v1.3.3
v1_3_3 = versionutils.convert_version_to_int((1, 3, 3))
mock_get_version.return_value = v1_3_3
drvr._live_migration_operation(
self.context, instance, dest, block_migration, migrate_data,
guest, device_names)
expected_uri = drvr._live_migration_uri(dest)
expected_flags = 0
expected_params = {
'bandwidth': 0,
'destination_xml': mock.sentinel.dest_xml,
'migrate_disks': device_names,
'migrate_uri': 'tcp://127.0.0.1'
}
# Assert that migrateToURI3 is called without the persistent_xml param
mock_get_version.assert_called()
mock_migrateToURI3.assert_called_once_with(
expected_uri, params=expected_params, flags=expected_flags)
# reset mocks and try again with v1.3.4
mock_get_version.reset_mock()
mock_migrateToURI3.reset_mock()
# persistent_xml was introduced in v1.3.4 so provide it this time
v1_3_4 = versionutils.convert_version_to_int((1, 3, 4))
mock_get_version.return_value = v1_3_4
drvr._live_migration_operation(
self.context, instance, dest,
block_migration, migrate_data, guest, device_names)
expected_params = {
'bandwidth': 0,
'destination_xml': mock.sentinel.dest_xml,
'persistent_xml': mock.sentinel.dest_xml,
'migrate_disks': device_names,
'migrate_uri': 'tcp://127.0.0.1'
}
# Assert that migrateToURI3 is called with the persistent_xml param
mock_get_version.assert_called()
mock_migrateToURI3.assert_called_once_with(
expected_uri, params=expected_params, flags=expected_flags)
@mock.patch.object(host.Host, 'has_min_version', return_value=True) @mock.patch.object(host.Host, 'has_min_version', return_value=True)
@mock.patch.object(fakelibvirt.virDomain, "migrateToURI3") @mock.patch.object(fakelibvirt.virDomain, "migrateToURI3")
@mock.patch.object(fakelibvirt.virDomain, "XMLDesc") @mock.patch.object(fakelibvirt.virDomain, "XMLDesc")
@ -9778,6 +9848,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'migrate_disks': disk_paths, 'migrate_disks': disk_paths,
'bandwidth': _bandwidth, 'bandwidth': _bandwidth,
'destination_xml': target_xml, 'destination_xml': target_xml,
'persistent_xml': target_xml,
} }
# start test # start test
@ -9885,7 +9956,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'migrate_disks': disk_paths, 'migrate_disks': disk_paths,
'migrate_uri': 'tcp://127.0.0.2', 'migrate_uri': 'tcp://127.0.0.2',
'bandwidth': CONF.libvirt.live_migration_bandwidth, 'bandwidth': CONF.libvirt.live_migration_bandwidth,
'destination_xml': target_xml 'destination_xml': target_xml,
} }
# Start test # Start test
@ -9985,6 +10056,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'migrate_uri': 'tcp://127.0.0.2', 'migrate_uri': 'tcp://127.0.0.2',
'bandwidth': CONF.libvirt.live_migration_bandwidth, 'bandwidth': CONF.libvirt.live_migration_bandwidth,
'destination_xml': target_xml, 'destination_xml': target_xml,
'persistent_xml': target_xml,
} }
# start test # start test
@ -10335,6 +10407,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'migrate_disks': ['vda', 'vdb'], 'migrate_disks': ['vda', 'vdb'],
'bandwidth': CONF.libvirt.live_migration_bandwidth, 'bandwidth': CONF.libvirt.live_migration_bandwidth,
'destination_xml': target_xml, 'destination_xml': target_xml,
'persistent_xml': target_xml,
} }
# start test # start test
@ -10388,14 +10461,14 @@ class LibvirtConnTestCase(test.NoDBTestCase,
@mock.patch.object(host.Host, 'has_min_version', return_value=True) @mock.patch.object(host.Host, 'has_min_version', return_value=True)
@mock.patch.object(fakelibvirt.virDomain, "migrateToURI3") @mock.patch.object(fakelibvirt.virDomain, "migrateToURI3")
@mock.patch('nova.virt.libvirt.migration.get_updated_guest_xml', @mock.patch('nova.virt.libvirt.migration.get_updated_guest_xml')
return_value='')
@mock.patch('nova.virt.libvirt.guest.Guest.get_xml_desc', @mock.patch('nova.virt.libvirt.guest.Guest.get_xml_desc',
return_value='<xml></xml>') return_value='<xml></xml>')
def test_live_migration_uses_migrateToURI3( def test_live_migration_uses_migrateToURI3(
self, mock_old_xml, mock_new_xml, mock_migrateToURI3, self, mock_old_xml, mock_new_xml, mock_migrateToURI3,
mock_min_version): mock_min_version):
mock_new_xml.return_value = mock.sentinel.new_xml
target_connection = '127.0.0.2' target_connection = '127.0.0.2'
# Preparing mocks # Preparing mocks
disk_paths = ['vda', 'vdb'] disk_paths = ['vda', 'vdb']
@ -10403,6 +10476,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'migrate_uri': 'tcp://127.0.0.2', 'migrate_uri': 'tcp://127.0.0.2',
'migrate_disks': ['vda', 'vdb'], 'migrate_disks': ['vda', 'vdb'],
'bandwidth': CONF.libvirt.live_migration_bandwidth, 'bandwidth': CONF.libvirt.live_migration_bandwidth,
'destination_xml': mock.sentinel.new_xml,
'persistent_xml': mock.sentinel.new_xml,
} }
mock_migrateToURI3.side_effect = fakelibvirt.libvirtError("ERR") mock_migrateToURI3.side_effect = fakelibvirt.libvirtError("ERR")
@ -10461,6 +10536,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'migrate_disks': device_names, 'migrate_disks': device_names,
'bandwidth': CONF.libvirt.live_migration_bandwidth, 'bandwidth': CONF.libvirt.live_migration_bandwidth,
'destination_xml': '<xml/>', 'destination_xml': '<xml/>',
'persistent_xml': '<xml/>',
} }
if not params['migrate_disks']: if not params['migrate_disks']:
del params['migrate_disks'] del params['migrate_disks']
@ -10492,14 +10568,14 @@ class LibvirtConnTestCase(test.NoDBTestCase,
@mock.patch.object(host.Host, 'has_min_version', return_value=True) @mock.patch.object(host.Host, 'has_min_version', return_value=True)
@mock.patch.object(fakelibvirt.virDomain, "migrateToURI3") @mock.patch.object(fakelibvirt.virDomain, "migrateToURI3")
@mock.patch('nova.virt.libvirt.migration.get_updated_guest_xml', @mock.patch('nova.virt.libvirt.migration.get_updated_guest_xml')
return_value='')
@mock.patch('nova.virt.libvirt.guest.Guest.get_xml_desc', return_value='') @mock.patch('nova.virt.libvirt.guest.Guest.get_xml_desc', return_value='')
def test_block_live_migration_tunnelled_migrateToURI3( def test_block_live_migration_tunnelled_migrateToURI3(
self, mock_old_xml, mock_new_xml, self, mock_old_xml, mock_new_xml,
mock_migrateToURI3, mock_min_version): mock_migrateToURI3, mock_min_version):
self.flags(live_migration_tunnelled=True, group='libvirt') self.flags(live_migration_tunnelled=True, group='libvirt')
mock_new_xml.return_value = mock.sentinel.new_xml
target_connection = None target_connection = None
device_names = ['disk1', 'disk2'] device_names = ['disk1', 'disk2']
@ -10507,7 +10583,9 @@ class LibvirtConnTestCase(test.NoDBTestCase,
# Since we are passing the VIR_MIGRATE_TUNNELLED flag, the # Since we are passing the VIR_MIGRATE_TUNNELLED flag, the
# 'parms' dict will not (as expected) contain 'migrate_disks' # 'parms' dict will not (as expected) contain 'migrate_disks'
params = { params = {
'bandwidth': CONF.libvirt.live_migration_bandwidth 'bandwidth': CONF.libvirt.live_migration_bandwidth,
'destination_xml': mock.sentinel.new_xml,
'persistent_xml': mock.sentinel.new_xml,
} }
# Start test # Start test
migrate_data = objects.LibvirtLiveMigrateData( migrate_data = objects.LibvirtLiveMigrateData(
@ -10554,6 +10632,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'migrate_disks': disk_paths, 'migrate_disks': disk_paths,
'bandwidth': CONF.libvirt.live_migration_bandwidth, 'bandwidth': CONF.libvirt.live_migration_bandwidth,
'destination_xml': '<xml/>', 'destination_xml': '<xml/>',
'persistent_xml': '<xml/>',
} }
# Prepare mocks # Prepare mocks

View File

@ -135,7 +135,7 @@ class _FakeDriverBackendTestCase(object):
self.stub_out('nova.virt.libvirt.guest.Guest.migrate', self.stub_out('nova.virt.libvirt.guest.Guest.migrate',
lambda self, destination, migrate_uri=None, lambda self, destination, migrate_uri=None,
migrate_disks=None, destination_xml=None, flags=0, migrate_disks=None, destination_xml=None, flags=0,
bandwidth=0: None) bandwidth=0, persistent_xml_param=False: None)
# We can't actually make a config drive v2 because ensure_tree has # We can't actually make a config drive v2 because ensure_tree has
# been faked out # been faked out
self.stub_out('nova.virt.configdrive.ConfigDriveBuilder.make_drive', self.stub_out('nova.virt.configdrive.ConfigDriveBuilder.make_drive',

View File

@ -301,6 +301,11 @@ MIN_LIBVIRT_BETTER_SIGKILL_HANDLING = (4, 7, 0)
VGPU_RESOURCE_SEMAPHORE = "vgpu_resources" VGPU_RESOURCE_SEMAPHORE = "vgpu_resources"
# libvirt >= v1.3.4 introduced VIR_MIGRATE_PARAM_PERSIST_XML that needs to be
# provided when the VIR_MIGRATE_PERSIST_DEST flag is used to ensure the updated
# domain XML is persisted on the destination.
MIN_LIBVIRT_MIGRATE_PARAM_PERSIST_XML = (1, 3, 4)
class LibvirtDriver(driver.ComputeDriver): class LibvirtDriver(driver.ComputeDriver):
capabilities = { capabilities = {
@ -7279,13 +7284,18 @@ class LibvirtDriver(driver.ComputeDriver):
if CONF.serial_console.enabled: if CONF.serial_console.enabled:
serial_ports = list(self._get_serial_ports_from_guest(guest)) serial_ports = list(self._get_serial_ports_from_guest(guest))
# NOTE(lyarwood): Only available from v1.3.4
persistent_xml_param = self._host.has_min_version(
MIN_LIBVIRT_MIGRATE_PARAM_PERSIST_XML)
LOG.debug("About to invoke the migrate API", instance=instance) LOG.debug("About to invoke the migrate API", instance=instance)
guest.migrate(self._live_migration_uri(dest), guest.migrate(self._live_migration_uri(dest),
migrate_uri=migrate_uri, migrate_uri=migrate_uri,
flags=migration_flags, flags=migration_flags,
migrate_disks=device_names, migrate_disks=device_names,
destination_xml=new_xml_str, destination_xml=new_xml_str,
bandwidth=CONF.libvirt.live_migration_bandwidth) bandwidth=CONF.libvirt.live_migration_bandwidth,
persistent_xml_param=persistent_xml_param)
LOG.debug("Migrate API has completed", instance=instance) LOG.debug("Migrate API has completed", instance=instance)
for hostname, port in serial_ports: for hostname, port in serial_ports:

View File

@ -610,7 +610,8 @@ class Guest(object):
self._domain.suspend() self._domain.suspend()
def migrate(self, destination, migrate_uri=None, migrate_disks=None, def migrate(self, destination, migrate_uri=None, migrate_disks=None,
destination_xml=None, flags=0, bandwidth=0): destination_xml=None, flags=0, bandwidth=0,
persistent_xml_param=False):
"""Migrate guest object from its current host to the destination """Migrate guest object from its current host to the destination
:param destination: URI of host destination where guest will be migrate :param destination: URI of host destination where guest will be migrate
@ -645,6 +646,9 @@ class Guest(object):
unsafe. unsafe.
VIR_MIGRATE_OFFLINE Migrate offline VIR_MIGRATE_OFFLINE Migrate offline
:param bandwidth: The maximum bandwidth in MiB/s :param bandwidth: The maximum bandwidth in MiB/s
:param persistent_xml_param: Boolean indicating if the
VIR_MIGRATE_PARAM_PERSIST_XML param should
be provided to migrateToURI3.
""" """
params = {} params = {}
# In migrateToURI3 these parameters are extracted from the # In migrateToURI3 these parameters are extracted from the
@ -653,6 +657,9 @@ class Guest(object):
if destination_xml: if destination_xml:
params['destination_xml'] = destination_xml params['destination_xml'] = destination_xml
# NOTE(lyarwood): Only available from v1.3.4
if persistent_xml_param:
params['persistent_xml'] = destination_xml
if migrate_disks: if migrate_disks:
params['migrate_disks'] = migrate_disks params['migrate_disks'] = migrate_disks
if migrate_uri: if migrate_uri: