Add new configuration option to turn postcopy on/off
Since QEMU 2.5 and Libvirt 1.3.3 it is possible to use postcopy live migration to ensure an upper limit in the amount of memory to be transferred duing the live migration process. This option enables to live migrate instances with memory-intensive workloads by driving the migration process by the destination host, i.e., after the switch to postcopy mode, the destination VM is the active one and therefore any dirty pages are directly generated at the destination hosts. Partially-implements: blueprint auto-live-migration-completion Change-Id: I35b8400604eece5ddfba3e35015bcd3500d9f605 Signed-off-by: Luis Tomas <luis5tb@gmail.com> Co-Authored-By: Pawel Koniszewski <pawel.koniszewski@intel.com>
This commit is contained in:

committed by
Pawel Koniszewski

parent
e1e68eb557
commit
3d83c462bc
@ -152,6 +152,26 @@ libvirt_general_opts = [
|
||||
help='Time to wait, in seconds, for migration to make forward '
|
||||
'progress in transferring data before aborting the '
|
||||
'operation. Set to 0 to disable timeouts.'),
|
||||
cfg.BoolOpt('live_migration_permit_post_copy',
|
||||
default=False,
|
||||
help="""
|
||||
This option allows nova to switch an on-going live migration to post-copy
|
||||
mode, i.e., switch the active VM to the one on the destination node before the
|
||||
migration is complete, therefore ensuring an upper bound on the memory that
|
||||
needs to be transferred. Post-copy requires libvirt>=1.3.3 and QEMU>=2.5.0.
|
||||
|
||||
When permitted, post-copy mode will be automatically activated if a
|
||||
live-migration memory copy iteration does not make percentage increase of at
|
||||
least 10% over the last iteration.
|
||||
|
||||
The live-migration force complete API also uses post-copy when permitted. If
|
||||
post-copy mode is not available, force complete falls back to pausing the VM
|
||||
to ensure the live-migration operation will complete.
|
||||
|
||||
When using post-copy mode, if the source and destination hosts loose network
|
||||
connectivity, the VM being live-migrated will need to be rebooted. For more
|
||||
details, please see the Administration guide.
|
||||
"""),
|
||||
cfg.StrOpt('snapshot_image_format',
|
||||
choices=('raw', 'qcow2', 'vmdk', 'vdi'),
|
||||
help='Snapshot image format. Defaults to same as source image'),
|
||||
|
@ -94,6 +94,7 @@ VIR_MIGRATE_TUNNELLED = 4
|
||||
VIR_MIGRATE_PERSIST_DEST = 8
|
||||
VIR_MIGRATE_UNDEFINE_SOURCE = 16
|
||||
VIR_MIGRATE_NON_SHARED_INC = 128
|
||||
VIR_MIGRATE_POSTCOPY = 32768
|
||||
|
||||
VIR_NODE_CPU_STATS_ALL_CPUS = -1
|
||||
|
||||
|
@ -1181,6 +1181,75 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
msg = mock_log.warning.call_args_list[1]
|
||||
self.assertIn('contains the VIR_MIGRATE_TUNNELLED flag', msg[0][0])
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
|
||||
def test_live_migration_permit_postcopy_true(self, host):
|
||||
self.flags(live_migration_permit_post_copy=True, group='libvirt')
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED'),
|
||||
bm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED, '
|
||||
'VIR_MIGRATE_NON_SHARED_INC'),
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_POSTCOPY),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_POSTCOPY))
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=False)
|
||||
def test_live_migration_permit_postcopy_true_old_libvirt(self, host):
|
||||
self.flags(live_migration_permit_post_copy=True, group='libvirt')
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED'),
|
||||
bm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED, '
|
||||
'VIR_MIGRATE_NON_SHARED_INC'),
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC))
|
||||
|
||||
def test_live_migration_permit_postcopy_false(self):
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED'),
|
||||
bm_config=('VIR_MIGRATE_PERSIST_DEST, '
|
||||
'VIR_MIGRATE_PEER2PEER, '
|
||||
'VIR_MIGRATE_LIVE, '
|
||||
'VIR_MIGRATE_TUNNELLED, '
|
||||
'VIR_MIGRATE_NON_SHARED_INC'),
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC))
|
||||
|
||||
@mock.patch('nova.utils.get_image_from_system_metadata')
|
||||
@mock.patch.object(host.Host,
|
||||
'has_min_version', return_value=True)
|
||||
|
@ -284,6 +284,12 @@ ALLOWED_QEMU_SERIAL_PORTS = QEMU_MAX_SERIAL_PORTS - 1
|
||||
# realtime support
|
||||
MIN_LIBVIRT_REALTIME_VERSION = (1, 2, 13)
|
||||
|
||||
# libvirt postcopy support
|
||||
MIN_LIBVIRT_POSTCOPY_VERSION = (1, 3, 3)
|
||||
|
||||
# qemu postcopy support
|
||||
MIN_QEMU_POSTCOPY_VERSION = (2, 5, 0)
|
||||
|
||||
MIN_LIBVIRT_OTHER_ARCH = {arch.S390: MIN_LIBVIRT_KVM_S390_VERSION,
|
||||
arch.S390X: MIN_LIBVIRT_KVM_S390_VERSION,
|
||||
arch.PPC: MIN_LIBVIRT_KVM_PPC64_VERSION,
|
||||
@ -587,6 +593,24 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
|
||||
return migration_flags
|
||||
|
||||
def _is_post_copy_available(self):
|
||||
if self._host.has_min_version(lv_ver=MIN_LIBVIRT_POSTCOPY_VERSION,
|
||||
hv_ver=MIN_QEMU_POSTCOPY_VERSION):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _handle_live_migration_post_copy(self, migration_flags,
|
||||
config_name):
|
||||
if CONF.libvirt.live_migration_permit_post_copy:
|
||||
if self._is_post_copy_available():
|
||||
migration_flags |= libvirt.VIR_MIGRATE_POSTCOPY
|
||||
else:
|
||||
LOG.info(_LI('The live_migration_permit_post_copy is set '
|
||||
'to True, but it is not supported.'))
|
||||
elif self._is_post_copy_available():
|
||||
migration_flags &= ~libvirt.VIR_MIGRATE_POSTCOPY
|
||||
return migration_flags
|
||||
|
||||
def _parse_migration_flags(self):
|
||||
def str2sum(str_val):
|
||||
logical_sum = 0
|
||||
@ -618,6 +642,11 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
block_migration_flags = self._handle_live_migration_tunnelled(
|
||||
block_migration_flags, block_config_name)
|
||||
|
||||
live_migration_flags = self._handle_live_migration_post_copy(
|
||||
live_migration_flags, live_config_name)
|
||||
block_migration_flags = self._handle_live_migration_post_copy(
|
||||
block_migration_flags, block_config_name)
|
||||
|
||||
self._live_migration_flags = live_migration_flags
|
||||
self._block_migration_flags = block_migration_flags
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- New configuration option live_migration_permit_post_copy
|
||||
has been added to start live migrations in a way that allows
|
||||
nova to switch an on-going live migration to post-copy mode.
|
||||
Requires libvirt>=1.3.3 and QEMU>=2.5.0.
|
Reference in New Issue
Block a user