Merge "Add new configuration option to turn postcopy on/off"
This commit is contained in:
commit
7890d91eed
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user