diff --git a/nova/tests/unit/virt/libvirt/test_config.py b/nova/tests/unit/virt/libvirt/test_config.py
index eada5a2b14a1..a11d2df79f48 100644
--- a/nova/tests/unit/virt/libvirt/test_config.py
+++ b/nova/tests/unit/virt/libvirt/test_config.py
@@ -2182,6 +2182,7 @@ class LibvirtConfigGuestFeatureTest(LibvirtConfigBaseTest):
obj.relaxed = True
obj.vapic = True
obj.spinlocks = True
+ obj.vendorid_spoof = True
xml = obj.to_xml()
self.assertXmlEqual(xml, """
@@ -2189,6 +2190,7 @@ class LibvirtConfigGuestFeatureTest(LibvirtConfigBaseTest):
+
""")
diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py
index adbff9c1ee82..8a8f2cec1fda 100644
--- a/nova/tests/unit/virt/libvirt/test_driver.py
+++ b/nova/tests/unit/virt/libvirt/test_driver.py
@@ -3813,13 +3813,17 @@ class LibvirtConnTestCase(test.NoDBTestCase,
self.assertIsInstance(cfg.features[2],
vconfig.LibvirtConfigGuestFeatureHyperV)
- @mock.patch.object(host.Host, 'has_min_version')
- def test_get_guest_config_windows_hyperv_feature2(self, mock_version):
- mock_version.return_value = True
+ @mock.patch.object(host.Host, 'has_min_version',
+ new=mock.Mock(return_value=True))
+ def _test_get_guest_config_windows_hyperv(
+ self, flavor=None, image_meta=None, hvid_hidden=False):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
instance_ref = objects.Instance(**self.test_instance)
instance_ref['os_type'] = 'windows'
- image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
+ if flavor is not None:
+ instance_ref.flavor = flavor
+ if image_meta is None:
+ image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance_ref,
@@ -3832,18 +3836,67 @@ class LibvirtConnTestCase(test.NoDBTestCase,
vconfig.LibvirtConfigGuestClock)
self.assertEqual(cfg.clock.offset, "localtime")
- self.assertEqual(3, len(cfg.features))
+ num_features = 4 if hvid_hidden else 3
+ self.assertEqual(num_features, len(cfg.features))
self.assertIsInstance(cfg.features[0],
vconfig.LibvirtConfigGuestFeatureACPI)
self.assertIsInstance(cfg.features[1],
vconfig.LibvirtConfigGuestFeatureAPIC)
self.assertIsInstance(cfg.features[2],
vconfig.LibvirtConfigGuestFeatureHyperV)
+ if hvid_hidden:
+ self.assertIsInstance(cfg.features[3],
+ vconfig.LibvirtConfigGuestFeatureKvmHidden)
self.assertTrue(cfg.features[2].relaxed)
self.assertTrue(cfg.features[2].spinlocks)
self.assertEqual(8191, cfg.features[2].spinlock_retries)
self.assertTrue(cfg.features[2].vapic)
+ self.assertEqual(hvid_hidden, cfg.features[2].vendorid_spoof)
+
+ def test_get_guest_config_windows_hyperv_feature2(self):
+ self._test_get_guest_config_windows_hyperv()
+
+ def test_get_guest_config_windows_hyperv_all_hide_flv(self):
+ # Similar to test_get_guest_config_windows_hyperv_feature2
+ # but also test hiding the HyperV signature with the flavor
+ # extra_spec "hide_hypervisor_id"
+ flavor_hide_id = fake_flavor.fake_flavor_obj(self.context,
+ extra_specs={"hide_hypervisor_id": "true"},
+ expected_attrs={"extra_specs"})
+ # this works for kvm (the default, tested below) and qemu
+ self.flags(virt_type='qemu', group='libvirt')
+
+ self._test_get_guest_config_windows_hyperv(
+ flavor=flavor_hide_id, hvid_hidden=True)
+
+ def test_get_guest_config_windows_hyperv_all_hide_img(self):
+ # Similar to test_get_guest_config_windows_hyperv_feature2
+ # but also test hiding the HyperV signature with the image
+ # property "img_hide_hypervisor_id"
+ image_meta = objects.ImageMeta.from_dict({
+ "disk_format": "raw",
+ "properties": {"img_hide_hypervisor_id": "true"}})
+
+ self._test_get_guest_config_windows_hyperv(
+ image_meta=image_meta, hvid_hidden=True)
+
+ def test_get_guest_config_windows_hyperv_all_hide_flv_img(self):
+ # Similar to test_get_guest_config_windows_hyperv_feature2
+ # but also test hiding the HyperV signature with both the flavor
+ # extra_spec "hide_hypervisor_id" and the image property
+ # "img_hide_hypervisor_id"
+ flavor_hide_id = fake_flavor.fake_flavor_obj(self.context,
+ extra_specs={"hide_hypervisor_id": "true"},
+ expected_attrs={"extra_specs"})
+ self.flags(virt_type='qemu', group='libvirt')
+
+ image_meta = objects.ImageMeta.from_dict({
+ "disk_format": "raw",
+ "properties": {"img_hide_hypervisor_id": "true"}})
+
+ self._test_get_guest_config_windows_hyperv(
+ flavor=flavor_hide_id, image_meta=image_meta, hvid_hidden=True)
def test_get_guest_config_with_two_nics(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py
index b1e43bdccd2f..ec0a19af9a81 100644
--- a/nova/virt/libvirt/config.py
+++ b/nova/virt/libvirt/config.py
@@ -2334,6 +2334,8 @@ class LibvirtConfigGuestFeatureHyperV(LibvirtConfigGuestFeature):
# QEMU requires at least this value to be set
MIN_SPINLOCK_RETRIES = 4095
+ # The spoofed vendor_id can be any alphanumeric string
+ SPOOFED_VENDOR_ID = "1234567890ab"
def __init__(self, **kwargs):
super(LibvirtConfigGuestFeatureHyperV, self).__init__("hyperv",
@@ -2343,6 +2345,8 @@ class LibvirtConfigGuestFeatureHyperV(LibvirtConfigGuestFeature):
self.vapic = False
self.spinlocks = False
self.spinlock_retries = self.MIN_SPINLOCK_RETRIES
+ self.vendorid_spoof = False
+ self.vendorid = self.SPOOFED_VENDOR_ID
def format_dom(self):
root = super(LibvirtConfigGuestFeatureHyperV, self).format_dom()
@@ -2354,6 +2358,9 @@ class LibvirtConfigGuestFeatureHyperV(LibvirtConfigGuestFeature):
if self.spinlocks:
root.append(etree.Element("spinlocks", state="on",
retries=str(self.spinlock_retries)))
+ if self.vendorid_spoof:
+ root.append(etree.Element("vendor_id", state="on",
+ value=self.vendorid))
return root
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index 89622734ad0e..f89da6745808 100644
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -4737,6 +4737,10 @@ class LibvirtDriver(driver.ComputeDriver):
def _set_features(self, guest, os_type, caps, virt_type, image_meta,
flavor):
+ hide_hypervisor_id = (strutils.bool_from_string(
+ flavor.extra_specs.get('hide_hypervisor_id')) or
+ image_meta.properties.get('img_hide_hypervisor_id'))
+
if virt_type == "xen":
# PAE only makes sense in X86
if caps.host.cpu.arch in (fields.Architecture.I686,
@@ -4759,13 +4763,23 @@ class LibvirtDriver(driver.ComputeDriver):
# with Microsoft
hv.spinlock_retries = 8191
hv.vapic = True
+
+ # NOTE(kosamara): Spoofing the vendor_id aims to allow the nvidia
+ # driver to work on windows VMs. At the moment, the nvidia driver
+ # checks for the hyperv vendorid, and if it doesn't find that, it
+ # works. In the future, its behaviour could become more strict,
+ # checking for the presence of other hyperv feature flags to
+ # determine that it's loaded in a VM. If that happens, this
+ # workaround will not be enough, and we'll need to drop the whole
+ # hyperv element.
+ # That would disable some optimizations, reducing the guest's
+ # performance.
+ if hide_hypervisor_id:
+ hv.vendorid_spoof = True
+
guest.features.append(hv)
- flavor_hide_kvm = strutils.bool_from_string(
- flavor.get('extra_specs', {}).get('hide_hypervisor_id'))
- if (virt_type in ("qemu", "kvm") and
- (image_meta.properties.get('img_hide_hypervisor_id') or
- flavor_hide_kvm)):
+ if (virt_type in ("qemu", "kvm") and hide_hypervisor_id):
guest.features.append(vconfig.LibvirtConfigGuestFeatureKvmHidden())
def _check_number_of_serial_console(self, num_ports):
diff --git a/releasenotes/notes/bug-1779845-8819eea6e91fb09c.yaml b/releasenotes/notes/bug-1779845-8819eea6e91fb09c.yaml
new file mode 100644
index 000000000000..f8d19a454902
--- /dev/null
+++ b/releasenotes/notes/bug-1779845-8819eea6e91fb09c.yaml
@@ -0,0 +1,11 @@
+---
+fixes:
+ - |
+ Blueprints `hide-hypervisor-id-flavor-extra-spec`_ and
+ `add-kvm-hidden-feature`_ enabled NVIDIA drivers in Linux guests using KVM
+ and QEMU, but support was not included for Windows guests. This is now
+ fixed. See `bug 1779845`_ for details.
+
+ .. _hide-hypervisor-id-flavor-extra-spec: https://blueprints.launchpad.net/nova/+spec/hide-hypervisor-id-flavor-extra-spec
+ .. _add-kvm-hidden-feature: https://blueprints.launchpad.net/nova/+spec/add-kvm-hidden-feature
+ .. _bug 1779845: https://bugs.launchpad.net/nova/+bug/1779845