Add --virt-uefi to boot the VM using OVMF

This requires OVMF to be setup on the system, and for the kickstart to
create a /boot/efi/ partition. You can then use it to create UEFI
bootable partitioned disk images.

The UEFI firmware needs to be installed manually on the system, either
in the default location of /usr/share/OVMF/ or use --ovmf-path to point
to the location.

Resolves: rhbz#1546715
Resolves: rhbz#1544805
This commit is contained in:
Brian C. Lane 2015-11-03 18:03:09 -08:00
parent 22392b64fc
commit c8cee96b1c
2 changed files with 75 additions and 29 deletions

View File

@ -24,6 +24,7 @@ livemedia-creator [-h]
[--dracut-arg DRACUT_ARGS] [--title TITLE] [--dracut-arg DRACUT_ARGS] [--title TITLE]
[--project PROJECT] [--releasever RELEASEVER] [--project PROJECT] [--releasever RELEASEVER]
[--volid VOLID] [--squashfs_args SQUASHFS_ARGS] [--volid VOLID] [--squashfs_args SQUASHFS_ARGS]
[--virt-uefi] [--ovmf-path OVMF_PATH]
.SH DESCRIPTION .SH DESCRIPTION
livemedia-creator uses Anaconda, kickstart and Lorax to create bootable media livemedia-creator uses Anaconda, kickstart and Lorax to create bootable media
@ -223,6 +224,15 @@ Passed to --arch command
\fB\-\-kernel\-args KERNEL_ARGS\fR \fB\-\-kernel\-args KERNEL_ARGS\fR
Additional argument to pass to the installation kernel Additional argument to pass to the installation kernel
.TP
\fB\-\-virt\-uefi\fR
Boot the virtual machine in UEFI mode. Requires OVMF_CODE.fd and OVMF_VARS.fd
.TP
\fB\-\-ovmf\-path\fR
Path to OVMF_CODE.fd and OVMF_VARS.fd. Defaults to /usr/share/OVMF/, the UEFI
firmware files need to be installed manually, they are not shipped with RHEL.
.SH DRACUT ARGUMENTS: .SH DRACUT ARGUMENTS:
.TP .TP
\fB\-\-dracut\-arg DRACUT_ARGS\fR \fB\-\-dracut\-arg DRACUT_ARGS\fR

View File

