From 322a810403449118116fc9ea868bb3e1ed5e717c Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Mon, 24 May 2021 13:44:31 -0700 Subject: [PATCH] Add a context manager for dracut dracut needs a reasonable chroot environment in order to run correctly. This adds the DracutChroot context manager that sets up and tears down mounts inside the root directory tree. Switch to using it in creator.rebuild_initrds_for_live() and TreeBuilder.rebuild_initrds() --- src/pylorax/creator.py | 35 +++++++++++++-------------------- src/pylorax/imgutils.py | 36 ++++++++++++++++++++++++++++++++++ src/pylorax/treebuilder.py | 40 +++++++++++++++++++------------------- 3 files changed, 70 insertions(+), 41 deletions(-) diff --git a/src/pylorax/creator.py b/src/pylorax/creator.py index 73f5f1ba..c510b100 100644 --- a/src/pylorax/creator.py +++ b/src/pylorax/creator.py @@ -36,8 +36,8 @@ from pykickstart.version import makeVersion # Use the Lorax treebuilder branch for iso creation from pylorax import ArchData from pylorax.base import DataHolder -from pylorax.executils import execWithRedirect, runcmd -from pylorax.imgutils import PartitionMount +from pylorax.executils import execWithRedirect +from pylorax.imgutils import DracutChroot, PartitionMount from pylorax.imgutils import mount, umount, Mount from pylorax.imgutils import mksquashfs, mkrootfsimg from pylorax.imgutils import copytree @@ -243,7 +243,7 @@ def rebuild_initrds_for_live(opts, sys_root_dir, results_dir): # cmdline dracut args override the defaults, but need to be parsed log.info("dracut args = %s", dracut_args(opts)) - dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + dracut_args(opts) + args = ["--nomdadmconf", "--nolvmconf"] + dracut_args(opts) kdir = "boot" if opts.ostree: @@ -272,25 +272,18 @@ def rebuild_initrds_for_live(opts, sys_root_dir, results_dir): # Write the new initramfs directly to the results directory os.mkdir(joinpaths(sys_root_dir, "results")) - mount(results_dir, opts="bind", mnt=joinpaths(sys_root_dir, "results")) - # Dracut runs out of space inside the minimal rootfs image - mount("/var/tmp", opts="bind", mnt=joinpaths(sys_root_dir, "var/tmp")) - for kernel in kernels: - if hasattr(kernel, "initrd"): - outfile = os.path.basename(kernel.initrd.path) - else: - # Construct an initrd from the kernel name - outfile = os.path.basename(kernel.path.replace("vmlinuz-", "initrd-") + ".img") - log.info("rebuilding %s", outfile) - log.info("dracut warnings about /proc are safe to ignore") + with DracutChroot(sys_root_dir, bind=[(results_dir, "/results")]) as dracut: + for kernel in kernels: + if hasattr(kernel, "initrd"): + outfile = os.path.basename(kernel.initrd.path) + else: + # Construct an initrd from the kernel name + outfile = os.path.basename(kernel.path.replace("vmlinuz-", "initrd-") + ".img") + log.info("rebuilding %s", outfile) - kver = kernel.version - cmd = dracut + ["/results/"+outfile, kver] - runcmd(cmd, root=sys_root_dir) - - shutil.copy2(joinpaths(sys_root_dir, kernel.path), results_dir) - umount(joinpaths(sys_root_dir, "var/tmp"), delete=False) - umount(joinpaths(sys_root_dir, "results"), delete=False) + kver = kernel.version + dracut.Run(args + ["/results/"+outfile, kver]) + shutil.copy2(joinpaths(sys_root_dir, kernel.path), results_dir) def create_pxe_config(template, images_dir, live_image_name, add_args = None): """ diff --git a/src/pylorax/imgutils.py b/src/pylorax/imgutils.py index 13d9b280..d713e4c1 100644 --- a/src/pylorax/imgutils.py +++ b/src/pylorax/imgutils.py @@ -473,6 +473,42 @@ class PartitionMount(object): execWithRedirect("kpartx", ["-d", "-s", self.disk_img]) +class DracutChroot(object): + """Setup the chroot for running dracut inside it, cleanup when done + + This mount /proc, /dev, and /var/tmp plus optional bind mounted directories + as a list of (source, destination) tuples where destination is relative to the chroot. + """ + def __init__(self, root, bind=None): + self.root = root + self.bind = [("/var/tmp", "/var/tmp")] + (bind if bind else []) + + def __enter__(self): + for d in [d for _, d in self.bind] + ["/proc", "/dev"]: + if not os.path.exists(self.root + d): + logger.warning("Making missing dracut chroot directory: %s", d) + os.makedirs(self.root + d) + + runcmd(["mount", "-t", "proc", "-o", "nosuid,noexec,nodev", "proc", self.root + "/proc" ]) + runcmd(["mount", "-t", "devtmpfs", "-o", "mode=0755,noexec,nosuid,strictatime", "devtmpfs", self.root + "/dev" ]) + + for s, d in self.bind: + runcmd(["mount", "-o", "bind", s, self.root + d]) + + return self + + def __exit__(self, exc_type, exc_value, tracebk): + runcmd(["umount", self.root + "/proc" ]) + runcmd(["umount", self.root + "/dev" ]) + + # cleanup bind mounts + for _, d in self.bind: + runcmd(["umount", self.root + d ]) + + def Run(self, args): + runcmd(["dracut"] + args, root=self.root) + + ######## Functions for making filesystem images ########################## def mkfsimage(fstype, rootdir, outfile, size=None, mkfsargs=None, mountargs="", graft=None): diff --git a/src/pylorax/treebuilder.py b/src/pylorax/treebuilder.py index d57370d3..bc93d4f7 100644 --- a/src/pylorax/treebuilder.py +++ b/src/pylorax/treebuilder.py @@ -31,6 +31,7 @@ from pylorax.sysutils import joinpaths, remove from pylorax.base import DataHolder from pylorax.ltmpl import LoraxTemplateRunner import pylorax.imgutils as imgutils +from pylorax.imgutils import DracutChroot from pylorax.executils import runcmd, runcmd_output, execWithCapture templatemap = { @@ -310,32 +311,31 @@ class TreeBuilder(object): name of the kernel. ''' add_args = add_args or [] - dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + add_args + args = ["--nomdadmconf", "--nolvmconf"] + add_args if not backup: - dracut.append("--force") + args.append("--force") if not self.kernels: raise Exception("No kernels found, cannot rebuild_initrds") - for kernel in self.kernels: - if prefix: - idir = os.path.dirname(kernel.path) - outfile = joinpaths(idir, prefix+'-'+kernel.version+'.img') - elif hasattr(kernel, "initrd"): - # If there is an existing initrd, use that - outfile = kernel.initrd.path - else: - # Construct an initrd from the kernel name - outfile = kernel.path.replace("vmlinuz-", "initrd-") + ".img" - logger.info("rebuilding %s", outfile) - logger.info("dracut warnings about /proc are safe to ignore") + with DracutChroot(self.vars.inroot) as dracut: + for kernel in self.kernels: + if prefix: + idir = os.path.dirname(kernel.path) + outfile = joinpaths(idir, prefix+'-'+kernel.version+'.img') + elif hasattr(kernel, "initrd"): + # If there is an existing initrd, use that + outfile = kernel.initrd.path + else: + # Construct an initrd from the kernel name + outfile = kernel.path.replace("vmlinuz-", "initrd-") + ".img" + logger.info("rebuilding %s", outfile) - if backup: - initrd = joinpaths(self.vars.inroot, outfile) - if os.path.exists(initrd): - os.rename(initrd, initrd + backup) - cmd = dracut + [outfile, kernel.version] - runcmd(cmd, root=self.vars.inroot) + if backup: + initrd = joinpaths(self.vars.inroot, outfile) + if os.path.exists(initrd): + os.rename(initrd, initrd + backup) + dracut.Run(args + [outfile, kernel.version]) def build(self): templatefile = templatemap[self.vars.arch.basearch]