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
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):
"""

View File

@ -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):

View File

@ -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]