@ -254,20 +254,27 @@ class VirtualInstall( object ):
def __init__( self, iso, ks_paths, disk_img, img_size=2, def __init__( self, iso, ks_paths, disk_img, img_size=2,
kernel_args=None, memory=1024, vnc=None, arch=None, kernel_args=None, memory=1024, vnc=None, arch=None,
log_check=None, virtio_host="127.0.0.1", virtio_port=6080, log_check=None, virtio_host="127.0.0.1", virtio_port=6080,
qcow2=False): qcow2=False, boot_uefi=False, ovmf_path=None):
""" """
Start the installation
iso is an instance of IsoMountpoint :param iso: Information about the iso to use for the installation
ks_paths is a list of paths to a kickstart files. All are injected, the :type iso: IsoMountpoint
:param list ks_paths: Paths to kickstart files. All are injected, the
first one is the one executed. first one is the one executed.
disk_img is the path to a disk image (doesn't need to exist) :param str disk_img: Path to a disk image, created it it doesn't exist
img_size is the size, in GiB, of the image if it doesn't exist :param int img_size: The image size, in MiB, to create if it doesn't exist
kernel_args are extra arguments to pass on the kernel cmdline :param str kernel_args: Extra kernel arguments to pass on the kernel cmdline
memory is the amount of ram to assign to the virt :param int memory: Amount of RAM to assign to the virt, in MiB
vnc is passed to the --graphics command verbatim :param str vnc: Arguments to pass to virt-install --graphics
arch is the optional architecture to use in the virt :param str arch: Optional architecture to use in the virt
log_check is a method that returns True of the log indicates an error :param log_check: Method that returns True if the installation fails
virtio_host and virtio_port are used to communicate with the log monitor :type log_check: method
:param str virtio_host: Hostname to connect virtio log to
:param int virtio_port: Port to connect virtio log to
:param bool qcow2: Set to True if disk_img is a qcow2
:param bool boot_uefi: Use OVMF to boot the VM in UEFI mode
:param str ovmf_path: Path to the OVMF firmware
""" """
self.virt_name = "LiveOS-"+str(uuid.uuid4()) self.virt_name = "LiveOS-"+str(uuid.uuid4())
# add --graphics none later # add --graphics none later
@ -325,9 +332,15 @@ class VirtualInstall( object ):
args.append("--arch") args.append("--arch")
args.append(arch) args.append(arch)
rc = execWithRedirect("virt-install", args) elif boot_uefi and ovmf_path:
if rc: args.append("--boot")
raise Exception("Problem starting virtual install") args.append("loader=%s/OVMF_CODE.fd,loader_ro=yes,loader_type=pflash,nvram_template=%s/OVMF_VARS.fd,loader_secure=no" % (ovmf_path, ovmf_path))
log.info("Running virt-install.")
try:
execWithRedirect("virt-install", args, raise_err=True)
except subprocess.CalledProcessError as e:
raise InstallError("Problem starting virtual install: %s" % e)
conn = libvirt.openReadOnly(None) conn = libvirt.openReadOnly(None)
dom = conn.lookupByName(self.virt_name) dom = conn.lookupByName(self.virt_name)
@ -354,7 +367,9 @@ class VirtualInstall( object ):
""" """
log.info( "Shutting down {0}".format(self.virt_name) ) log.info( "Shutting down {0}".format(self.virt_name) )
subprocess.call(["virsh", "destroy", self.virt_name]) subprocess.call(["virsh", "destroy", self.virt_name])
subprocess.call(["virsh", "undefine", self.virt_name])
# Undefine the virt, UEFI installs need to have --nvram passed
subprocess.call(["virsh", "undefine", self.virt_name, "--nvram"])
def is_image_mounted(disk_img): def is_image_mounted(disk_img):
""" """
@ -834,15 +849,22 @@ def virt_install(opts, install_log, disk_img, disk_size):
else: else:
diskimg_path = disk_img diskimg_path = disk_img
try:
virt = VirtualInstall(iso_mount, opts.ks, diskimg_path, disk_size, virt = VirtualInstall(iso_mount, opts.ks, diskimg_path, disk_size,
kernel_args, opts.ram, opts.vnc, opts.arch, kernel_args, opts.ram, opts.vnc, opts.arch,
log_check = log_monitor.server.log_check, log_check = log_monitor.server.log_check,
virtio_host = log_monitor.host, virtio_host = log_monitor.host,
virtio_port = log_monitor.port, virtio_port = log_monitor.port,
qcow2=opts.qcow2) qcow2=opts.qcow2, boot_uefi=opts.virt_uefi,
ovmf_path=opts.ovmf_path)
virt.destroy() virt.destroy()
log_monitor.shutdown() log_monitor.shutdown()
except InstallError as e:
log.error("VirtualInstall failed: %s", e)
raise
finally:
log.info("unmounting the iso")
iso_mount.umount() iso_mount.umount()
if log_monitor.server.log_check(): if log_monitor.server.log_check():
@ -1114,9 +1136,13 @@ if __name__ == '__main__':
virt_group.add_argument("--vnc", virt_group.add_argument("--vnc",
help="Passed to --graphics command" ) help="Passed to --graphics command" )
virt_group.add_argument("--arch", default=None, virt_group.add_argument("--arch", default=None,
help="Passed to --arch command" ) help="Passed to --arch command")
virt_group.add_argument( "--kernel-args", virt_group.add_argument("--kernel-args",
help="Additional argument to pass to the installation kernel" ) help="Additional argument to pass to the installation kernel")
virt_group.add_argument("--ovmf-path", default="/usr/share/OVMF/",
help="Path to OVMF firmware. Requires OVMF_CODE.fd and OVMF_VARS.fd")
virt_group.add_argument("--virt-uefi", action="store_true", default=False,
help="Use OVMF firmware to boot the VM in UEFI mode")
# dracut arguments # dracut arguments
dracut_group = parser.add_argument_group( "dracut arguments" ) dracut_group = parser.add_argument_group( "dracut arguments" )
@ -1232,6 +1258,16 @@ if __name__ == '__main__':
log.error("qcow2 cannot be used to make a bootable iso.") log.error("qcow2 cannot be used to make a bootable iso.")
sys.exit(1) sys.exit(1)
if opts.virt_uefi:
if not os.path.isdir(opts.ovmf_path):
log.error("The OVMF firmware is missing from %s", opts.ovmf_path)
sys.exit(1)
for f in ["OVMF_CODE.fd", "OVMF_VARS.fd"]:
if not os.path.exists(joinpaths(opts.ovmf_path, f)):
log.error("OVMF firmware file %s is missing from %s", f, opts.ovmf_path)
sys.exit(1)
# AMI image is just a fsimage with an AMI label # AMI image is just a fsimage with an AMI label
if opts.make_ami: if opts.make_ami:
opts.make_fsimage = True opts.make_fsimage = True