Merge "Add new configuration option to turn postcopy on/off"

This commit is contained in:
Jenkins 2016-06-28 18:14:23 +00:00 committed by Gerrit Code Review
commit 7890d91eed
5 changed files with 125 additions and 0 deletions

View File

@ -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'),

View File

@ -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

View File

@ -1180,6 +1180,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)

View File

@ -286,6 +286,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,
@ -601,6 +607,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
@ -632,6 +656,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

View File

@ -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.