From de512f2c025429b72ade5a5ec38a6f1bde60af3c Mon Sep 17 00:00:00 2001 From: Kashyap Chamarthy Date: Thu, 20 Sep 2018 11:16:40 +0200 Subject: [PATCH] libvirt: Add a default VirtIO-RNG device to guests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tl;dr: We're adding the default VirtIO-RNG device to ensure guests are not starved of entropy (and thus not hang) during boot time. Background ---------- From Nova Git history, commit b94550f419 ("libvirt: configuration element for a random number generator device") _did_ add a default RNG device (but with its entropy source to the undesirable '/dev/random'). However, the default RNG device was immediately removed in another commit (605677c -- "libvirt: remove explicit /dev/random rng default"), with this rationale: libvirt (or rather qemu) will default to /dev/random if no rng device path is specified [...] It's preferable for us to not duplicate this default to allow for a future where libvirt or the hypervisor needs to make more intelligent decisions about the default device to use. The above reasoning doesn't hold up, because: (a) libvirt does not make "policy" decisions, such as choosing an entropy source (or any other such). Therefore Nova, as a management application, should make the decision here. (b) More importantly, when QEMU exposes a VirtIO-RNG device to the guest, that device needs a source of entropy; and QEMU by default uses the legacy and problematic `/dev/random` as the source — instead of the preferred `/dev/urandom`. So QEMU's default for VirtIO-RNG devices is not sufficient, and Nova should not rely on it. (Discussion[+] on 'qemu-devel' list to consider changing QEMU's default.) * * * In this patch: - Make Nova configure a VirtIO-RNG device by default for guests. (Which will be using `/dev/urandom` as the default entropy source.) This will also work for Windows guests, when using VirtIO-Win drivers[*] on the Linux host. - The 'hw_rng_model' image metadata property is now rendered (temporarily) useless -- as it's not used anywhere outside the _add_rng_device() method. But we don't want to deprecate it yet, as we may extend it (see code comment for details); docucment that. [*] https://docs.pagure.org/docs-fedora/create-windows-vms-using-virtio.html [+] https://lists.nongnu.org/archive/html/qemu-devel/2018-09/msg02724.html -- "[RFC] Virtio RNG: Consider changing the default entropy source to /dev/urandom?" Closes-Bug: #1789868 Change-Id: I28e66c9640c38d23b8c0dbd0b05f5260bfcf6d30 Signed-off-by: Kashyap Chamarthy --- nova/objects/fields.py | 14 ++ nova/objects/image_meta.py | 6 + nova/tests/unit/virt/libvirt/test_driver.py | 173 ++++++++++-------- nova/virt/libvirt/driver.py | 30 +-- ...irtio-rng-by-default-9cc1366ed1634129.yaml | 9 + 5 files changed, 145 insertions(+), 87 deletions(-) create mode 100644 releasenotes/notes/virtio-rng-by-default-9cc1366ed1634129.yaml diff --git a/nova/objects/fields.py b/nova/objects/fields.py index f812d0f71b06..946dc4e9189d 100644 --- a/nova/objects/fields.py +++ b/nova/objects/fields.py @@ -480,6 +480,20 @@ class OSType(BaseNovaEnum): class RNGModel(BaseNovaEnum): + # NOTE(kchamart): Along with "virtio", we may need to extend this (if a + # good reason shows up) to allow two more values for VirtIO + # transitional and non-transitional devices (available since libvirt + # 5.2.0): + # + # - virtio-transitional + # - virtio-nontransitional + # + # This allows one to choose whether you want to have compatibility + # with older guest operating systems. The value you select will in + # turn decide the kind of PCI topology the guest will get. + # + # Details: + # https://libvirt.org/formatdomain.html#elementsVirtioTransitional VIRTIO = "virtio" ALL = (VIRTIO,) diff --git a/nova/objects/image_meta.py b/nova/objects/image_meta.py index cbfdbc6bd857..8e3b4cc4410c 100644 --- a/nova/objects/image_meta.py +++ b/nova/objects/image_meta.py @@ -359,6 +359,12 @@ class ImageMetaProps(base.NovaObject): 'hw_rescue_device': fields.BlockDeviceTypeField(), # name of the RNG device type eg virtio + # NOTE(kchamart): Although this is currently not used anymore, + # we should not remove / deprecate it yet, as we are likely to + # extend this field to allow two more values to support "VirtIO + # transitional/non-transitional devices" (refer to the note in + # RNGModel() class in nova/objects/fields.py), and thus expose + # to the user again. 'hw_rng_model': fields.RNGModelField(), # boolean 'true' or 'false' to enable HPET diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 7c115df87d65..dc9a880203a8 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -2486,7 +2486,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual(cfg.os_type, fields.VMMode.HVM) self.assertEqual(cfg.os_boot_dev, ["hd"]) self.assertIsNone(cfg.os_root) - self.assertEqual(len(cfg.devices), 9) + self.assertEqual(len(cfg.devices), 10) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -2504,6 +2504,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[8], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[9], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(len(cfg.metadata), 1) self.assertIsInstance(cfg.metadata[0], @@ -4533,7 +4535,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual(cfg.os_type, fields.VMMode.HVM) self.assertEqual(cfg.os_boot_dev, ["hd"]) self.assertIsNone(cfg.os_root) - self.assertEqual(len(cfg.devices), 9) + self.assertEqual(len(cfg.devices), 10) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -4551,6 +4553,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[8], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[9], vconfig.LibvirtConfigMemoryBalloon) def test_get_guest_config_with_root_device_name(self): @@ -5001,7 +5005,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = self._get_guest_config_with_graphics() - self.assertEqual(len(cfg.devices), 6) + self.assertEqual(len(cfg.devices), 7) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5013,6 +5017,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[4], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[5], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[6], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(cfg.devices[3].type, 'vnc') @@ -5028,7 +5034,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = self._get_guest_config_with_graphics() - self.assertEqual(len(cfg.devices), 7) + self.assertEqual(len(cfg.devices), 8) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5042,6 +5048,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(cfg.devices[3].type, "tablet") @@ -5060,7 +5068,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = self._get_guest_config_with_graphics() - self.assertEqual(len(cfg.devices), 7) + self.assertEqual(len(cfg.devices), 8) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5074,6 +5082,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(cfg.devices[3].type, 'tablet') @@ -5095,7 +5105,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, expect = {"ppc": "vga", "ppc64": "vga", "ppc64le": "vga", "aarch64": "virtio"} video_type = expect.get(blockinfo.libvirt_utils.get_arch({}), "qxl") - self.assertEqual(len(cfg.devices), 7) + self.assertEqual(len(cfg.devices), 8) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5109,6 +5119,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(cfg.devices[3].target_name, "com.redhat.spice.0") @@ -5228,7 +5240,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(7, len(cfg.devices)) + self.assertEqual(8, len(cfg.devices)) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5242,6 +5254,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual("tcp", cfg.devices[2].type) @@ -5262,7 +5276,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(9, len(cfg.devices)) + self.assertEqual(10, len(cfg.devices)) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5280,6 +5294,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[8], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[9], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual("tcp", cfg.devices[2].type) @@ -5320,7 +5336,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta) cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(9, len(cfg.devices), cfg.devices) + self.assertEqual(10, len(cfg.devices), cfg.devices) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5338,6 +5354,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[8], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[9], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual("tcp", cfg.devices[2].type) @@ -5693,7 +5711,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta) cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(len(cfg.devices), 9) + self.assertEqual(len(cfg.devices), 10) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5711,6 +5729,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[8], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[9], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(cfg.devices[3].type, "tablet") @@ -5733,7 +5753,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta) cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(len(cfg.devices), 8) + self.assertEqual(len(cfg.devices), 9) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5747,11 +5767,13 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], - vconfig.LibvirtConfigGuestWatchdog) + vconfig.LibvirtConfigGuestRng) self.assertIsInstance(cfg.devices[7], + vconfig.LibvirtConfigGuestWatchdog) + self.assertIsInstance(cfg.devices[8], vconfig.LibvirtConfigMemoryBalloon) - self.assertEqual("none", cfg.devices[6].action) + self.assertEqual("none", cfg.devices[7].action) def _test_get_guest_usb_tablet(self, vnc_enabled, spice_enabled, os_type, agent_enabled=False, image_meta=None): @@ -5885,7 +5907,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(8, len(cfg.devices)) + self.assertEqual(9, len(cfg.devices)) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5899,11 +5921,13 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], - vconfig.LibvirtConfigGuestWatchdog) + vconfig.LibvirtConfigGuestRng) self.assertIsInstance(cfg.devices[7], + vconfig.LibvirtConfigGuestWatchdog) + self.assertIsInstance(cfg.devices[8], vconfig.LibvirtConfigMemoryBalloon) - self.assertEqual("none", cfg.devices[6].action) + self.assertEqual("none", cfg.devices[7].action) def test_get_guest_config_with_watchdog_overrides_flavor(self): self.flags(virt_type='kvm', group='libvirt') @@ -5923,7 +5947,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(8, len(cfg.devices)) + self.assertEqual(9, len(cfg.devices)) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -5937,11 +5961,12 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], - vconfig.LibvirtConfigGuestWatchdog) + vconfig.LibvirtConfigGuestRng) self.assertIsInstance(cfg.devices[7], + vconfig.LibvirtConfigGuestWatchdog) + self.assertIsInstance(cfg.devices[8], vconfig.LibvirtConfigMemoryBalloon) - - self.assertEqual("pause", cfg.devices[6].action) + self.assertEqual("pause", cfg.devices[7].action) def test_get_guest_config_with_video_driver_image_meta(self): self.flags(virt_type='kvm', group='libvirt') @@ -5952,43 +5977,45 @@ class LibvirtConnTestCase(test.NoDBTestCase, "disk_format": "raw", "properties": {"hw_video_model": "vmvga"}}) - 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.assertEqual(len(cfg.devices), 7) - self.assertIsInstance(cfg.devices[0], - vconfig.LibvirtConfigGuestDisk) - self.assertIsInstance(cfg.devices[1], - vconfig.LibvirtConfigGuestDisk) - self.assertIsInstance(cfg.devices[2], - vconfig.LibvirtConfigGuestSerial) - self.assertIsInstance(cfg.devices[3], - vconfig.LibvirtConfigGuestInput) - self.assertIsInstance(cfg.devices[4], - vconfig.LibvirtConfigGuestGraphics) - self.assertIsInstance(cfg.devices[5], - vconfig.LibvirtConfigGuestVideo) - self.assertIsInstance(cfg.devices[6], - vconfig.LibvirtConfigMemoryBalloon) - - self.assertEqual(cfg.devices[4].type, "vnc") - self.assertEqual(cfg.devices[5].type, "vmvga") - - def test_get_guest_config_with_qga_through_image_meta(self): - self.flags(virt_type='kvm', group='libvirt') - - drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - instance_ref = objects.Instance(**self.test_instance) - image_meta = objects.ImageMeta.from_dict({ - "disk_format": "raw", - "properties": {"hw_qemu_guest_agent": "yes"}}) - 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.assertEqual(len(cfg.devices), 8) + self.assertIsInstance(cfg.devices[0], + vconfig.LibvirtConfigGuestDisk) + self.assertIsInstance(cfg.devices[1], + vconfig.LibvirtConfigGuestDisk) + self.assertIsInstance(cfg.devices[2], + vconfig.LibvirtConfigGuestSerial) + self.assertIsInstance(cfg.devices[3], + vconfig.LibvirtConfigGuestInput) + self.assertIsInstance(cfg.devices[4], + vconfig.LibvirtConfigGuestGraphics) + self.assertIsInstance(cfg.devices[5], + vconfig.LibvirtConfigGuestVideo) + self.assertIsInstance(cfg.devices[6], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[7], + vconfig.LibvirtConfigMemoryBalloon) + + self.assertEqual(cfg.devices[4].type, "vnc") + self.assertEqual(cfg.devices[5].type, "vmvga") + + def test_get_guest_config_with_qga_through_image_meta(self): + self.flags(virt_type='kvm', group='libvirt') + + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + instance_ref = objects.Instance(**self.test_instance) + image_meta = objects.ImageMeta.from_dict({ + "disk_format": "raw", + "properties": {"hw_qemu_guest_agent": "yes"}}) + + 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.assertEqual(len(cfg.devices), 9) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -6004,6 +6031,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[6], vconfig.LibvirtConfigGuestChannel) self.assertIsInstance(cfg.devices[7], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[8], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(cfg.devices[3].type, "tablet") @@ -6050,7 +6079,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(len(cfg.devices), 7) + self.assertEqual(len(cfg.devices), 8) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -6064,6 +6093,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(cfg.devices[4].type, "spice") @@ -6233,7 +6264,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, instance_ref, image_meta) cfg = drvr._get_guest_config(instance_ref, [], image_meta, disk_info) - self.assertEqual(len(cfg.devices), 7) + self.assertEqual(len(cfg.devices), 8) self.assertIsInstance(cfg.devices[0], vconfig.LibvirtConfigGuestDisk) self.assertIsInstance(cfg.devices[1], @@ -6247,6 +6278,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertIsInstance(cfg.devices[5], vconfig.LibvirtConfigGuestVideo) self.assertIsInstance(cfg.devices[6], + vconfig.LibvirtConfigGuestRng) + self.assertIsInstance(cfg.devices[7], vconfig.LibvirtConfigMemoryBalloon) self.assertEqual(cfg.devices[3].type, "tablet") @@ -6258,10 +6291,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) instance_ref = objects.Instance(**self.test_instance) - instance_ref.flavor.extra_specs = {'hw_rng:allowed': 'True'} image_meta = objects.ImageMeta.from_dict({ - "disk_format": "raw", - "properties": {"hw_rng_model": "virtio"}}) + "disk_format": "raw"}) disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance_ref, @@ -6296,9 +6327,9 @@ class LibvirtConnTestCase(test.NoDBTestCase, drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) instance_ref = objects.Instance(**self.test_instance) + instance_ref.flavor.extra_specs = {'hw_rng:allowed': 'False'} image_meta = objects.ImageMeta.from_dict({ - "disk_format": "raw", - "properties": {"hw_rng_model": "virtio"}}) + "disk_format": "raw"}) disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance_ref, @@ -6326,12 +6357,10 @@ class LibvirtConnTestCase(test.NoDBTestCase, drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) instance_ref = objects.Instance(**self.test_instance) - instance_ref.flavor.extra_specs = {'hw_rng:allowed': 'True', - 'hw_rng:rate_bytes': '1024', + instance_ref.flavor.extra_specs = {'hw_rng:rate_bytes': '1024', 'hw_rng:rate_period': '2'} image_meta = objects.ImageMeta.from_dict({ - "disk_format": "raw", - "properties": {"hw_rng_model": "virtio"}}) + "disk_format": "raw"}) disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance_ref, @@ -6371,10 +6400,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) instance_ref = objects.Instance(**self.test_instance) - instance_ref.flavor.extra_specs = {'hw_rng:allowed': 'True'} image_meta = objects.ImageMeta.from_dict({ - "disk_format": "raw", - "properties": {"hw_rng_model": "virtio"}}) + "disk_format": "raw"}) disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance_ref, @@ -6413,10 +6440,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) instance_ref = objects.Instance(**self.test_instance) - instance_ref.flavor.extra_specs = {'hw_rng:allowed': 'True'} image_meta = objects.ImageMeta.from_dict({ - "disk_format": "raw", - "properties": {"hw_rng_model": "virtio"}}) + "disk_format": "raw"}) disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance_ref, @@ -7074,8 +7099,9 @@ class LibvirtConnTestCase(test.NoDBTestCase, _fake_network_info(self), image_meta, disk_info) self.assertTrue(mock_path_exists.called) - mock_path_exists.assert_any_call( - libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'][0]) + expected = mock.call(libvirt_driver. + DEFAULT_UEFI_LOADER_PATH['aarch64'][0]) + self.assertIn(expected, mock_path_exists.mock_calls) self.assertEqual(cfg.os_mach_type, "virt") num_ports = 0 @@ -7120,8 +7146,9 @@ class LibvirtConnTestCase(test.NoDBTestCase, cfg = self._get_guest_config_with_graphics() self.assertTrue(mock_path_exists.called) - mock_path_exists.assert_any_call( - libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'][0]) + expected = mock.call(libvirt_driver. + DEFAULT_UEFI_LOADER_PATH['aarch64'][0]) + self.assertIn(expected, mock_path_exists.mock_calls) self.assertEqual(cfg.os_mach_type, "virt") usbhost_exists = False diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index a6bd4d6fa72a..e21361a2d1c9 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -5109,21 +5109,23 @@ class LibvirtDriver(driver.ComputeDriver): guest.add_device(qga) def _add_rng_device(self, guest, flavor, image_meta): - rng_is_virtio = image_meta.properties.get('hw_rng_model') == 'virtio' - rng_allowed_str = flavor.extra_specs.get('hw_rng:allowed', '') + rng_allowed_str = flavor.extra_specs.get('hw_rng:allowed', 'True') rng_allowed = strutils.bool_from_string(rng_allowed_str) - if rng_is_virtio and rng_allowed: - rng_device = vconfig.LibvirtConfigGuestRng() - rate_bytes = flavor.extra_specs.get('hw_rng:rate_bytes', 0) - period = flavor.extra_specs.get('hw_rng:rate_period', 0) - if rate_bytes: - rng_device.rate_bytes = int(rate_bytes) - rng_device.rate_period = int(period) - rng_path = CONF.libvirt.rng_dev_path - if (rng_path and not os.path.exists(rng_path)): - raise exception.RngDeviceNotExist(path=rng_path) - rng_device.backend = rng_path - guest.add_device(rng_device) + + if not rng_allowed: + return + + rng_device = vconfig.LibvirtConfigGuestRng() + rate_bytes = flavor.extra_specs.get('hw_rng:rate_bytes', 0) + period = flavor.extra_specs.get('hw_rng:rate_period', 0) + if rate_bytes: + rng_device.rate_bytes = int(rate_bytes) + rng_device.rate_period = int(period) + rng_path = CONF.libvirt.rng_dev_path + if (rng_path and not os.path.exists(rng_path)): + raise exception.RngDeviceNotExist(path=rng_path) + rng_device.backend = rng_path + guest.add_device(rng_device) def _add_virtio_serial_controller(self, guest, instance): virtio_controller = vconfig.LibvirtConfigGuestController() diff --git a/releasenotes/notes/virtio-rng-by-default-9cc1366ed1634129.yaml b/releasenotes/notes/virtio-rng-by-default-9cc1366ed1634129.yaml new file mode 100644 index 000000000000..008507d76f3c --- /dev/null +++ b/releasenotes/notes/virtio-rng-by-default-9cc1366ed1634129.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + When using the libvirt driver, Nova instances will now get a + VirtIO-RNG (Random Number Generator) device by default. This is to + ensure guests are not starved of entropy during boot time. In case + you want to *disallow* setting an RNG device for some reason, it can + be done by setting the flavor Extra Spec property ``hw_rng:allowed`` + to ``False``.