libvirt: make live migration possible with Virtuozzo

Live migration for Libvirt vz driver works the same
way as for qemu. However some migration capabilities
are supported differently:
* Virtuozzo containers doesn't use backing file, so
we shouldn't ensure it exists in pre live migration.
* migrate_disks parameter doesn't make sense for
Virtuozzo, as backend determines whether specific
block device should be migrated or not.
* Passing new domain xml to migration method is not
supported.

Implements: blueprint live-migration-vz-driver
Change-Id: I89ecdef13ad47800abc8a5158f8834e46750b9ea
Signed-off-by: Pavel Gluschak <pglushchak@virtuozzo.com>
This commit is contained in:
Pavel Gluschak 2016-08-11 14:12:30 +03:00 committed by Matt Riedemann
parent 38a43e56dd
commit d8d813800c
4 changed files with 88 additions and 11 deletions

View File

@ -313,8 +313,8 @@ driver-impl-vmware=missing
driver-notes-vmware=https://bugs.launchpad.net/nova/+bug/1192192
driver-impl-hyperv=complete
driver-impl-ironic=missing
driver-impl-libvirt-vz-vm=missing
driver-impl-libvirt-vz-ct=missing
driver-impl-libvirt-vz-vm=complete
driver-impl-libvirt-vz-ct=complete
[operation.force-live-migration-to-complete]
title=Force live migration to complete

View File

@ -7638,6 +7638,60 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.context, instance_ref, 'dest',
False, migrate_data, guest, [])
def test_live_migration_parallels_no_new_xml(self):
self.flags(virt_type='parallels', group='libvirt')
self.flags(enabled=False, group='vnc')
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI())
instance_dict = dict(self.test_instance)
instance_dict.update({'host': 'fake',
'power_state': power_state.RUNNING,
'vm_state': vm_states.ACTIVE})
instance = objects.Instance(**instance_dict)
migrate_data = objects.LibvirtLiveMigrateData(
block_migration=False)
dom_mock = mock.MagicMock()
guest = libvirt_guest.Guest(dom_mock)
drvr._live_migration_operation(self.context, instance, 'dest',
False, migrate_data, guest, [])
# when new xml is not passed we fall back to migrateToURI
dom_mock.migrateToURI.assert_called_once_with(
drvr._live_migration_uri('dest'),
flags=0, bandwidth=0)
@mock.patch.object(utils, 'spawn')
@mock.patch.object(host.Host, 'get_guest')
@mock.patch.object(fakelibvirt.Connection, '_mark_running')
@mock.patch.object(libvirt_driver.LibvirtDriver,
'_live_migration_monitor')
@mock.patch.object(libvirt_driver.LibvirtDriver,
'_live_migration_copy_disk_paths')
def test_live_migration_parallels_no_migrate_disks(self,
mock_copy_disk_paths,
mock_monitor,
mock_running,
mock_guest,
mock_thread):
self.flags(virt_type='parallels', group='libvirt')
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI())
instance_dict = dict(self.test_instance)
instance_dict.update({'host': 'fake',
'power_state': power_state.RUNNING,
'vm_state': vm_states.ACTIVE})
instance = objects.Instance(**instance_dict)
migrate_data = objects.LibvirtLiveMigrateData(
block_migration=True)
dom = fakelibvirt.Domain(drvr._get_connection(), '<domain/>', True)
guest = libvirt_guest.Guest(dom)
mock_guest.return_value = guest
drvr._live_migration(self.context, instance, 'dest',
lambda: None, lambda: None, True,
migrate_data)
self.assertFalse(mock_copy_disk_paths.called)
mock_thread.assert_called_once_with(
drvr._live_migration_operation,
self.context, instance, 'dest', True,
migrate_data, guest, [])
def test_live_migration_update_volume_xml(self):
self.compute = manager.ComputeManager()
instance_dict = dict(self.test_instance)
@ -7798,9 +7852,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
('xen', 'xenmigr://%s/system'),
('kvm', 'qemu+tcp://%s/system'),
('qemu', 'qemu+tcp://%s/system'),
('parallels', 'parallels+tcp://%s/system'),
# anything else will return None
('lxc', None),
('parallels', None),
)
dest = 'destination'
for hyperv, uri in hypervisor_uri_map:
@ -9420,6 +9474,17 @@ class LibvirtConnTestCase(test.NoDBTestCase):
# Assert that we did nothing
self.assertEqual({}, fake_backend.created_disks)
@mock.patch.object(libvirt_driver.LibvirtDriver,
'_fetch_instance_kernel_ramdisk')
def test_create_images_and_backing_parallels(self, mock_fetch):
self.flags(virt_type='parallels', group='libvirt')
instance = objects.Instance(**self.test_instance)
instance.vm_mode = fields.VMMode.EXE
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI())
drvr._create_images_and_backing(self.context, instance,
'/fake/instance/dir', None)
self.assertFalse(mock_fetch.called)
def _generate_target_ret(self, target_connect_addr=None):
target_ret = {
'graphics_listen_addrs': {'spice': '127.0.0.1', 'vnc': '127.0.0.1'},

View File

@ -681,12 +681,11 @@ class LibvirtDriver(driver.ComputeDriver):
@staticmethod
def _live_migration_uri(dest):
# Only Xen and QEMU support live migration, see
# https://libvirt.org/migration.html#scenarios for reference
uris = {
'kvm': 'qemu+tcp://%s/system',
'qemu': 'qemu+tcp://%s/system',
'xen': 'xenmigr://%s/system',
'parallels': 'parallels+tcp://%s/system',
}
virt_type = CONF.libvirt.virt_type
uri = CONF.libvirt.live_migration_uri or uris.get(virt_type)
@ -6036,11 +6035,13 @@ class LibvirtDriver(driver.ComputeDriver):
migrate_uri = self._migrate_uri(dest)
params = None
new_xml_str = libvirt_migrate.get_updated_guest_xml(
# TODO(sahid): It's not a really good idea to pass
# the method _get_volume_config and we should to find
# a way to avoid this in future.
guest, migrate_data, self._get_volume_config)
new_xml_str = None
if CONF.libvirt.virt_type != "parallels":
new_xml_str = libvirt_migrate.get_updated_guest_xml(
# TODO(sahid): It's not a really good idea to pass
# the method _get_volume_config and we should to find
# a way to avoid this in future.
guest, migrate_data, self._get_volume_config)
if self._host.has_min_version(
MIN_LIBVIRT_BLOCK_LM_WITH_VOLUMES_VERSION):
params = {
@ -6483,7 +6484,8 @@ class LibvirtDriver(driver.ComputeDriver):
disk_paths = []
device_names = []
if migrate_data.block_migration:
if (migrate_data.block_migration and
CONF.libvirt.virt_type != "parallels"):
disk_paths, device_names = self._live_migration_copy_disk_paths(
context, instance, guest)
@ -6792,6 +6794,12 @@ class LibvirtDriver(driver.ComputeDriver):
not available.
"""
# Virtuozzo containers don't use backing file
if (CONF.libvirt.virt_type == "parallels" and
instance.vm_mode == fields.VMMode.EXE):
return
if not disk_info:
disk_info = []

View File

@ -0,0 +1,4 @@
---
features:
- Live migration is supported for both Virtuozzo containers
and virtual machines when using virt_type=parallels.