Merge "libvirt: Support native TLS for migration and disks over NBD"
This commit is contained in:
commit
5f9c8b45ff
|
@ -458,6 +458,44 @@ Determine the snapshot image format when sending to the image service.
|
|||
|
||||
If set, this decides what format is used when sending the snapshot to the
|
||||
image service. If not set, defaults to same type as source image.
|
||||
"""),
|
||||
cfg.BoolOpt('live_migration_with_native_tls',
|
||||
default=False,
|
||||
help="""
|
||||
|
||||
This option will allow both migration stream (guest RAM plus device
|
||||
state) *and* disk stream to be transported over native TLS, i.e. TLS
|
||||
support built into QEMU.
|
||||
|
||||
Prerequisite: TLS environment is configured correctly on all relevant
|
||||
Compute nodes. This means, Certificate Authority (CA), server, client
|
||||
certificates, their corresponding keys, and their file permisssions are
|
||||
in place, and are validated.
|
||||
|
||||
Notes:
|
||||
|
||||
* To have encryption for migration stream and disk stream (also called:
|
||||
"block migration"), ``live_migration_with_native_tls`` is the
|
||||
preferred config attribute instead of ``live_migration_tunnelled``.
|
||||
|
||||
* The ``live_migration_tunnelled`` will be deprecated in the long-term,
|
||||
for two main reasons: (a) it incurs a huge performance penalty; and
|
||||
it's not compatible with block migration.
|
||||
|
||||
* The ``live_migration_tunnelled`` and
|
||||
``live_migration_with_native_tls`` should not be used at the same
|
||||
time.
|
||||
|
||||
* Unlike ``live_migration_tunnelled``, the
|
||||
``live_migration_with_native_tls`` *is* compatible with block
|
||||
migration. That is, with this option, NBD stream, over which disks
|
||||
are migrated to a target host, will be encrypted.
|
||||
|
||||
Related options:
|
||||
|
||||
``live_migration_tunnelled``: This transports migration stream (but not
|
||||
disk stream) over libvirtd.
|
||||
|
||||
"""),
|
||||
cfg.StrOpt('disk_prefix',
|
||||
help="""
|
||||
|
|
|
@ -98,6 +98,7 @@ VIR_MIGRATE_UNDEFINE_SOURCE = 16
|
|||
VIR_MIGRATE_NON_SHARED_INC = 128
|
||||
VIR_MIGRATE_AUTO_CONVERGE = 8192
|
||||
VIR_MIGRATE_POSTCOPY = 32768
|
||||
VIR_MIGRATE_TLS = 65536
|
||||
|
||||
VIR_NODE_CPU_STATS_ALL_CPUS = -1
|
||||
|
||||
|
|
|
@ -1284,6 +1284,22 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED))
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
|
||||
def test_live_migration_with_native_tls(self, host):
|
||||
self.flags(live_migration_with_native_tls=True, group='libvirt')
|
||||
self._do_test_parse_migration_flags(
|
||||
lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PERSIST_DEST |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TLS),
|
||||
bm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_LIVE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_PERSIST_DEST |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_NON_SHARED_INC |
|
||||
libvirt_driver.libvirt.VIR_MIGRATE_TLS))
|
||||
|
||||
@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')
|
||||
|
@ -10439,6 +10455,52 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
drvr._live_migration_uri(target_connection),
|
||||
params=params, flags=expected_flags)
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
|
||||
@mock.patch.object(fakelibvirt.virDomain, "migrateToURI3")
|
||||
@mock.patch('nova.virt.libvirt.migration.get_updated_guest_xml',
|
||||
return_value='')
|
||||
@mock.patch('nova.virt.libvirt.guest.Guest.get_xml_desc', return_value='')
|
||||
def test_block_live_migration_native_tls_migrateToURI3(
|
||||
self, mock_old_xml, mock_new_xml,
|
||||
mock_migrateToURI3, mock_min_version):
|
||||
self.flags(live_migration_with_native_tls=True, group='libvirt')
|
||||
|
||||
target_connection = None
|
||||
disk_paths = ['vda', 'vdb']
|
||||
|
||||
params = {
|
||||
'bandwidth': CONF.libvirt.live_migration_bandwidth,
|
||||
'migrate_disks': disk_paths
|
||||
}
|
||||
|
||||
# Start test
|
||||
migrate_data = objects.LibvirtLiveMigrateData(
|
||||
graphics_listen_addr_vnc='0.0.0.0',
|
||||
graphics_listen_addr_spice='0.0.0.0',
|
||||
serial_listen_addr='127.0.0.1',
|
||||
target_connect_addr=target_connection,
|
||||
bdms=[],
|
||||
block_migration=True)
|
||||
|
||||
dom = fakelibvirt.virDomain
|
||||
guest = libvirt_guest.Guest(dom)
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
drvr._parse_migration_flags()
|
||||
instance = objects.Instance(**self.test_instance)
|
||||
drvr._live_migration_operation(self.context, instance,
|
||||
target_connection, True, migrate_data,
|
||||
guest, disk_paths)
|
||||
|
||||
expected_flags = (fakelibvirt.VIR_MIGRATE_UNDEFINE_SOURCE |
|
||||
fakelibvirt.VIR_MIGRATE_PERSIST_DEST |
|
||||
fakelibvirt.VIR_MIGRATE_PEER2PEER |
|
||||
fakelibvirt.VIR_MIGRATE_NON_SHARED_INC |
|
||||
fakelibvirt.VIR_MIGRATE_TLS |
|
||||
fakelibvirt.VIR_MIGRATE_LIVE)
|
||||
mock_migrateToURI3.assert_called_once_with(
|
||||
drvr._live_migration_uri(target_connection),
|
||||
params=params, flags=expected_flags)
|
||||
|
||||
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
|
||||
@mock.patch.object(fakelibvirt.virDomain, "migrateToURI3")
|
||||
@mock.patch('nova.virt.libvirt.guest.Guest.get_xml_desc',
|
||||
|
|
|
@ -288,6 +288,9 @@ MIN_QEMU_FILE_BACKED_VERSION = (2, 6, 0)
|
|||
MIN_LIBVIRT_FILE_BACKED_DISCARD_VERSION = (4, 4, 0)
|
||||
MIN_QEMU_FILE_BACKED_DISCARD_VERSION = (2, 10, 0)
|
||||
|
||||
MIN_LIBVIRT_NATIVE_TLS_VERSION = (4, 4, 0)
|
||||
MIN_QEMU_NATIVE_TLS_VERSION = (2, 11, 0)
|
||||
|
||||
VGPU_RESOURCE_SEMAPHORE = "vgpu_resources"
|
||||
|
||||
|
||||
|
@ -543,6 +546,20 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
'libvirt_ver': libvirt_utils.version_to_string(
|
||||
MIN_LIBVIRT_OTHER_ARCH.get(kvm_arch))})
|
||||
|
||||
# Allowing both "tunnelling via libvirtd" (which will be
|
||||
# deprecated once the MIN_{LIBVIRT,QEMU}_VERSION is sufficiently
|
||||
# new enough) and "native TLS" options at the same time is
|
||||
# nonsensical.
|
||||
if (CONF.libvirt.live_migration_tunnelled and
|
||||
CONF.libvirt.live_migration_with_native_tls):
|
||||
msg = _("Setting both 'live_migration_tunnelled' and"
|
||||
"'live_migration_with_native_tls' at the same"
|
||||
"time is invalid. If you have the relevant"
|
||||
"libvirt and QEMU versions, and TLS configured"
|
||||
"in your environment, pick"
|
||||
"'live_migration_with_native_tls'.")
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
# TODO(sbauza): Remove this code once mediated devices are persisted
|
||||
# across reboots.
|
||||
if self._host.has_min_version(MIN_LIBVIRT_MDEV_SUPPORT):
|
||||
|
@ -643,6 +660,16 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
migration_flags |= libvirt.VIR_MIGRATE_TUNNELLED
|
||||
return migration_flags
|
||||
|
||||
def _is_native_tls_available(self):
|
||||
return self._host.has_min_version(MIN_LIBVIRT_NATIVE_TLS_VERSION,
|
||||
MIN_QEMU_NATIVE_TLS_VERSION)
|
||||
|
||||
def _handle_native_tls(self, migration_flags):
|
||||
if (CONF.libvirt.live_migration_with_native_tls and
|
||||
self._is_native_tls_available()):
|
||||
migration_flags |= libvirt.VIR_MIGRATE_TLS
|
||||
return migration_flags
|
||||
|
||||
def _is_post_copy_available(self):
|
||||
return self._host.has_min_version(lv_ver=MIN_LIBVIRT_POSTCOPY_VERSION)
|
||||
|
||||
|
@ -682,6 +709,11 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
block_migration_flags = self._handle_live_migration_tunnelled(
|
||||
block_migration_flags)
|
||||
|
||||
live_migration_flags = self._handle_native_tls(
|
||||
live_migration_flags)
|
||||
block_migration_flags = self._handle_native_tls(
|
||||
block_migration_flags)
|
||||
|
||||
live_migration_flags = self._handle_live_migration_post_copy(
|
||||
live_migration_flags)
|
||||
block_migration_flags = self._handle_live_migration_post_copy(
|
||||
|
|
|
@ -636,6 +636,7 @@ class Guest(object):
|
|||
VIR_MIGRATE_UNSAFE Force migration even if it is considered
|
||||
unsafe.
|
||||
VIR_MIGRATE_OFFLINE Migrate offline
|
||||
VIR_MIGRATE_TLS Use QEMU-native TLS
|
||||
:param bandwidth: The maximum bandwidth in MiB/s
|
||||
"""
|
||||
params = {}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
The libvirt driver now supports "QEMU-native TLS" transport for live
|
||||
migration. This will provide encryption for all migration streams,
|
||||
namely: guest RAM, device state and disks on a non-shared setup that are
|
||||
transported over NBD (Network Block Device), also called as "block
|
||||
migration".
|
||||
|
||||
This can be configured via a new configuration attribute
|
||||
``[libvirt]/live_migration_with_native_tls``. Refer to its
|
||||
documentation in ``nova.conf`` for usage details. Note that this is
|
||||
the preferred the way to secure all migration streams in an
|
||||
OpenStack network, instead of
|
||||
``[libvirt]/live_migration_tunnelled``.
|
Loading…
Reference in New Issue