Add cancel_func to virt and novirt_install functions
In addition to monitoring the logs for errors, call a function (or functions) that tell it to cancel the anaconda process and cleanup. Also check for a cancel after creating the squashfs image for live-iso since that's a long running process. This required adding a new argument to a number of existing functions, passing it down to QEMUInstall and novirt_install where the function is called. Resolves: rhbz#1656691
This commit is contained in:
parent
a8f616c6da
commit
4b84475612
@ -245,7 +245,7 @@ def make_compose(cfg, results_dir):
|
|||||||
else:
|
else:
|
||||||
open(joinpaths(results_dir, install_cfg.image_name), "w").write("TEST IMAGE")
|
open(joinpaths(results_dir, install_cfg.image_name), "w").write("TEST IMAGE")
|
||||||
else:
|
else:
|
||||||
run_creator(install_cfg, callback_func=cancel_build)
|
run_creator(install_cfg, cancel_func=cancel_build)
|
||||||
|
|
||||||
# Extract the results of the compose into results_dir and cleanup the compose directory
|
# Extract the results of the compose into results_dir and cleanup the compose directory
|
||||||
move_compose_results(install_cfg, results_dir)
|
move_compose_results(install_cfg, results_dir)
|
||||||
|
@ -456,13 +456,15 @@ def calculate_disk_size(opts, ks):
|
|||||||
log.info("Using disk size of %sMiB", disk_size)
|
log.info("Using disk size of %sMiB", disk_size)
|
||||||
return disk_size
|
return disk_size
|
||||||
|
|
||||||
def make_image(opts, ks):
|
def make_image(opts, ks, cancel_func=None):
|
||||||
"""
|
"""
|
||||||
Install to a disk image
|
Install to a disk image
|
||||||
|
|
||||||
:param opts: options passed to livemedia-creator
|
:param opts: options passed to livemedia-creator
|
||||||
:type opts: argparse options
|
:type opts: argparse options
|
||||||
:param str ks: Path to the kickstart to use for the installation
|
:param str ks: Path to the kickstart to use for the installation
|
||||||
|
:param cancel_func: Function that returns True to cancel build
|
||||||
|
:type cancel_func: function
|
||||||
:returns: Path of the image created
|
:returns: Path of the image created
|
||||||
:rtype: str
|
:rtype: str
|
||||||
|
|
||||||
@ -476,12 +478,12 @@ def make_image(opts, ks):
|
|||||||
disk_size = calculate_disk_size(opts, ks)
|
disk_size = calculate_disk_size(opts, ks)
|
||||||
try:
|
try:
|
||||||
if opts.no_virt:
|
if opts.no_virt:
|
||||||
novirt_install(opts, disk_img, disk_size)
|
novirt_install(opts, disk_img, disk_size, cancel_func=cancel_func)
|
||||||
else:
|
else:
|
||||||
install_log = os.path.abspath(os.path.dirname(opts.logfile))+"/virt-install.log"
|
install_log = os.path.abspath(os.path.dirname(opts.logfile))+"/virt-install.log"
|
||||||
log.info("install_log = %s", install_log)
|
log.info("install_log = %s", install_log)
|
||||||
|
|
||||||
virt_install(opts, install_log, disk_img, disk_size)
|
virt_install(opts, install_log, disk_img, disk_size, cancel_func=cancel_func)
|
||||||
except InstallError as e:
|
except InstallError as e:
|
||||||
log.error("Install failed: %s", e)
|
log.error("Install failed: %s", e)
|
||||||
if not opts.keep_image and os.path.exists(disk_img):
|
if not opts.keep_image and os.path.exists(disk_img):
|
||||||
@ -576,11 +578,13 @@ def make_live_images(opts, work_dir, disk_img):
|
|||||||
|
|
||||||
return work_dir
|
return work_dir
|
||||||
|
|
||||||
def run_creator(opts, callback_func=None):
|
def run_creator(opts, cancel_func=None):
|
||||||
"""Run the image creator process
|
"""Run the image creator process
|
||||||
|
|
||||||
:param opts: Commandline options to control the process
|
:param opts: Commandline options to control the process
|
||||||
:type opts: Either a DataHolder or ArgumentParser
|
:type opts: Either a DataHolder or ArgumentParser
|
||||||
|
:param cancel_func: Function that returns True to cancel build
|
||||||
|
:type cancel_func: function
|
||||||
:returns: The result directory and the disk image path.
|
:returns: The result directory and the disk image path.
|
||||||
:rtype: Tuple of str
|
:rtype: Tuple of str
|
||||||
|
|
||||||
@ -639,7 +643,7 @@ def run_creator(opts, callback_func=None):
|
|||||||
|
|
||||||
# Make the image. Output of this is either a partitioned disk image or a fsimage
|
# Make the image. Output of this is either a partitioned disk image or a fsimage
|
||||||
try:
|
try:
|
||||||
disk_img = make_image(opts, ks)
|
disk_img = make_image(opts, ks, cancel_func=cancel_func)
|
||||||
except InstallError as e:
|
except InstallError as e:
|
||||||
log.error("ERROR: Image creation failed: %s", e)
|
log.error("ERROR: Image creation failed: %s", e)
|
||||||
raise RuntimeError("Image creation failed: %s" % e)
|
raise RuntimeError("Image creation failed: %s" % e)
|
||||||
@ -659,6 +663,9 @@ def run_creator(opts, callback_func=None):
|
|||||||
log.error("squashfs.img creation failed")
|
log.error("squashfs.img creation failed")
|
||||||
raise RuntimeError("squashfs.img creation failed")
|
raise RuntimeError("squashfs.img creation failed")
|
||||||
|
|
||||||
|
if cancel_func():
|
||||||
|
raise RuntimeError("ISO creation canceled")
|
||||||
|
|
||||||
with Mount(disk_img, opts="loop") as mount_dir:
|
with Mount(disk_img, opts="loop") as mount_dir:
|
||||||
result_dir = make_livecd(opts, mount_dir, work_dir)
|
result_dir = make_livecd(opts, mount_dir, work_dir)
|
||||||
else:
|
else:
|
||||||
|
@ -137,7 +137,7 @@ class QEMUInstall(object):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048,
|
def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048,
|
||||||
kernel_args=None, memory=1024, vcpus=None, vnc=None, arch=None,
|
kernel_args=None, memory=1024, vcpus=None, vnc=None, arch=None,
|
||||||
log_check=None, virtio_host="127.0.0.1", virtio_port=6080,
|
cancel_func=None, virtio_host="127.0.0.1", virtio_port=6080,
|
||||||
image_type=None, boot_uefi=False, ovmf_path=None):
|
image_type=None, boot_uefi=False, ovmf_path=None):
|
||||||
"""
|
"""
|
||||||
Start the installation
|
Start the installation
|
||||||
@ -153,8 +153,8 @@ class QEMUInstall(object):
|
|||||||
:param int vcpus: Number of virtual cpus
|
:param int vcpus: Number of virtual cpus
|
||||||
:param str vnc: Arguments to pass to qemu -display
|
:param str vnc: Arguments to pass to qemu -display
|
||||||
:param str arch: Optional architecture to use in the virt
|
:param str arch: Optional architecture to use in the virt
|
||||||
:param log_check: Method that returns True if the installation fails
|
:param cancel_func: Function that returns True if the installation fails
|
||||||
:type log_check: method
|
:type cancel_func: function
|
||||||
:param str virtio_host: Hostname to connect virtio log to
|
:param str virtio_host: Hostname to connect virtio log to
|
||||||
:param int virtio_port: Port to connect virtio log to
|
:param int virtio_port: Port to connect virtio log to
|
||||||
:param str image_type: Type of qemu-img disk to create, or None.
|
:param str image_type: Type of qemu-img disk to create, or None.
|
||||||
@ -243,7 +243,7 @@ class QEMUInstall(object):
|
|||||||
log.debug(qemu_cmd)
|
log.debug(qemu_cmd)
|
||||||
try:
|
try:
|
||||||
execWithRedirect(qemu_cmd[0], qemu_cmd[1:], reset_lang=False, raise_err=True,
|
execWithRedirect(qemu_cmd[0], qemu_cmd[1:], reset_lang=False, raise_err=True,
|
||||||
callback=lambda p: not log_check())
|
callback=lambda p: not cancel_func())
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
log.error("Running qemu failed:")
|
log.error("Running qemu failed:")
|
||||||
log.error("cmd: %s", " ".join(e.cmd))
|
log.error("cmd: %s", " ".join(e.cmd))
|
||||||
@ -257,25 +257,28 @@ class QEMUInstall(object):
|
|||||||
if boot_uefi and ovmf_path:
|
if boot_uefi and ovmf_path:
|
||||||
os.unlink(ovmf_vars)
|
os.unlink(ovmf_vars)
|
||||||
|
|
||||||
if log_check():
|
if cancel_func():
|
||||||
log.error("Installation error detected. See logfile for details.")
|
log.error("Installation error detected. See logfile for details.")
|
||||||
raise InstallError("QEMUInstall failed")
|
raise InstallError("QEMUInstall failed")
|
||||||
else:
|
else:
|
||||||
log.info("Installation finished without errors.")
|
log.info("Installation finished without errors.")
|
||||||
|
|
||||||
|
|
||||||
def novirt_log_check(log_check, proc):
|
def novirt_cancel_check(cancel_funcs, proc):
|
||||||
"""
|
"""
|
||||||
Check to see if there has been an error in the logs
|
Check to see if there has been an error in the logs
|
||||||
|
|
||||||
:param log_check: method to call to check for an error in the logs
|
:param cancel_funcs: list of functions to call, True from any one cancels the build
|
||||||
|
:type cancel_funcs: list
|
||||||
:param proc: Popen object for the anaconda process
|
:param proc: Popen object for the anaconda process
|
||||||
|
:type proc: subprocess.Popen
|
||||||
:returns: True if the process has been terminated
|
:returns: True if the process has been terminated
|
||||||
|
|
||||||
The log_check method should return a True if an error has been detected.
|
The cancel_funcs functions should return a True if an error has been detected.
|
||||||
When an error is detected the process is terminated and this returns True
|
When an error is detected the process is terminated and this returns True
|
||||||
"""
|
"""
|
||||||
if log_check():
|
for f in cancel_funcs:
|
||||||
|
if f():
|
||||||
proc.terminate()
|
proc.terminate()
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -308,7 +311,7 @@ def anaconda_cleanup(dirinstall_path):
|
|||||||
return rc
|
return rc
|
||||||
|
|
||||||
|
|
||||||
def novirt_install(opts, disk_img, disk_size):
|
def novirt_install(opts, disk_img, disk_size, cancel_func=None):
|
||||||
"""
|
"""
|
||||||
Use Anaconda to install to a disk image
|
Use Anaconda to install to a disk image
|
||||||
|
|
||||||
@ -316,6 +319,8 @@ def novirt_install(opts, disk_img, disk_size):
|
|||||||
:type opts: argparse options
|
:type opts: argparse options
|
||||||
:param str disk_img: The full path to the disk image to be created
|
:param str disk_img: The full path to the disk image to be created
|
||||||
:param int disk_size: The size of the disk_img in MiB
|
:param int disk_size: The size of the disk_img in MiB
|
||||||
|
:param cancel_func: Function that returns True to cancel build
|
||||||
|
:type cancel_func: function
|
||||||
|
|
||||||
This method runs anaconda to create the image and then based on the opts
|
This method runs anaconda to create the image and then based on the opts
|
||||||
passed creates a qemu disk image or tarfile.
|
passed creates a qemu disk image or tarfile.
|
||||||
@ -365,6 +370,9 @@ def novirt_install(opts, disk_img, disk_size):
|
|||||||
|
|
||||||
log_monitor = LogMonitor(timeout=opts.timeout)
|
log_monitor = LogMonitor(timeout=opts.timeout)
|
||||||
args += ["--remotelog", "%s:%s" % (log_monitor.host, log_monitor.port)]
|
args += ["--remotelog", "%s:%s" % (log_monitor.host, log_monitor.port)]
|
||||||
|
cancel_funcs = [log_monitor.server.log_check]
|
||||||
|
if cancel_func is not None:
|
||||||
|
cancel_funcs.append(cancel_func)
|
||||||
|
|
||||||
# Make sure anaconda has the right product and release
|
# Make sure anaconda has the right product and release
|
||||||
log.info("Running anaconda.")
|
log.info("Running anaconda.")
|
||||||
@ -372,7 +380,7 @@ def novirt_install(opts, disk_img, disk_size):
|
|||||||
for line in execReadlines("anaconda", args, reset_lang=False,
|
for line in execReadlines("anaconda", args, reset_lang=False,
|
||||||
env_add={"ANACONDA_PRODUCTNAME": opts.project,
|
env_add={"ANACONDA_PRODUCTNAME": opts.project,
|
||||||
"ANACONDA_PRODUCTVERSION": opts.releasever},
|
"ANACONDA_PRODUCTVERSION": opts.releasever},
|
||||||
callback=lambda p: not novirt_log_check(log_monitor.server.log_check, p)):
|
callback=lambda p: not novirt_cancel_check(cancel_funcs, p)):
|
||||||
log.info(line)
|
log.info(line)
|
||||||
|
|
||||||
# Make sure the new filesystem is correctly labeled
|
# Make sure the new filesystem is correctly labeled
|
||||||
@ -418,10 +426,14 @@ def novirt_install(opts, disk_img, disk_size):
|
|||||||
|
|
||||||
if not opts.make_iso and not opts.make_fsimage and not opts.make_pxe_live:
|
if not opts.make_iso and not opts.make_fsimage and not opts.make_pxe_live:
|
||||||
dm_name = os.path.splitext(os.path.basename(disk_img))[0]
|
dm_name = os.path.splitext(os.path.basename(disk_img))[0]
|
||||||
dm_path = "/dev/mapper/"+dm_name
|
|
||||||
if os.path.exists(dm_path):
|
# Remove device-mapper for partitions and disk
|
||||||
dm_detach(dm_path)
|
log.debug("Removing device-mapper setup on %s", dm_name)
|
||||||
loop_detach(get_loop_name(disk_img))
|
for d in sorted(glob.glob("/dev/mapper/"+dm_name+"*"), reverse=True):
|
||||||
|
dm_detach(d)
|
||||||
|
|
||||||
|
log.debug("Removing loop device for %s", disk_img)
|
||||||
|
loop_detach("/dev/"+get_loop_name(disk_img))
|
||||||
|
|
||||||
# qemu disk image is used by bare qcow2 images and by Vagrant
|
# qemu disk image is used by bare qcow2 images and by Vagrant
|
||||||
if opts.image_type:
|
if opts.image_type:
|
||||||
@ -487,7 +499,7 @@ def novirt_install(opts, disk_img, disk_size):
|
|||||||
execWithRedirect("fallocate", ["--dig-holes", disk_img], raise_err=True)
|
execWithRedirect("fallocate", ["--dig-holes", disk_img], raise_err=True)
|
||||||
|
|
||||||
|
|
||||||
def virt_install(opts, install_log, disk_img, disk_size):
|
def virt_install(opts, install_log, disk_img, disk_size, cancel_func=None):
|
||||||
"""
|
"""
|
||||||
Use qemu to install to a disk image
|
Use qemu to install to a disk image
|
||||||
|
|
||||||
@ -496,6 +508,8 @@ def virt_install(opts, install_log, disk_img, disk_size):
|
|||||||
:param str install_log: The path to write the log from qemu
|
:param str install_log: The path to write the log from qemu
|
||||||
:param str disk_img: The full path to the disk image to be created
|
:param str disk_img: The full path to the disk image to be created
|
||||||
:param int disk_size: The size of the disk_img in MiB
|
:param int disk_size: The size of the disk_img in MiB
|
||||||
|
:param cancel_func: Function that returns True to cancel build
|
||||||
|
:type cancel_func: function
|
||||||
|
|
||||||
This uses qemu with a boot.iso and a kickstart to create a disk
|
This uses qemu with a boot.iso and a kickstart to create a disk
|
||||||
image and then optionally, based on the opts passed, creates tarfile.
|
image and then optionally, based on the opts passed, creates tarfile.
|
||||||
@ -506,6 +520,9 @@ def virt_install(opts, install_log, disk_img, disk_size):
|
|||||||
raise InstallError("ISO is missing stage2, cannot continue")
|
raise InstallError("ISO is missing stage2, cannot continue")
|
||||||
|
|
||||||
log_monitor = LogMonitor(install_log, timeout=opts.timeout)
|
log_monitor = LogMonitor(install_log, timeout=opts.timeout)
|
||||||
|
cancel_funcs = [log_monitor.server.log_check]
|
||||||
|
if cancel_func is not None:
|
||||||
|
cancel_funcs.append(cancel_func)
|
||||||
|
|
||||||
kernel_args = ""
|
kernel_args = ""
|
||||||
if opts.kernel_args:
|
if opts.kernel_args:
|
||||||
@ -530,7 +547,7 @@ def virt_install(opts, install_log, disk_img, disk_size):
|
|||||||
try:
|
try:
|
||||||
QEMUInstall(opts, iso_mount, opts.ks, diskimg_path, disk_size,
|
QEMUInstall(opts, iso_mount, opts.ks, diskimg_path, disk_size,
|
||||||
kernel_args, opts.ram, opts.vcpus, opts.vnc, opts.arch,
|
kernel_args, opts.ram, opts.vcpus, opts.vnc, opts.arch,
|
||||||
log_check = log_monitor.server.log_check,
|
cancel_func = lambda : any(f() for f in cancel_funcs),
|
||||||
virtio_host = log_monitor.host,
|
virtio_host = log_monitor.host,
|
||||||
virtio_port = log_monitor.port,
|
virtio_port = log_monitor.port,
|
||||||
image_type=opts.image_type, boot_uefi=opts.virt_uefi,
|
image_type=opts.image_type, boot_uefi=opts.virt_uefi,
|
||||||
@ -549,6 +566,8 @@ def virt_install(opts, install_log, disk_img, disk_size):
|
|||||||
else:
|
else:
|
||||||
msg = "virt_install failed on line: %s" % log_monitor.server.error_line
|
msg = "virt_install failed on line: %s" % log_monitor.server.error_line
|
||||||
raise InstallError(msg)
|
raise InstallError(msg)
|
||||||
|
elif cancel_func():
|
||||||
|
raise InstallError("virt_install canceled by cancel_func")
|
||||||
|
|
||||||
if opts.make_fsimage:
|
if opts.make_fsimage:
|
||||||
mkfsimage_from_disk(diskimg_path, disk_img, disk_size, label=opts.fs_label)
|
mkfsimage_from_disk(diskimg_path, disk_img, disk_size, label=opts.fs_label)
|
||||||
|
Loading…
Reference in New Issue
Block a user