libvirt: Handle alternative UEFI firmware binary paths

The OVMF binary paths differ based on the Linux distribution:

  - Debian and Ubuntu:
     - /usr/share/OVMF/OVMF_CODE.fd
  - Fedora:
     - /usr/share/edk2/ovmf/OVMF_CODE.fd
       (`symlink`s to /usr/share/OVMF/OVMF_CODE.fd)
     - /usr/share/edk2/ovmf/OVMF_CODE.secboot.fd (`symlink`s to
       /usr/share/OVMF/OVMF_CODE.secboot.fd)
  - CentOS and RHEL:
     - /usr/share/OVMF/OVMF_CODE.secboot.fd
  - SUSE:
     - /usr/share/qemu/ovmf-x86_64-opensuse-code.bin

Currently, Nova only checks for one location OVMF_CODE.fd.  Let's also
check for the other two common distributions, SUSE and CentOS OVMF
binary paths.  This is a short-term solution to fix two bugs.

In the long run:

  - We will get rid of the "DEFAULT_UEFI_LOADER_PATH", which is used to
    probe for firmware file paths.  Instead, we'll use the more robust
    approach of the recently introduced[1] get_domain_capabilities()[1]
    to query for the firmware binary paths (as reported in the 'loader'
    attribute).

  - Use libvirt's (>=5.3) firmware auto-selection feature.  Which is a
    more robust way to decide UEFI boot (secure or otherwise).  More
    details of it in the spec here[2].

[1] https://opendev.org/openstack/nova/commit/297f3ba687 -- Add
    infrastructure for invoking libvirt's getDomainCapabilities API
[2] http://specs.openstack.org/openstack/nova-specs/specs/train/approved/allow-secure-boot-for-qemu-kvm-guests.html

Co-Authored-By: Kashyap Chamarthy <kchamart@redhat.com>
Closes-Bug: 1607400
Closes-Bug: 1825386
blueprint: allow-secure-boot-for-qemu-kvm-guests
Signed-off-by: Kashyap Chamarthy <kchamart@redhat.com>
Change-Id: I28afdb09d300be39981606d5234fd837ea738e1d
This commit is contained in:
Dirk Mueller
2016-07-28 16:39:19 +02:00
committed by Kashyap Chamarthy
parent 8ad437d142
commit 363710b655
2 changed files with 35 additions and 10 deletions

View File

@@ -6423,8 +6423,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
_fake_network_info(self, 1),
image_meta, disk_info)
self.assertTrue(mock_path_exists.called)
mock_path_exists.assert_called_with(
libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'])
mock_path_exists.assert_any_call(
libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'][0])
self.assertEqual(cfg.os_mach_type, "virt")
num_ports = 0
@@ -6468,8 +6468,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
cfg = self._get_guest_config_with_graphics()
self.assertTrue(mock_path_exists.called)
mock_path_exists.assert_called_with(
libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'])
mock_path_exists.assert_any_call(
libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'][0])
self.assertEqual(cfg.os_mach_type, "virt")
usbhost_exists = False

View File

@@ -139,8 +139,11 @@ DEFAULT_FIREWALL_DRIVER = "%s.%s" % (
libvirt_firewall.IptablesFirewallDriver.__name__)
DEFAULT_UEFI_LOADER_PATH = {
"x86_64": "/usr/share/OVMF/OVMF_CODE.fd",
"aarch64": "/usr/share/AAVMF/AAVMF_CODE.fd"
"x86_64": ['/usr/share/OVMF/OVMF_CODE.fd',
'/usr/share/OVMF/OVMF_CODE.secboot.fd',
'/usr/share/qemu/ovmf-x86_64-code.bin'],
"aarch64": ['/usr/share/AAVMF/AAVMF_CODE.fd',
'/usr/share/qemu/aavmf-aarch64-code.bin']
}
MAX_CONSOLE_BYTES = 100 * units.Ki
@@ -4959,12 +4962,33 @@ class LibvirtDriver(driver.ComputeDriver):
return instance.flavor
def _has_uefi_support(self):
# This means that the host can support uefi booting for guests
# This means that the host can support UEFI booting for guests
supported_archs = [fields.Architecture.X86_64,
fields.Architecture.AARCH64]
caps = self._host.get_capabilities()
# TODO(dmllr, kchamart): Get rid of probing the OVMF binary file
# paths, it is not robust, because nothing but the binary's
# filename is reported, which means you have to detect its
# architecture and features by other means. To solve this,
# query the libvirt's getDomainCapabilities() to get the
# firmware paths (as reported in the 'loader' value). Nova now
# has a wrapper method for this, get_domain_capabilities().
# This is a more reliable way to detect UEFI boot support.
#
# Further, with libvirt 5.3 onwards, support for UEFI boot is
# much more simplified by the "firmware auto-selection" feature.
# When using this, Nova doesn't need to query OVMF file paths at
# all; libvirt will take care of it. This is done by taking
# advantage of the so-called firmware "descriptor files" --
# small JSON files (which will be shipped by Linux
# distributions) that describe a UEFI firmware binary's
# "characteristics", such as the binary's file path, its
# features, architecture, supported machine type, NVRAM template
# and so forth.
return ((caps.host.cpu.arch in supported_archs) and
os.path.exists(DEFAULT_UEFI_LOADER_PATH[caps.host.cpu.arch]))
any((os.path.exists(p)
for p in DEFAULT_UEFI_LOADER_PATH[caps.host.cpu.arch])))
def _get_supported_perf_events(self):
@@ -5023,8 +5047,9 @@ class LibvirtDriver(driver.ComputeDriver):
"functional testing and therefore "
"considered experimental.")
uefi_logged = True
guest.os_loader = DEFAULT_UEFI_LOADER_PATH[
caps.host.cpu.arch]
for lpath in DEFAULT_UEFI_LOADER_PATH[caps.host.cpu.arch]:
if os.path.exists(lpath):
guest.os_loader = lpath
guest.os_loader_type = "pflash"
else:
raise exception.UEFINotSupported()