enable uefi boot

This patch enables uefi boot with the libvirt driver. This feature
is without some kind of functional testing and therefore
considered experimental.

Co-Authored-By: XinXiaohui <xiaohui.xin@intel.com>

Change-Id: I9d8b2896e4bd29f67ebab6ce1bc927aae271c3e7
Implements: blueprint boot-from-uefi
This commit is contained in:
Qiaowei Ren 2016-01-02 09:20:16 +08:00
parent 3d4c8edd6b
commit 9e2dfb61ed
6 changed files with 126 additions and 1 deletions

View File

@ -2034,6 +2034,10 @@ class RequestSpecNotFound(NotFound):
msg_fmt = _("RequestSpec not found for instance %(instance_uuid)s")
class UEFINotSupported(Invalid):
msg_fmt = _("UEFI is not supported")
class NMINotSupported(Invalid):
msg_fmt = _("Injecting NMI is not supported")

View File

@ -1792,6 +1792,31 @@ class LibvirtConfigGuestTest(LibvirtConfigBaseTest):
</devices>
</domain>""")
def test_config_uefi(self):
obj = config.LibvirtConfigGuest()
obj.virt_type = "kvm"
obj.memory = 100 * units.Mi
obj.vcpus = 1
obj.name = "uefi"
obj.uuid = "f01cf68d-515c-4daf-b85f-ef1424d93bfc"
obj.os_type = "x86_64"
obj.os_loader = '/tmp/OVMF.fd'
obj.os_loader_type = 'pflash'
xml = obj.to_xml()
self.assertXmlEqual(xml, """
<domain type="kvm">
<uuid>f01cf68d-515c-4daf-b85f-ef1424d93bfc</uuid>
<name>uefi</name>
<memory>104857600</memory>
<vcpu>1</vcpu>
<os>
<type>x86_64</type>
<loader readonly='yes' type='pflash'>/tmp/OVMF.fd</loader>
<nvram template="/tmp/OVMF.fd"></nvram>
</os>
</domain>""")
def test_config_boot_menu(self):
obj = config.LibvirtConfigGuest()
obj.virt_type = "kvm"

View File

@ -2632,6 +2632,56 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.assertIsInstance(cfg.devices[2],
vconfig.LibvirtConfigGuestConsole)
def test_has_uefi_support_with_invalid_version(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
with mock.patch.object(drvr._host,
'has_min_version', return_value=False):
self.assertFalse(drvr._has_uefi_support())
def test_has_uefi_support_not_supported_arch(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
caps = vconfig.LibvirtConfigCaps()
caps.host = vconfig.LibvirtConfigCapsHost()
caps.host.cpu = vconfig.LibvirtConfigCPU()
caps.host.cpu.arch = "alpha"
self.assertFalse(drvr._has_uefi_support())
@mock.patch('os.path.exists', return_value=False)
def test_has_uefi_support_with_no_loader_existed(self, mock_exist):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
self.assertFalse(drvr._has_uefi_support())
@mock.patch('os.path.exists', return_value=True)
def test_has_uefi_support(self, mock_has_version):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
caps = vconfig.LibvirtConfigCaps()
caps.host = vconfig.LibvirtConfigCapsHost()
caps.host.cpu = vconfig.LibvirtConfigCPU()
caps.host.cpu.arch = "x86_64"
with mock.patch.object(drvr._host,
'has_min_version', return_value=True):
self.assertTrue(drvr._has_uefi_support())
def test_get_guest_config_with_uefi(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
image_meta = objects.ImageMeta.from_dict({
"disk_format": "raw",
"properties": {"hw_firmware_type": "uefi"}})
instance_ref = objects.Instance(**self.test_instance)
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance_ref,
image_meta)
with test.nested(
mock.patch.object(drvr, "_has_uefi_support",
return_value=True)):
cfg = drvr._get_guest_config(instance_ref, [],
image_meta, disk_info)
self.assertEqual(cfg.os_loader_type, "pflash")
def test_get_guest_config_with_block_device(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)

View File

@ -1858,6 +1858,7 @@ class LibvirtConfigGuest(LibvirtConfigObject):
self.sysinfo = None
self.os_type = None
self.os_loader = None
self.os_loader_type = None
self.os_kernel = None
self.os_initrd = None
self.os_cmdline = None
@ -1903,7 +1904,17 @@ class LibvirtConfigGuest(LibvirtConfigObject):
if self.os_kernel is not None:
os.append(self._text_node("kernel", self.os_kernel))
if self.os_loader is not None:
os.append(self._text_node("loader", self.os_loader))
# Generate XML nodes for UEFI boot.
if self.os_loader_type == "pflash":
loader = self._text_node("loader", self.os_loader)
loader.set("type", "pflash")
loader.set("readonly", "yes")
os.append(loader)
nvram = self._text_node("nvram", "")
nvram.set("template", self.os_loader)
os.append(nvram)
else:
os.append(self._text_node("loader", self.os_loader))
if self.os_initrd is not None:
os.append(self._text_node("initrd", self.os_initrd))
if self.os_cmdline is not None:

View File

@ -114,6 +114,8 @@ from nova.volume import encryptors
libvirt = None
uefi_logged = False
LOG = logging.getLogger(__name__)
# Downtime period in milliseconds
@ -307,6 +309,11 @@ DEFAULT_FIREWALL_DRIVER = "%s.%s" % (
libvirt_firewall.__name__,
libvirt_firewall.IptablesFirewallDriver.__name__)
DEFAULT_UEFI_LOADER_PATH = {
"x86_64": "/usr/share/OVMF/OVMF_CODE.fd",
"aarch64": "/usr/share/AAVMF/AAVMF_CODE.fd"
}
MAX_CONSOLE_BYTES = 100 * units.Ki
# The libvirt driver will prefix any disable reason codes with this string.
@ -422,6 +429,9 @@ MIN_QEMU_NUMA_HUGEPAGE_VERSION = (2, 1, 0)
# fsFreeze/fsThaw requirement
MIN_LIBVIRT_FSFREEZE_VERSION = (1, 2, 5)
# UEFI booting support
MIN_LIBVIRT_UEFI_VERSION = (1, 2, 9)
# Hyper-V paravirtualized time source
MIN_LIBVIRT_HYPERV_TIMER_VERSION = (1, 2, 2)
MIN_QEMU_HYPERV_TIMER_VERSION = (2, 0, 0)
@ -4118,6 +4128,14 @@ class LibvirtDriver(driver.ComputeDriver):
return flavor
return instance.flavor
def _has_uefi_support(self):
# This means that the host can support uefi booting for guests
supported_archs = [arch.X86_64, arch.AARCH64]
caps = self._host.get_capabilities()
return ((caps.host.cpu.arch in supported_archs) and
self._host.has_min_version(MIN_LIBVIRT_UEFI_VERSION) and
os.path.exists(DEFAULT_UEFI_LOADER_PATH[caps.host.cpu.arch]))
def _configure_guest_by_virt_type(self, guest, virt_type, caps, instance,
image_meta, flavor, root_device_name):
if virt_type == "xen":
@ -4127,6 +4145,20 @@ class LibvirtDriver(driver.ComputeDriver):
if caps.host.cpu.arch in (arch.I686, arch.X86_64):
guest.sysinfo = self._get_guest_config_sysinfo(instance)
guest.os_smbios = vconfig.LibvirtConfigGuestSMBIOS()
hw_firmware_type = image_meta.properties.get('hw_firmware_type')
if hw_firmware_type == fields.FirmwareType.UEFI:
if self._has_uefi_support():
global uefi_logged
if not uefi_logged:
LOG.warn(_LW("uefi support is without some kind of "
"functional testing and therefore "
"considered experimental."))
uefi_logged = True
guest.os_loader = DEFAULT_UEFI_LOADER_PATH[
caps.host.cpu.arch]
guest.os_loader_type = "pflash"
else:
raise exception.UEFINotSupported()
guest.os_mach_type = self._get_machine_type(image_meta, caps)
if image_meta.properties.get('hw_boot_menu') is None:
guest.os_bootmenu = strutils.bool_from_string(

View File

@ -0,0 +1,3 @@
---
features:
- Add support for enabling uefi boot with libvirt.