diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 41ca995453ba..7be95968d51d 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -1073,6 +1073,53 @@ class LibvirtConnTestCase(test.NoDBTestCase): msg = mock_log.warning.call_args_list[3] self.assertIn('Removing the VIR_MIGRATE_PERSIST_DEST flag', msg[0][0]) + @mock.patch('nova.virt.libvirt.driver.LOG') + def test_live_migration_tunnelled_true(self, mock_log): + self.flags(live_migration_tunnelled=True, group='libvirt') + + self._do_test_parse_migration_flags( + lm_config=('VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_UNDEFINE_SOURCE, ' + 'VIR_MIGRATE_LIVE'), + bm_config=('VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_UNDEFINE_SOURCE, ' + 'VIR_MIGRATE_LIVE, VIR_MIGRATE_NON_SHARED_INC'), + 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_TUNNELLED), + 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_NON_SHARED_INC | + libvirt_driver.libvirt.VIR_MIGRATE_TUNNELLED)) + + msg = mock_log.warning.call_args_list[0] + self.assertIn('does not contain the VIR_MIGRATE_TUNNELLED', msg[0][0]) + msg = mock_log.warning.call_args_list[1] + self.assertIn('does not contain the VIR_MIGRATE_TUNNELLED', msg[0][0]) + + @mock.patch('nova.virt.libvirt.driver.LOG') + def test_live_migration_tunnelled_false(self, mock_log): + self.flags(live_migration_tunnelled=False, group='libvirt') + + self._do_test_parse_migration_flags( + lm_config=('VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_UNDEFINE_SOURCE, ' + 'VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED'), + bm_config=('VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_UNDEFINE_SOURCE, ' + 'VIR_MIGRATE_LIVE, VIR_MIGRATE_NON_SHARED_INC, ' + 'VIR_MIGRATE_TUNNELLED'), + lm_expected=(libvirt_driver.libvirt.VIR_MIGRATE_LIVE | + libvirt_driver.libvirt.VIR_MIGRATE_PEER2PEER | + libvirt_driver.libvirt.VIR_MIGRATE_UNDEFINE_SOURCE), + 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_NON_SHARED_INC)) + + msg = mock_log.warning.call_args_list[0] + self.assertIn('contains the VIR_MIGRATE_TUNNELLED flag', msg[0][0]) + msg = mock_log.warning.call_args_list[1] + self.assertIn('contains the VIR_MIGRATE_TUNNELLED flag', msg[0][0]) + @mock.patch('nova.utils.get_image_from_system_metadata') @mock.patch.object(host.Host, 'has_min_version', return_value=True) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 95c0fe45ada1..a2ee0b3dbb3c 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -170,6 +170,16 @@ libvirt_opts = [ 'VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED, ' 'VIR_MIGRATE_NON_SHARED_INC', help='Migration flags to be set for block migration'), + cfg.BoolOpt('live_migration_tunnelled', + help='Whether to use tunnelled migration, where migration ' + 'data is transported over the libvirtd connection. If ' + 'True, we use the VIR_MIGRATE_TUNNELLED migration flag, ' + 'avoiding the need to configure the network to allow ' + 'direct hypervisor to hypervisor communication. If ' + 'False, use the native transport. If not set, Nova ' + 'will choose a sensible default based on, for example ' + 'the availability of native encryption support in the ' + 'hypervisor.'), cfg.IntOpt('live_migration_bandwidth', default=0, help='Maximum bandwidth(in MiB/s) to be used during migration. ' @@ -721,6 +731,31 @@ class LibvirtDriver(driver.ComputeDriver): return (live_migration_flags, block_migration_flags) + def _handle_live_migration_tunnelled(self, migration_flags, config_name): + if CONF.libvirt.live_migration_tunnelled is None: + return migration_flags + + if CONF.libvirt.live_migration_tunnelled: + if (migration_flags & libvirt.VIR_MIGRATE_TUNNELLED) == 0: + LOG.warning(_LW('The %(config_name)s config option does not ' + 'contain the VIR_MIGRATE_TUNNELLED flag but ' + 'the live_migration_tunnelled is set to True ' + 'which causes VIR_MIGRATE_TUNNELLED to be ' + 'set'), + {'config_name': config_name}) + migration_flags |= libvirt.VIR_MIGRATE_TUNNELLED + else: + if (migration_flags & libvirt.VIR_MIGRATE_TUNNELLED) != 0: + LOG.warning(_LW('The %(config_name)s config option contains ' + 'the VIR_MIGRATE_TUNNELLED flag but the ' + 'live_migration_tunnelled is set to False ' + 'which causes VIR_MIGRATE_TUNNELLED to be ' + 'unset'), + {'config_name': config_name}) + migration_flags &= ~libvirt.VIR_MIGRATE_TUNNELLED + + return migration_flags + def _parse_migration_flags(self): def str2sum(str_val): logical_sum = 0 @@ -747,6 +782,11 @@ class LibvirtDriver(driver.ComputeDriver): block_migration_flags) = self._check_block_migration_flags( live_migration_flags, block_migration_flags) + live_migration_flags = self._handle_live_migration_tunnelled( + live_migration_flags, live_config_name) + block_migration_flags = self._handle_live_migration_tunnelled( + block_migration_flags, block_config_name) + self._live_migration_flags = live_migration_flags self._block_migration_flags = block_migration_flags diff --git a/releasenotes/notes/libvirt-live-migration-new-tunneled-option-d7ebb1eb1e95e683.yaml b/releasenotes/notes/libvirt-live-migration-new-tunneled-option-d7ebb1eb1e95e683.yaml new file mode 100644 index 000000000000..6c56365275b5 --- /dev/null +++ b/releasenotes/notes/libvirt-live-migration-new-tunneled-option-d7ebb1eb1e95e683.yaml @@ -0,0 +1,7 @@ +--- +features: + - The libvirt driver now has a live_migration_tunnelled + configuration option which should be used where the + VIR_MIGRATE_TUNNELLED flag would previously have been + set or unset in the live_migration_flag and + block_migration_flag configuration options.