diff --git a/doc/source/admin/scheduling.rst b/doc/source/admin/scheduling.rst index 9071c92ac9f..a8d3229a8dc 100644 --- a/doc/source/admin/scheduling.rst +++ b/doc/source/admin/scheduling.rst @@ -1122,10 +1122,9 @@ scheduling. Usage scenarios ~~~~~~~~~~~~~~~ -Since allocation ratios can be set via nova configuration, host aggregate -metadata and the placement API, it can be confusing to know which should be -used. This really depends on your scenario. A few common scenarios are detailed -here. +Since allocation ratios can be set via nova configuration and the placement +API, it can be confusing to know which should be used. This really depends on +your scenario. A few common scenarios are detailed here. 1. When the deployer wants to **always** set an override value for a resource on a compute node, the deployer should ensure that the diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 774498b69f4..ffa9ff18f9f 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -694,6 +694,7 @@ def _create_test_instance(): 'numa_topology': None, 'config_drive': None, 'vm_mode': None, + 'vm_state': None, 'kernel_id': None, 'ramdisk_id': None, 'os_type': 'linux', @@ -12313,7 +12314,7 @@ def test_live_migration_update_volume_xml(self, mock_xml, mock_updated_guest_xml, mock_migrateToURI3): self.compute = manager.ComputeManager() - instance_ref = self.test_instance + instance_ref = objects.Instance(**self.test_instance) target_connection = '127.0.0.2' target_xml = self.device_xml_tmpl.format( @@ -12482,7 +12483,7 @@ def test_live_migration_with_valid_target_connect_addr(self, mock_xml, mock_migrateToURI3, mock_min_version): self.compute = manager.ComputeManager() - instance_ref = self.test_instance + instance_ref = objects.Instance(**self.test_instance) target_connection = '127.0.0.2' target_xml = self.device_xml_tmpl.format( @@ -13097,6 +13098,33 @@ def test_block_live_migration_tunnelled_migrateToURI3( 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='') + def test_live_migration_paused_instance_postcopy(self, mock_new_xml, + mock_migrateToURI3, + mock_min_version): + disk_paths = [] + params = {'bandwidth': CONF.libvirt.live_migration_bandwidth} + migrate_data = objects.LibvirtLiveMigrateData(block_migration=False, + serial_listen_addr=False) + 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) + instance.vm_state = vm_states.PAUSED + + drvr._live_migration_operation(self.context, instance, 'dest', + True, migrate_data, guest, + disk_paths) + + # Verify VIR_MIGRATE_POSTCOPY flag was not set + self.assertEqual(drvr._live_migration_flags, 27) + mock_migrateToURI3.assert_called_once_with( + drvr._live_migration_uri('dest'), params=params, flags=27) + @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', @@ -13106,7 +13134,6 @@ def test_block_live_migration_native_tls( 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'] diff --git a/nova/tests/unit/virt/libvirt/test_utils.py b/nova/tests/unit/virt/libvirt/test_utils.py index c648108f561..37744ea9f7f 100644 --- a/nova/tests/unit/virt/libvirt/test_utils.py +++ b/nova/tests/unit/virt/libvirt/test_utils.py @@ -710,6 +710,10 @@ def test_get_machine_type_from_image(self): os_mach_type = libvirt_utils.get_machine_type(image_meta) self.assertEqual('q35', os_mach_type) + def test_make_reverse_cpu_traits_mapping(self): + for k in libvirt_utils.make_reverse_cpu_traits_mapping(): + self.assertIsInstance(k, str) + def test_get_flags_by_flavor_specs(self): flavor = objects.Flavor( id=1, flavorid='fakeid-1', name='fake1.small', memory_mb=128, @@ -718,11 +722,15 @@ def test_get_flags_by_flavor_specs(self): 'trait:%s' % os_traits.HW_CPU_X86_3DNOW: 'required', 'trait:%s' % os_traits.HW_CPU_X86_SSE2: 'required', 'trait:%s' % os_traits.HW_CPU_HYPERTHREADING: 'required', + 'trait:%s' % os_traits.HW_CPU_X86_INTEL_VMX: 'required', + 'trait:%s' % os_traits.HW_CPU_X86_VMX: 'required', + 'trait:%s' % os_traits.HW_CPU_X86_SVM: 'required', + 'trait:%s' % os_traits.HW_CPU_X86_AMD_SVM: 'required', }) traits = libvirt_utils.get_flags_by_flavor_specs(flavor) # we shouldn't see the hyperthreading trait since that's a valid trait # but not a CPU flag - self.assertEqual(set(['3dnow', 'sse2']), traits) + self.assertEqual(set(['3dnow', 'sse2', 'vmx', 'svm']), traits) @mock.patch('nova.virt.libvirt.utils.copy_image') @mock.patch('nova.privsep.path.chown') diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 7f02c8ed47f..6005bf3c628 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -10152,6 +10152,17 @@ def _live_migration_operation(self, context, instance, dest, else: migration_flags = self._live_migration_flags + # Note(siva_krishnan): live migrating paused instance fails + # when VIR_MIGRATE_POSTCOPY flag is set. It is unset here + # to permit live migration of paused instance. + if ( + instance.vm_state == vm_states.PAUSED and + self._is_post_copy_enabled(migration_flags) + ): + LOG.debug('Post-copy flag unset because instance is paused.', + instance=instance) + migration_flags ^= libvirt.VIR_MIGRATE_POSTCOPY + if not migrate_data.serial_listen_addr: # In this context we want to ensure that serial console is # disabled on source node. This is because nova couldn't diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py index adb2ec45a12..bec3b71e2bd 100644 --- a/nova/virt/libvirt/utils.py +++ b/nova/virt/libvirt/utils.py @@ -103,8 +103,20 @@ 'xop': os_traits.HW_CPU_X86_XOP } + +def make_reverse_cpu_traits_mapping() -> ty.Dict[str, str]: + traits_cpu_mapping = dict() + for k, v in CPU_TRAITS_MAPPING.items(): + if isinstance(v, tuple): + for trait in v: + traits_cpu_mapping[trait] = k + else: + traits_cpu_mapping[v] = k + return traits_cpu_mapping + + # Reverse CPU_TRAITS_MAPPING -TRAITS_CPU_MAPPING = {v: k for k, v in CPU_TRAITS_MAPPING.items()} +TRAITS_CPU_MAPPING = make_reverse_cpu_traits_mapping() # global directory for emulated TPM VTPM_DIR = '/var/lib/libvirt/swtpm/'