diff --git a/doc/source/user/flavors.rst b/doc/source/user/flavors.rst index 3052b7d5ba6c..971568d57d94 100644 --- a/doc/source/user/flavors.rst +++ b/doc/source/user/flavors.rst @@ -600,6 +600,28 @@ PCI passthrough - COUNT: (integer) The amount of PCI devices of type ALIAS to be assigned to a guest. +Hiding hypervisor signature + Some hypervisors add a signature to their guests. While the presence + of the signature can enable some paravirtualization features on the + guest, it can also have the effect of preventing some drivers from + loading. Hiding the signature by setting this property to true may + allow such drivers to load and work. + + .. note:: + + As of the 18.0.0 Rocky release, this is only supported by the libvirt + driver. + + .. code:: console + + $ openstack flavor set FLAVOR-NAME \ + --property hide_hypervisor_id=VALUE + + Where: + + - VALUE: (string) 'true' or 'false'. 'false' is equivalent to the + property not existing. + Secure Boot When your Compute services use the Hyper-V hypervisor, you can enable secure boot for Windows and Linux instances. diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index a83317e94c70..54715d52668f 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -78,6 +78,7 @@ from nova import rc_fields from nova import test from nova.tests.unit import fake_block_device from nova.tests.unit import fake_diagnostics +from nova.tests.unit import fake_flavor from nova.tests.unit import fake_instance from nova.tests.unit import fake_network import nova.tests.unit.image.fake @@ -5270,6 +5271,108 @@ class LibvirtConnTestCase(test.NoDBTestCase, any(isinstance(feature, vconfig.LibvirtConfigGuestFeatureKvmHidden) for feature in cfg.features)) + def test_get_guest_config_with_hiding_hypervisor_id_flavor_extra_specs( + self): + # Input to the test: flavor extra_specs + flavor_hide_id = fake_flavor.fake_flavor_obj(self.context, + extra_specs={"hide_hypervisor_id": "true"}, + expected_attrs={"extra_specs"}) + + self.flags(virt_type='kvm', group='libvirt') + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + instance_ref = objects.Instance(**self.test_instance) + instance_ref.flavor = flavor_hide_id + image_meta = objects.ImageMeta.from_dict({ + "disk_format": "raw"}) + disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, + instance_ref, + image_meta) + cfg = drvr._get_guest_config(instance_ref, + [], + image_meta, + disk_info) + + self.assertTrue( + any(isinstance(feature, vconfig.LibvirtConfigGuestFeatureKvmHidden) + for feature in cfg.features)) + + def test_get_guest_config_with_hiding_hypervisor_id_img_and_flavor( + self): + # Input to the test: image metadata (true) and flavor + # extra_specs (true) + flavor_hide_id = fake_flavor.fake_flavor_obj(self.context, + extra_specs={"hide_hypervisor_id": "true"}, + expected_attrs={"extra_specs"}) + image_meta = objects.ImageMeta.from_dict({ + "disk_format": "raw", + "properties": {"img_hide_hypervisor_id": "true"}}) + + self.flags(virt_type='kvm', group='libvirt') + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + instance_ref = objects.Instance(**self.test_instance) + instance_ref.flavor = flavor_hide_id + disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, + instance_ref, + image_meta) + cfg = drvr._get_guest_config(instance_ref, + [], + image_meta, + disk_info) + + self.assertTrue( + any(isinstance(feature, vconfig.LibvirtConfigGuestFeatureKvmHidden) + for feature in cfg.features)) + + def test_get_guest_config_with_hiding_hypervisor_id_img_or_flavor( + self): + # Input to the test: image metadata (false) and flavor + # extra_specs (true) + flavor_hide_id = fake_flavor.fake_flavor_obj(self.context, + extra_specs={"hide_hypervisor_id": "true"}, + expected_attrs={"extra_specs"}) + image_meta = objects.ImageMeta.from_dict({ + "disk_format": "raw", + "properties": {"img_hide_hypervisor_id": "false"}}) + + self.flags(virt_type='kvm', group='libvirt') + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + instance_ref = objects.Instance(**self.test_instance) + instance_ref.flavor = flavor_hide_id + disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, + instance_ref, + image_meta) + cfg = drvr._get_guest_config(instance_ref, + [], + image_meta, + disk_info) + + self.assertTrue( + any(isinstance(feature, vconfig.LibvirtConfigGuestFeatureKvmHidden) + for feature in cfg.features)) + + # Input to the test: image metadata (true) and flavor + # extra_specs (false) + flavor_hide_id = fake_flavor.fake_flavor_obj(self.context, + extra_specs={"hide_hypervisor_id": "false"}, + expected_attrs={"extra_specs"}) + image_meta = objects.ImageMeta.from_dict({ + "disk_format": "raw", + "properties": {"img_hide_hypervisor_id": "true"}}) + + instance_ref.flavor = flavor_hide_id + + disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, + instance_ref, + image_meta) + cfg = drvr._get_guest_config(instance_ref, + [], + image_meta, + disk_info) + + self.assertTrue( + any(isinstance(feature, vconfig.LibvirtConfigGuestFeatureKvmHidden) + for feature in cfg.features)) + def test_get_guest_config_without_hiding_hypervisor_id(self): self.flags(virt_type='kvm', group='libvirt') @@ -5294,6 +5397,30 @@ class LibvirtConnTestCase(test.NoDBTestCase, any(isinstance(feature, vconfig.LibvirtConfigGuestFeatureKvmHidden) for feature in cfg.features)) + def test_get_guest_config_without_hiding_hypervisor_id_flavor_extra_specs( + self): + flavor_hide_id = fake_flavor.fake_flavor_obj(self.context, + extra_specs={"hide_hypervisor_id": "false"}, + expected_attrs={"extra_specs"}) + + self.flags(virt_type='qemu', group='libvirt') + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + instance_ref = objects.Instance(**self.test_instance) + instance_ref.flavor = flavor_hide_id + image_meta = objects.ImageMeta.from_dict({ + "disk_format": "raw"}) + disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, + instance_ref, + image_meta) + cfg = drvr._get_guest_config(instance_ref, + [], + image_meta, + disk_info) + + self.assertFalse( + any(isinstance(feature, vconfig.LibvirtConfigGuestFeatureKvmHidden) + for feature in cfg.features)) + def _test_get_guest_config_disk_cachemodes(self, images_type): # Verify that the configured cachemodes are propagated to the device # configurations. diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index bff62d3f7e08..69770958f758 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -4584,7 +4584,8 @@ class LibvirtDriver(driver.ComputeDriver): tmhyperv.present = True clk.add_timer(tmhyperv) - def _set_features(self, guest, os_type, caps, virt_type, image_meta): + def _set_features(self, guest, os_type, caps, virt_type, image_meta, + flavor): if virt_type == "xen": # PAE only makes sense in X86 if caps.host.cpu.arch in (fields.Architecture.I686, @@ -4609,8 +4610,11 @@ class LibvirtDriver(driver.ComputeDriver): hv.vapic = 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')): + (image_meta.properties.get('img_hide_hypervisor_id') or + flavor_hide_kvm)): guest.features.append(vconfig.LibvirtConfigGuestFeatureKvmHidden()) def _check_number_of_serial_console(self, num_ports): @@ -5171,7 +5175,7 @@ class LibvirtDriver(driver.ComputeDriver): instance, inst_path, image_meta, disk_info) self._set_features(guest, instance.os_type, caps, virt_type, - image_meta) + image_meta, flavor) self._set_clock(guest, instance.os_type, image_meta, virt_type) storage_configs = self._get_guest_storage_config(context, diff --git a/releasenotes/notes/hide_hypervisor_id-flavor-a7c16afeab553b01.yaml b/releasenotes/notes/hide_hypervisor_id-flavor-a7c16afeab553b01.yaml new file mode 100644 index 000000000000..263d42f90599 --- /dev/null +++ b/releasenotes/notes/hide_hypervisor_id-flavor-a7c16afeab553b01.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + Added a new flavor extra_spec, ``hide_hypervisor_id``, which hides + the hypervisor signature for the guest when true ('kvm' won't appear + in ``lscpu``). This acts exactly like and in parallel to the image + property ``img_hide_hypervisor_id`` and is useful for running the + nvidia drivers in the guest. + Currently, this is only supported in the libvirt driver.