Merge "Hide hypervisor id on windows guests"

This commit is contained in:
Zuul 2019-06-06 05:35:53 +00:00 committed by Gerrit Code Review
commit 6009cdaa47
5 changed files with 97 additions and 10 deletions
nova
tests/unit/virt/libvirt
virt/libvirt
releasenotes/notes

@ -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):
<relaxed state="on"/>
<vapic state="on"/>
<spinlocks state="on" retries="4095"/>
<vendor_id state="on" value="1234567890ab"/>
</hyperv>""")

@ -3812,13 +3812,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,
@ -3831,18 +3835,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)

@ -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

@ -4760,6 +4760,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,
@ -4782,13 +4786,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):

@ -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