diff --git a/docs/livemedia-creator.1 b/docs/livemedia-creator.1 index fee6e5de..9967428d 100644 --- a/docs/livemedia-creator.1 +++ b/docs/livemedia-creator.1 @@ -24,6 +24,7 @@ livemedia-creator [-h] [--dracut-arg DRACUT_ARGS] [--title TITLE] [--project PROJECT] [--releasever RELEASEVER] [--volid VOLID] [--squashfs_args SQUASHFS_ARGS] + [--virt-uefi] [--ovmf-path OVMF_PATH] .SH DESCRIPTION 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 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: .TP \fB\-\-dracut\-arg DRACUT_ARGS\fR diff --git a/src/sbin/livemedia-creator b/src/sbin/livemedia-creator index 0ace1668..895dc56e 100755 --- a/src/sbin/livemedia-creator +++ b/src/sbin/livemedia-creator @@ -251,23 +251,30 @@ class VirtualInstall( object ): """ Run virt-install using an iso and kickstart(s) """ - 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, 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 - ks_paths is a list of paths to a kickstart files. All are injected, the - first one is the one executed. - disk_img is the path to a disk image (doesn't need to exist) - img_size is the size, in GiB, of the image if it doesn't exist - kernel_args are extra arguments to pass on the kernel cmdline - memory is the amount of ram to assign to the virt - vnc is passed to the --graphics command verbatim - arch is the optional architecture to use in the virt - log_check is a method that returns True of the log indicates an error - virtio_host and virtio_port are used to communicate with the log monitor + :param iso: Information about the iso to use for the installation + :type iso: IsoMountpoint + :param list ks_paths: Paths to kickstart files. All are injected, the + first one is the one executed. + :param str disk_img: Path to a disk image, created it it doesn't exist + :param int img_size: The image size, in MiB, to create if it doesn't exist + :param str kernel_args: Extra kernel arguments to pass on the kernel cmdline + :param int memory: Amount of RAM to assign to the virt, in MiB + :param str vnc: Arguments to pass to virt-install --graphics + :param str arch: Optional architecture to use in the virt + :param log_check: Method that returns True if the installation fails + :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()) # add --graphics none later @@ -325,9 +332,15 @@ class VirtualInstall( object ): args.append("--arch") args.append(arch) - rc = execWithRedirect("virt-install", args) - if rc: - raise Exception("Problem starting virtual install") + elif boot_uefi and ovmf_path: + args.append("--boot") + 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) dom = conn.lookupByName(self.virt_name) @@ -354,7 +367,9 @@ class VirtualInstall( object ): """ log.info( "Shutting down {0}".format(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): """ @@ -834,16 +849,23 @@ def virt_install(opts, install_log, disk_img, disk_size): else: diskimg_path = disk_img - virt = VirtualInstall(iso_mount, opts.ks, diskimg_path, disk_size, - kernel_args, opts.ram, opts.vnc, opts.arch, - log_check = log_monitor.server.log_check, - virtio_host = log_monitor.host, - virtio_port = log_monitor.port, - qcow2=opts.qcow2) + try: + virt = VirtualInstall(iso_mount, opts.ks, diskimg_path, disk_size, + kernel_args, opts.ram, opts.vnc, opts.arch, + log_check = log_monitor.server.log_check, + virtio_host = log_monitor.host, + virtio_port = log_monitor.port, + qcow2=opts.qcow2, boot_uefi=opts.virt_uefi, + ovmf_path=opts.ovmf_path) - virt.destroy() - log_monitor.shutdown() - iso_mount.umount() + virt.destroy() + log_monitor.shutdown() + except InstallError as e: + log.error("VirtualInstall failed: %s", e) + raise + finally: + log.info("unmounting the iso") + iso_mount.umount() if log_monitor.server.log_check(): raise InstallError("virt_install failed") @@ -1114,9 +1136,13 @@ if __name__ == '__main__': virt_group.add_argument("--vnc", help="Passed to --graphics command" ) virt_group.add_argument("--arch", default=None, - help="Passed to --arch command" ) - virt_group.add_argument( "--kernel-args", - help="Additional argument to pass to the installation kernel" ) + help="Passed to --arch command") + virt_group.add_argument("--kernel-args", + 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_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.") 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 if opts.make_ami: opts.make_fsimage = True