diff --git a/nova/tests/fixtures/libvirt_data.py b/nova/tests/fixtures/libvirt_data.py index 7940ad2a069a..463cb0ae3f4a 100644 --- a/nova/tests/fixtures/libvirt_data.py +++ b/nova/tests/fixtures/libvirt_data.py @@ -82,7 +82,8 @@ def fake_kvm_guest(): obj.features = [ config.LibvirtConfigGuestFeatureACPI(), config.LibvirtConfigGuestFeatureAPIC(), - config.LibvirtConfigGuestFeatureKvmHidden() + config.LibvirtConfigGuestFeatureKvmHidden(), + config.LibvirtConfigGuestFeatureVMCoreInfo(), ] obj.sysinfo = config.LibvirtConfigGuestSysinfo() @@ -207,6 +208,7 @@ FAKE_KVM_GUEST = """ + 100 diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 9f5e7865db92..ec65be7ce280 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -2571,11 +2571,13 @@ class LibvirtConnTestCase(test.NoDBTestCase, context=ctxt) self.assertEqual(cfg.uuid, instance_ref["uuid"]) - self.assertEqual(2, len(cfg.features)) + self.assertEqual(3, len(cfg.features)) self.assertIsInstance(cfg.features[0], vconfig.LibvirtConfigGuestFeatureACPI) self.assertIsInstance(cfg.features[1], vconfig.LibvirtConfigGuestFeatureAPIC) + self.assertIsInstance( + cfg.features[2], vconfig.LibvirtConfigGuestFeatureVMCoreInfo) self.assertEqual(cfg.memory, 6 * units.Ki) self.assertEqual(cfg.vcpus, 28) self.assertEqual(cfg.os_type, fields.VMMode.HVM) @@ -4863,13 +4865,15 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual("hypervclock", cfg.clock.timers[3].name) self.assertTrue(cfg.clock.timers[3].present) - self.assertEqual(3, len(cfg.features)) + self.assertEqual(4, len(cfg.features)) self.assertIsInstance(cfg.features[0], vconfig.LibvirtConfigGuestFeatureACPI) self.assertIsInstance(cfg.features[1], vconfig.LibvirtConfigGuestFeatureAPIC) self.assertIsInstance(cfg.features[2], vconfig.LibvirtConfigGuestFeatureHyperV) + self.assertIsInstance( + cfg.features[3], vconfig.LibvirtConfigGuestFeatureVMCoreInfo) @mock.patch.object(host.Host, 'has_min_version', new=mock.Mock(return_value=True)) @@ -4894,7 +4898,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, vconfig.LibvirtConfigGuestClock) self.assertEqual(cfg.clock.offset, "localtime") - num_features = 4 if hvid_hidden else 3 + num_features = 5 if hvid_hidden else 4 self.assertEqual(num_features, len(cfg.features)) self.assertIsInstance(cfg.features[0], vconfig.LibvirtConfigGuestFeatureACPI) @@ -4902,9 +4906,11 @@ class LibvirtConnTestCase(test.NoDBTestCase, vconfig.LibvirtConfigGuestFeatureAPIC) self.assertIsInstance(cfg.features[2], vconfig.LibvirtConfigGuestFeatureHyperV) + self.assertIsInstance( + cfg.features[3], vconfig.LibvirtConfigGuestFeatureVMCoreInfo) if hvid_hidden: - self.assertIsInstance(cfg.features[3], - vconfig.LibvirtConfigGuestFeatureKvmHidden) + self.assertIsInstance( + cfg.features[4], vconfig.LibvirtConfigGuestFeatureKvmHidden) self.assertTrue(cfg.features[2].relaxed) self.assertTrue(cfg.features[2].spinlocks) @@ -4980,11 +4986,13 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = drvr._get_guest_config(instance_ref, _fake_network_info(self, 2), image_meta, disk_info) - self.assertEqual(2, len(cfg.features)) + self.assertEqual(3, len(cfg.features)) self.assertIsInstance(cfg.features[0], vconfig.LibvirtConfigGuestFeatureACPI) self.assertIsInstance(cfg.features[1], vconfig.LibvirtConfigGuestFeatureAPIC) + self.assertIsInstance( + cfg.features[2], vconfig.LibvirtConfigGuestFeatureVMCoreInfo) self.assertEqual(cfg.memory, instance_ref.flavor.memory_mb * units.Ki) self.assertEqual(cfg.vcpus, instance_ref.flavor.vcpus) self.assertEqual(cfg.os_type, fields.VMMode.HVM) diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py index f9475776b3da..c49c187d2d02 100644 --- a/nova/virt/libvirt/config.py +++ b/nova/virt/libvirt/config.py @@ -2762,6 +2762,12 @@ class LibvirtConfigGuestSEVLaunchSecurity(LibvirtConfigObject): return root +class LibvirtConfigGuestFeatureVMCoreInfo(LibvirtConfigGuestFeature): + + def __init__(self, **kwargs): + super().__init__('vmcoreinfo', **kwargs) + + class LibvirtConfigGuest(LibvirtConfigObject): def __init__(self, **kwargs): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 391231c52775..153df2d06ae9 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -5854,6 +5854,15 @@ class LibvirtDriver(driver.ComputeDriver): guest.features.append(hv) if CONF.libvirt.virt_type in ("qemu", "kvm"): + # vmcoreinfo support is x86, ARM-only for now + guestarch = libvirt_utils.get_arch(image_meta) + if guestarch in ( + fields.Architecture.I686, fields.Architecture.X86_64, + fields.Architecture.AARCH64, + ): + guest.features.append( + vconfig.LibvirtConfigGuestFeatureVMCoreInfo()) + if hide_hypervisor_id: guest.features.append( vconfig.LibvirtConfigGuestFeatureKvmHidden()) diff --git a/releasenotes/notes/libvirt-vmcoreinfo-3be69e21dfe7dbd2.yaml b/releasenotes/notes/libvirt-vmcoreinfo-3be69e21dfe7dbd2.yaml new file mode 100644 index 000000000000..2bd5c9cb98e4 --- /dev/null +++ b/releasenotes/notes/libvirt-vmcoreinfo-3be69e21dfe7dbd2.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + When using the libvirt virt driver with the QEMU or KVM backends, instances + will now be created with the *vmcoreinfo* feature enabled by default. This + creates a fw_cfg entry for a guest to store dump details, necessary to + process kernel dump with KASLR enabled and providing additional kernel + details. For more information, refer to the `libvirt`__ documentation. + + __ https://libvirt.org/formatdomain.html#hypervisor-features