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()

(cherry picked from commit 322a810403)

Resolves: rhbz#1982271
This commit is contained in:
Brian C. Lane 2021-05-24 13:44:31 -07:00
parent 9f8df6b76c
commit 0485ef22f2
3 changed files with 70 additions and 41 deletions

View File

@ -36,8 +36,8 @@ from pykickstart.version import makeVersion
# Use the Lorax treebuilder branch for iso creation # Use the Lorax treebuilder branch for iso creation
from pylorax import ArchData from pylorax import ArchData
from pylorax.base import DataHolder from pylorax.base import DataHolder
from pylorax.executils import execWithRedirect, runcmd from pylorax.executils import execWithRedirect
from pylorax.imgutils import PartitionMount from pylorax.imgutils import DracutChroot, PartitionMount
from pylorax.imgutils import mount, umount, Mount from pylorax.imgutils import mount, umount, Mount
from pylorax.imgutils import mksquashfs, mkrootfsimg from pylorax.imgutils import mksquashfs, mkrootfsimg
from pylorax.imgutils import copytree 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 # cmdline dracut args override the defaults, but need to be parsed
log.info("dracut args = %s", dracut_args(opts)) log.info("dracut args = %s", dracut_args(opts))
dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + dracut_args(opts) args = ["--nomdadmconf", "--nolvmconf"] + dracut_args(opts)
kdir = "boot" kdir = "boot"
if opts.ostree: 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 # Write the new initramfs directly to the results directory
os.mkdir(joinpaths(sys_root_dir, "results")) os.mkdir(joinpaths(sys_root_dir, "results"))
mount(results_dir, opts="bind", mnt=joinpaths(sys_root_dir, "results")) with DracutChroot(sys_root_dir, bind=[(results_dir, "/results")]) as dracut:
# Dracut runs out of space inside the minimal rootfs image for kernel in kernels:
mount("/var/tmp", opts="bind", mnt=joinpaths(sys_root_dir, "var/tmp")) if hasattr(kernel, "initrd"):
for kernel in kernels: outfile = os.path.basename(kernel.initrd.path)
if hasattr(kernel, "initrd"): else:
outfile = os.path.basename(kernel.initrd.path) # Construct an initrd from the kernel name
else: outfile = os.path.basename(kernel.path.replace("vmlinuz-", "initrd-") + ".img")
# Construct an initrd from the kernel name log.info("rebuilding %s", outfile)
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")
kver = kernel.version kver = kernel.version
cmd = dracut + ["/results/"+outfile, kver] dracut.Run(args + ["/results/"+outfile, kver])
runcmd(cmd, root=sys_root_dir) shutil.copy2(joinpaths(sys_root_dir, kernel.path), results_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)
def create_pxe_config(template, images_dir, live_image_name, add_args = None): def create_pxe_config(template, images_dir, live_image_name, add_args = None):
""" """

View File

@ -473,6 +473,42 @@ class PartitionMount(object):
execWithRedirect("kpartx", ["-d", "-s", self.disk_img]) 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 ########################## ######## Functions for making filesystem images ##########################
def mkfsimage(fstype, rootdir, outfile, size=None, mkfsargs=None, mountargs="", graft=None): def mkfsimage(fstype, rootdir, outfile, size=None, mkfsargs=None, mountargs="", graft=None):

View File

@ -31,6 +31,7 @@ from pylorax.sysutils import joinpaths, remove
from pylorax.base import DataHolder from pylorax.base import DataHolder
from pylorax.ltmpl import LoraxTemplateRunner from pylorax.ltmpl import LoraxTemplateRunner
import pylorax.imgutils as imgutils import pylorax.imgutils as imgutils
from pylorax.imgutils import DracutChroot
from pylorax.executils import runcmd, runcmd_output, execWithCapture from pylorax.executils import runcmd, runcmd_output, execWithCapture
templatemap = { templatemap = {
@ -310,32 +311,31 @@ class TreeBuilder(object):
name of the kernel. name of the kernel.
''' '''
add_args = add_args or [] add_args = add_args or []
dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + add_args args = ["--nomdadmconf", "--nolvmconf"] + add_args
if not backup: if not backup:
dracut.append("--force") args.append("--force")
if not self.kernels: if not self.kernels:
raise Exception("No kernels found, cannot rebuild_initrds") raise Exception("No kernels found, cannot rebuild_initrds")
for kernel in self.kernels: with DracutChroot(self.vars.inroot) as dracut:
if prefix: for kernel in self.kernels:
idir = os.path.dirname(kernel.path) if prefix:
outfile = joinpaths(idir, prefix+'-'+kernel.version+'.img') idir = os.path.dirname(kernel.path)
elif hasattr(kernel, "initrd"): outfile = joinpaths(idir, prefix+'-'+kernel.version+'.img')
# If there is an existing initrd, use that elif hasattr(kernel, "initrd"):
outfile = kernel.initrd.path # If there is an existing initrd, use that
else: outfile = kernel.initrd.path
# Construct an initrd from the kernel name else:
outfile = kernel.path.replace("vmlinuz-", "initrd-") + ".img" # Construct an initrd from the kernel name
logger.info("rebuilding %s", outfile) outfile = kernel.path.replace("vmlinuz-", "initrd-") + ".img"
logger.info("dracut warnings about /proc are safe to ignore") logger.info("rebuilding %s", outfile)
if backup: if backup:
initrd = joinpaths(self.vars.inroot, outfile) initrd = joinpaths(self.vars.inroot, outfile)
if os.path.exists(initrd): if os.path.exists(initrd):
os.rename(initrd, initrd + backup) os.rename(initrd, initrd + backup)
cmd = dracut + [outfile, kernel.version] dracut.Run(args + [outfile, kernel.version])
runcmd(cmd, root=self.vars.inroot)
def build(self): def build(self):
templatefile = templatemap[self.vars.arch.basearch] templatefile = templatemap[self.vars.arch.basearch]