Example #1
0
    def rebuild_initrds(self, add_args=[], backup="", prefix=""):
        '''Rebuild all the initrds in the tree. If backup is specified, each
        initrd will be renamed with backup as a suffix before rebuilding.
        If backup is empty, the existing initrd files will be overwritten.
        If suffix is specified, the existing initrd is untouched and a new
        image is built with the filename "${prefix}-${kernel.version}.img"
        '''
        dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + add_args
        if not backup:
            dracut.append("--force")

        # Hush some dracut warnings. TODO: bind-mount proc in place?
        open(joinpaths(self.vars.inroot,"/proc/modules"),"w")
        for kernel in self.kernels:
            if prefix:
                idir = os.path.dirname(kernel.initrd.path)
                outfile = joinpaths(idir, prefix+'-'+kernel.version+'.img')
            else:
                outfile = kernel.initrd.path
            logger.info("rebuilding %s", outfile)
            if backup:
                initrd = joinpaths(self.vars.inroot, outfile)
                os.rename(initrd, initrd + backup)
            cmd = dracut + [outfile, kernel.version]
            runcmd(cmd, root=self.vars.inroot)
        os.unlink(joinpaths(self.vars.inroot,"/proc/modules"))
Example #2
0
def mkrootfsimg(rootdir, outfile, label, size=2, sysroot=""):
    """
    Make rootfs image from a directory

    :param str rootdir: Root directory
    :param str outfile: Path of output image file
    :param str label: Filesystem label
    :param int size: Size of the image in GiB, if None computed automatically
    :param str sysroot: path to system (deployment) root relative to physical root
    """
    if size:
        fssize = size * (1024 * 1024 * 1024
                         )  # 2GB sparse file compresses down to nothin'
    else:
        fssize = None  # Let mkext4img figure out the needed size

    mkext4img(rootdir, outfile, label=label, size=fssize)
    # Reset selinux context on new rootfs
    with LoopDev(outfile) as loopdev:
        with Mount(loopdev) as mnt:
            cmd = [
                "setfiles", "-e", "/proc", "-e", "/sys", "-e", "/dev", "-e",
                "/install",
                "/etc/selinux/targeted/contexts/files/file_contexts", "/"
            ]
            root = join(mnt, sysroot.lstrip("/"))
            runcmd(cmd, root=root)
Example #3
0
    def create_runtime(self,
                       outfile="/var/tmp/squashfs.img",
                       compression="xz",
                       compressargs=[],
                       size=2):
        # make live rootfs image - must be named "LiveOS/rootfs.img" for dracut
        workdir = joinpaths(os.path.dirname(outfile), "runtime-workdir")
        if size:
            fssize = size * (1024 * 1024 * 1024
                             )  # 2GB sparse file compresses down to nothin'
        else:
            fssize = None  # Let mkext4img figure out the needed size
        os.makedirs(joinpaths(workdir, "LiveOS"))
        imgutils.mkext4img(self.vars.root,
                           joinpaths(workdir, "LiveOS/rootfs.img"),
                           label="Anaconda",
                           size=fssize)

        # Reset selinux context on new rootfs
        with imgutils.LoopDev(joinpaths(workdir,
                                        "LiveOS/rootfs.img")) as loopdev:
            with imgutils.Mount(loopdev) as mnt:
                cmd = [
                    "setfiles", "-e", "/proc", "-e", "/sys", "-e", "/dev",
                    "/etc/selinux/targeted/contexts/files/file_contexts", "/"
                ]
                runcmd(cmd, root=mnt)

        # squash the live rootfs and clean up workdir
        imgutils.mksquashfs(workdir, outfile, compression, compressargs)
        remove(workdir)
Example #4
0
def mkrootfsimg(rootdir, outfile, label, size=2, sysroot=""):
    """
    Make rootfs image from a directory

    :param str rootdir: Root directory
    :param str outfile: Path of output image file
    :param str label: Filesystem label
    :param int size: Size of the image in GiB, if None computed automatically
    :param str sysroot: path to system (deployment) root relative to physical root
    """
    if size:
        fssize = size * (1024 * 1024 * 1024
                         )  # 2GB sparse file compresses down to nothin'
    else:
        fssize = None  # Let mkext4img figure out the needed size

    mkext4img(rootdir, outfile, label=label, size=fssize)
    # Reset selinux context on new rootfs
    with LoopDev(outfile) as loopdev:
        with Mount(loopdev) as mnt:
            cmd = [
                "setfiles", "-e", "/proc", "-e", "/sys", "-e", "/dev", "-e",
                "/install", "-e", "/ostree",
                "/etc/selinux/targeted/contexts/files/file_contexts", "/"
            ]
            root = join(mnt, sysroot.lstrip("/"))
            try:
                runcmd(cmd, root=root)
            except CalledProcessError as e:
                logger.error(
                    "setfiles exited with a non-zero return code (%d) which may "
                    "be caused by running without SELinux in Permissive mode.",
                    e.returncode)
                raise
Example #5
0
def mkfsimage(fstype,
              rootdir,
              outfile,
              size=None,
              mkfsargs=[],
              mountargs="",
              graft={}):
    '''Generic filesystem image creation function.
    fstype should be a filesystem type - "mkfs.${fstype}" must exist.
    graft should be a dict: {"some/path/in/image": "local/file/or/dir"};
      if the path ends with a '/' it's assumed to be a directory.
    Will raise CalledProcessError if something goes wrong.'''
    preserve = (fstype not in ("msdos", "vfat"))
    if not size:
        size = estimate_size(rootdir, graft, fstype)
    with LoopDev(outfile, size) as loopdev:
        try:
            runcmd(["mkfs.%s" % fstype] + mkfsargs + [loopdev])
        except CalledProcessError as e:
            logger.error("mkfs exited with a non-zero return code: %d" %
                         e.returncode)
            logger.error(e.output)
            sys.exit(e.returncode)

        with Mount(loopdev, mountargs) as mnt:
            if rootdir:
                copytree(rootdir, mnt, preserve)
            do_grafts(graft, mnt, preserve)

    # Make absolutely sure that the data has been written
    runcmd(["sync"])
Example #6
0
def mkfsimage(fstype, rootdir, outfile, size=None, mkfsargs=None, mountargs="", graft=None):
    '''Generic filesystem image creation function.
    fstype should be a filesystem type - "mkfs.${fstype}" must exist.
    graft should be a dict: {"some/path/in/image": "local/file/or/dir"};
      if the path ends with a '/' it's assumed to be a directory.
    Will raise CalledProcessError if something goes wrong.'''
    mkfsargs = mkfsargs or []
    graft = graft or {}
    preserve = (fstype not in ("msdos", "vfat"))
    if not size:
        size = estimate_size(rootdir, graft, fstype)
    with LoopDev(outfile, size) as loopdev:
        try:
            runcmd(["mkfs.%s" % fstype] + mkfsargs + [loopdev])
        except CalledProcessError as e:
            logger.error("mkfs exited with a non-zero return code: %d", e.returncode)
            logger.error(e.output)
            sys.exit(e.returncode)

        with Mount(loopdev, mountargs) as mnt:
            if rootdir:
                copytree(rootdir, mnt, preserve)
            do_grafts(graft, mnt, preserve)

    # Make absolutely sure that the data has been written
    runcmd(["sync"])
Example #7
0
def rebuild_initrds_for_live(opts, sys_root_dir, results_dir):
    """
    Rebuild intrds for pxe live image (root=live:http://)

    :param opts: options passed to livemedia-creator
    :type opts: argparse options
    :param str sys_root_dir: Path to root of the system
    :param str results_dir: Path of directory for storing results
    """
    # 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)

    kdir = "boot"
    if opts.ostree:
        kernels_dir = glob.glob(joinpaths(sys_root_dir, "boot/ostree/*"))
        if kernels_dir:
            kdir = os.path.relpath(kernels_dir[0], sys_root_dir)

    kernels = [kernel for kernel in findkernels(sys_root_dir, kdir)]
    if not kernels:
        raise Exception("No initrds found, cannot rebuild_initrds")

    if opts.ostree:
        # Dracut assumes to have some dirs in disk image
        # /var/tmp for temp files
        vartmp_dir = joinpaths(sys_root_dir, "var/tmp")
        if not os.path.isdir(vartmp_dir):
            os.mkdir(vartmp_dir)
        # /root (maybe not fatal)
        root_dir = joinpaths(sys_root_dir, "var/roothome")
        if not os.path.isdir(root_dir):
            os.mkdir(root_dir)
        # /tmp (maybe not fatal)
        tmp_dir = joinpaths(sys_root_dir, "sysroot/tmp")
        if not os.path.isdir(tmp_dir):
            os.mkdir(tmp_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")

        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)
Example #8
0
 def generate_module_data(self):
     root = self.vars.root
     moddir = joinpaths(root, "lib/modules/")
     for kver in os.listdir(moddir):
         ksyms = joinpaths(root, "boot/System.map-%s" % kver)
         logger.info("doing depmod and module-info for %s", kver)
         runcmd(["depmod", "-a", "-F", ksyms, "-b", root, kver])
         generate_module_info(moddir+kver, outfile=moddir+"module-info")
Example #9
0
 def generate_module_data(self):
     root = self.vars.root
     moddir = joinpaths(root, "lib/modules/")
     for kernel in findkernels(root=root):
         ksyms = joinpaths(root, "boot/System.map-%s" % kernel.version)
         logger.info("doing depmod and module-info for %s", kernel.version)
         runcmd(["depmod", "-a", "-F", ksyms, "-b", root, kernel.version])
         generate_module_info(moddir+kernel.version, outfile=moddir+"module-info")
Example #10
0
 def generate_module_data(self):
     root = self.vars.root
     moddir = joinpaths(root, "lib/modules/")
     for kver in os.listdir(moddir):
         ksyms = joinpaths(root, "boot/System.map-%s" % kver)
         logger.info("doing depmod and module-info for %s", kver)
         runcmd(["depmod", "-a", "-F", ksyms, "-b", root, kver])
         generate_module_info(moddir + kver, outfile=moddir + "module-info")
Example #11
0
def copytree(src, dest, preserve=True):
    '''Copy a tree of files using cp -a, thus preserving modes, timestamps,
    links, acls, sparse files, xattrs, selinux contexts, etc.
    If preserve is False, uses cp -R (useful for modeless filesystems)
    raises CalledProcessError if copy fails.'''
    logger.debug("copytree %s %s", src, dest)
    cp = ["cp", "-a"] if preserve else ["cp", "-R", "-L"]
    cp += [".", os.path.abspath(dest)]
    runcmd(cp, cwd=src)
Example #12
0
def copytree(src, dest, preserve=True):
    '''Copy a tree of files using cp -a, thus preserving modes, timestamps,
    links, acls, sparse files, xattrs, selinux contexts, etc.
    If preserve is False, uses cp -R (useful for modeless filesystems)
    raises CalledProcessError if copy fails.'''
    logger.debug("copytree %s %s", src, dest)
    cp = ["cp", "-a"] if preserve else ["cp", "-R", "-L"]
    cp += [join(src, "."), os.path.abspath(dest)]
    runcmd(cp)
Example #13
0
def dm_attach(dev, size, name=None):
    '''Attach a devicemapper device to the given device, with the given size.
    If name is None, a random name will be chosen. Returns the device name.
    raises CalledProcessError if dmsetup fails.'''
    if name is None:
        name = tempfile.mktemp(prefix="lorax.imgutils.", dir="")
    runcmd(["dmsetup", "create", name, "--table",
                       "0 %i linear %s 0" % (size/512, dev)])
    return name
Example #14
0
 def mount_test(self):
     """Test the Mount context manager (requires loop)"""
     with tempfile.NamedTemporaryFile(prefix="lorax.test.disk.") as disk_img:
         mksparse(disk_img.name, 42 * 1024**2)
         runcmd(["mkfs.ext4", "-L", "Anaconda", "-b", "4096", "-m", "0", disk_img.name])
         with LoopDev(disk_img.name) as loopdev:
             self.assertTrue(loopdev is not None)
             with Mount(loopdev) as mnt:
                 self.assertTrue(mnt is not None)
Example #15
0
def dm_attach(dev, size, name=None):
    '''Attach a devicemapper device to the given device, with the given size.
    If name is None, a random name will be chosen. Returns the device name.
    raises CalledProcessError if dmsetup fails.'''
    if name is None:
        name = tempfile.mktemp(prefix="lorax.imgutils.", dir="")
    runcmd(["dmsetup", "create", name, "--table",
                       "0 %i linear %s 0" % (size/512, dev)])
    return name
Example #16
0
def mkqcow2(outfile, size, options=None):
    '''use qemu-img to create a file of the given size.
       options is a list of options passed to qemu-img

       Default format is qcow2, override by passing "-f", fmt
       in options.
    '''
    options = options or []
    if "-f" not in options:
        options.extend(["-f", "qcow2"])
    runcmd(["qemu-img", "create"] + options + [outfile, str(size)])
Example #17
0
def mkqcow2(outfile, size, options=None):
    '''use qemu-img to create a file of the given size.
       options is a list of options passed to qemu-img

       Default format is qcow2, override by passing "-f", fmt
       in options.
    '''
    options = options or []
    if "-f" not in options:
        options.extend(["-f", "qcow2"])
    runcmd(["qemu-img", "create"] + options + [outfile, str(size)])
Example #18
0
def mkfakediskimg(disk_img):
    """Create a fake partitioned disk image

    :param disk_img: Full path to a partitioned disk image
    :type disk_img: str
    :returns: True if it was successful, False if something went wrong

    Include /boot, swap, and / partitions with fake kernel and /etc/passwd
    """
    try:
        mksparse(disk_img, 42 * 1024**2)
        # Make a /boot, / and swap partitions on it
        dev = parted.getDevice(disk_img)
        disk = parted.freshDisk(dev, "gpt")

        # (start, length, flags, name)
        for start, length, flags, name in [
                  (  1024**2,    1024**2, None, "boot"),
                  (2*1024**2,  2*1024**2, parted.PARTITION_SWAP, "swap"),
                  (4*1024**2, 38*1024**2, None, "root")]:
            geo = parted.Geometry(device=dev, start=start//dev.sectorSize, length=length//dev.sectorSize)
            part = parted.Partition(disk=disk, type=parted.PARTITION_NORMAL, geometry=geo)
            part.getPedPartition().set_name(name)
            disk.addPartition(partition=part)
            if flags:
                part.setFlag(flags)
        disk.commit()
        os.sync()
    except parted.PartedException:
        return False

    # Mount the disk's partitions
    loop_devs = kpartx_disk_img(disk_img)

    try:
        # Format the partitions
        runcmd(["mkfs.ext4", "/dev/mapper/" + loop_devs[0][0]])
        runcmd(["mkswap", "/dev/mapper/" + loop_devs[1][0]])
        runcmd(["mkfs.ext4", "/dev/mapper/" + loop_devs[2][0]])

        # Mount the boot partition and make a fake kernel and initrd
        boot_mnt = mount("/dev/mapper/" + loop_devs[0][0])
        try:
            mkfakebootdir(boot_mnt)
        finally:
            umount(boot_mnt)

        # Mount the / partition and make a fake / filesystem with /etc/passwd
        root_mnt = mount("/dev/mapper/" + loop_devs[2][0])
        try:
            mkfakerootdir(root_mnt)
        finally:
            umount(root_mnt)
    except Exception:
        return False
    finally:
        # Remove the disk's mounted partitions
        runcmd(["kpartx", "-d", "-s", disk_img])

    return True
Example #19
0
    def generate_module_data(self):
        root = self.vars.root
        moddir = joinpaths(root, "lib/modules/")

        # Generate_module_data creates a file called "module-info" in this
        # directory. If we don't do something to exclude this file, depmod will fail
        # on the second path of this loop. Let's check to see if kver is a directory 
        # before generating module info from it.
        for kver in os.listdir(moddir):
            if os.path.isdir(kver):
                ksyms = joinpaths(root, "boot/System.map-%s" % kver)
                logger.info("doing depmod and module-info for %s", kver)
                runcmd(["depmod", "-a", "-F", ksyms, "-b", root, kver])
                generate_module_info(moddir+kver, outfile=moddir+"module-info")
Example #20
0
 def gconfset(self, path, keytype, value, outfile=None):
     '''
     gconfset PATH KEYTYPE VALUE [OUTFILE]
       Set the given gconf PATH, with type KEYTYPE, to the given value.
       OUTFILE defaults to /etc/gconf/gconf.xml.defaults if not given.
       Example:
         gconfset /apps/metacity/general/num_workspaces int 1
     '''
     if outfile is None:
         outfile = self._out("etc/gconf/gconf.xml.defaults")
     cmd = ["gconftool-2", "--direct",
                 "--config-source=xml:readwrite:%s" % outfile,
                 "--set", "--type", keytype, path, value]
     runcmd(cmd)
Example #21
0
 def gconfset(self, path, keytype, value, outfile=None):
     '''
     gconfset PATH KEYTYPE VALUE [OUTFILE]
       Set the given gconf PATH, with type KEYTYPE, to the given value.
       OUTFILE defaults to /etc/gconf/gconf.xml.defaults if not given.
       Example:
         gconfset /apps/metacity/general/num_workspaces int 1
     '''
     if outfile is None:
         outfile = self._out("etc/gconf/gconf.xml.defaults")
     cmd = ["gconftool-2", "--direct",
                 "--config-source=xml:readwrite:%s" % outfile,
                 "--set", "--type", keytype, path, value]
     runcmd(cmd)
Example #22
0
def mount(dev, opts="", mnt=None):
    '''Mount the given device at the given mountpoint, using the given opts.
    opts should be a comma-separated string of mount options.
    if mnt is none, a temporary directory will be created and its path will be
    returned.
    raises CalledProcessError if mount fails.'''
    if mnt is None:
        mnt = tempfile.mkdtemp(prefix="lorax.imgutils.")
        logger.debug("make tmp mountdir %s", mnt)
    cmd = ["mount"]
    if opts:
        cmd += ["-o", opts]
    cmd += [dev, mnt]
    runcmd(cmd)
    return mnt
Example #23
0
    def generate_module_data(self):
        root = self.vars.root
        moddir = joinpaths(root, "lib/modules/")

        # Generate_module_data creates a file called "module-info" in this
        # directory. If we don't do something to exclude this file, depmod will fail
        # on the second path of this loop. Let's check to see if kver is a directory
        # before generating module info from it.
        for kver in os.listdir(moddir):
            if os.path.isdir(kver):
                ksyms = joinpaths(root, "boot/System.map-%s" % kver)
                logger.info("doing depmod and module-info for %s", kver)
                runcmd(["depmod", "-a", "-F", ksyms, "-b", root, kver])
                generate_module_info(moddir + kver,
                                     outfile=moddir + "module-info")
Example #24
0
def mount(dev, opts="", mnt=None):
    '''Mount the given device at the given mountpoint, using the given opts.
    opts should be a comma-separated string of mount options.
    if mnt is none, a temporary directory will be created and its path will be
    returned.
    raises CalledProcessError if mount fails.'''
    if mnt is None:
        mnt = tempfile.mkdtemp(prefix="lorax.imgutils.")
        logger.debug("make tmp mountdir %s", mnt)
    mount = ["mount"]
    if opts:
        mount += ["-o", opts]
    mount += [dev, mnt]
    runcmd(mount)
    return mnt
Example #25
0
    def rebuild_initrds(self, add_args=None, backup="", prefix=""):
        '''Rebuild all the initrds in the tree. If backup is specified, each
        initrd will be renamed with backup as a suffix before rebuilding.
        If backup is empty, the existing initrd files will be overwritten.
        If suffix is specified, the existing initrd is untouched and a new
        image is built with the filename "${prefix}-${kernel.version}.img"

        If the initrd doesn't exist its name will be created based on the
        name of the kernel.
        '''
        add_args = add_args or []
        dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + add_args
        if not backup:
            dracut.append("--force")

        if not self.kernels:
            raise Exception("No kernels found, cannot rebuild_initrds")

        # Hush some dracut warnings. TODO: bind-mount proc in place?
        open(joinpaths(self.vars.inroot, "/proc/modules"), "w")
        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]
            logger.debug("cmd=%s", cmd)
            runcmd(cmd, root=self.vars.inroot)

            # ppc64 cannot boot images > 32MiB, check size and warn
            if self.vars.arch.basearch in (
                    "ppc64", "ppc64le") and os.path.exists(outfile):
                st = os.stat(outfile)
                if st.st_size > 32 * 1024 * 1024:
                    logging.warning("ppc64 initrd %s is > 32MiB", outfile)

        os.unlink(joinpaths(self.vars.inroot, "/proc/modules"))
Example #26
0
def umount(mnt,  lazy=False, maxretry=3, retrysleep=1.0):
    '''Unmount the given mountpoint. If lazy is True, do a lazy umount (-l).
    If the mount was a temporary dir created by mount, it will be deleted.
    raises CalledProcessError if umount fails.'''
    cmd = ["umount"]
    if lazy: cmd += ["-l"]
    cmd += [mnt]
    count = 0
    while maxretry > 0:
        try:
            rv = runcmd(cmd)
        except CalledProcessError:
            count += 1
            if count == maxretry:
                raise
            logger.warn("failed to unmount %s. retrying (%d/%d)...",
                         mnt, count, maxretry)
            if logger.getEffectiveLevel() <= logging.DEBUG:
                fuser = execWithCapture("fuser", ["-vm", mnt])
                logger.debug("fuser -vm:\n%s\n", fuser)
            sleep(retrysleep)
        else:
            break
    if 'lorax.imgutils' in mnt:
        os.rmdir(mnt)
        logger.debug("remove tmp mountdir %s", mnt)
    return (rv == 0)
Example #27
0
def umount(mnt, lazy=False, maxretry=3, retrysleep=1.0):
    '''Unmount the given mountpoint. If lazy is True, do a lazy umount (-l).
    If the mount was a temporary dir created by mount, it will be deleted.
    raises CalledProcessError if umount fails.'''
    umount = ["umount"]
    if lazy: umount += ["-l"]
    umount += [mnt]
    count = 0
    while maxretry > 0:
        try:
            rv = runcmd(umount)
        except CalledProcessError:
            count += 1
            if count == maxretry:
                raise
            logger.warn("failed to unmount %s. retrying (%d/%d)...", mnt,
                        count, maxretry)
            if logger.getEffectiveLevel() <= logging.DEBUG:
                fuser = execWithCapture("fuser", ["-vm", mnt])
                logger.debug("fuser -vm:\n%s\n", fuser)
            sleep(retrysleep)
        else:
            break
    if 'lorax.imgutils' in mnt:
        os.rmdir(mnt)
        logger.debug("remove tmp mountdir %s", mnt)
    return (rv == 0)
Example #28
0
 def test_runcmd(self):
     cmd = [
         "python3", "-c",
         "import sys; print('Theodor Seuss Geisel'); sys.exit(0)"
     ]
     rc = runcmd(cmd)
     self.assertEqual(rc, 0)
Example #29
0
    def rebuild_initrds(self, add_args=None, backup="", prefix=""):
        '''Rebuild all the initrds in the tree. If backup is specified, each
        initrd will be renamed with backup as a suffix before rebuilding.
        If backup is empty, the existing initrd files will be overwritten.
        If suffix is specified, the existing initrd is untouched and a new
        image is built with the filename "${prefix}-${kernel.version}.img"

        If the initrd doesn't exist its name will be created based on the
        name of the kernel.
        '''
        add_args = add_args or []
        dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + add_args
        if not backup:
            dracut.append("--force")

        if not self.kernels:
            raise Exception("No kernels found, cannot rebuild_initrds")

        # Hush some dracut warnings. TODO: bind-mount proc in place?
        open(joinpaths(self.vars.inroot,"/proc/modules"),"w")
        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)

            # ppc64 cannot boot images > 32MiB, check size and warn
            if self.vars.arch.basearch in ("ppc64", "ppc64le") and os.path.exists(outfile):
                st = os.stat(outfile)
                if st.st_size > 32 * 1024 * 1024:
                    logging.warning("ppc64 initrd %s is > 32MiB", outfile)

        os.unlink(joinpaths(self.vars.inroot,"/proc/modules"))
Example #30
0
    def create_runtime(self, outfile="/var/tmp/squashfs.img", compression="xz", compressargs=[], size=2):
        # make live rootfs image - must be named "LiveOS/rootfs.img" for dracut
        workdir = joinpaths(os.path.dirname(outfile), "runtime-workdir")
        if size:
            fssize = size * (1024*1024*1024) # 2GB sparse file compresses down to nothin'
        else:
            fssize = None       # Let mkext4img figure out the needed size
        os.makedirs(joinpaths(workdir, "LiveOS"))
        imgutils.mkext4img(self.vars.root, joinpaths(workdir, "LiveOS/rootfs.img"),
                           label="Anaconda", size=fssize)

        # Reset selinux context on new rootfs
        with imgutils.LoopDev( joinpaths(workdir, "LiveOS/rootfs.img") ) as loopdev:
            with imgutils.Mount(loopdev) as mnt:
                cmd = [ "setfiles", "-e", "/proc", "-e", "/sys", "-e", "/dev",  "/etc/selinux/targeted/contexts/files/file_contexts", "/"]
                runcmd(cmd, root=mnt)

        # squash the live rootfs and clean up workdir
        imgutils.mksquashfs(workdir, outfile, compression, compressargs)
        remove(workdir)
Example #31
0
    def rebuild_initrds(self, add_args=[], backup="", prefix=""):
        '''Rebuild all the initrds in the tree. If backup is specified, each
        initrd will be renamed with backup as a suffix before rebuilding.
        If backup is empty, the existing initrd files will be overwritten.
        If suffix is specified, the existing initrd is untouched and a new
        image is built with the filename "${prefix}-${kernel.version}.img"
        '''
        dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + add_args
        if not backup:
            dracut.append("--force")

        kernels = [
            kernel for kernel in self.kernels if hasattr(kernel, "initrd")
        ]
        if not kernels:
            raise Exception("No initrds found, cannot rebuild_initrds")

        # Hush some dracut warnings. TODO: bind-mount proc in place?
        open(joinpaths(self.vars.inroot, "/proc/modules"), "w")
        for kernel in kernels:
            if prefix:
                idir = os.path.dirname(kernel.initrd.path)
                outfile = joinpaths(idir,
                                    prefix + '-' + kernel.version + '.img')
            else:
                outfile = kernel.initrd.path
            logger.info("rebuilding %s", outfile)
            if backup:
                initrd = joinpaths(self.vars.inroot, outfile)
                os.rename(initrd, initrd + backup)
            cmd = dracut + [outfile, kernel.version]
            runcmd(cmd, root=self.vars.inroot)

            # ppc64 cannot boot images > 32MiB, check size and warn
            if self.vars.arch.basearch in (
                    "ppc64", "ppc64le") and os.path.exists(outfile):
                st = os.stat(outfile)
                if st.st_size > 32 * 1024 * 1024:
                    logging.warning("ppc64 initrd %s is > 32MiB", outfile)

        os.unlink(joinpaths(self.vars.inroot, "/proc/modules"))
Example #32
0
    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 ])
Example #33
0
def loop_waitfor(loop_dev, outfile):
    """Make sure the loop device is attached to the outfile.

    It seems that on rare occasions losetup can return before the /dev/loopX is
    ready for use, causing problems with mkfs. This tries to make sure that the
    loop device really is associated with the backing file before continuing.

    Raise RuntimeError if it isn't setup after 5 tries.
    """
    for _x in range(0,5):
        runcmd(["udevadm", "settle", "--timeout", "300"])
        ## XXX Note that losetup --list output can be truncated to 64 bytes in some
        ##     situations. Don't use it to lookup backing file, go the other way
        ##     and lookup the loop for the backing file. See util-linux lib/loopdev.c
        ##     loopcxt_get_backing_file()
        if get_loop_name(outfile) == os.path.basename(loop_dev):
            return

        # If this really is a race, give it some time to settle down
        time.sleep(1)

    raise RuntimeError("Unable to setup %s on %s" % (loop_dev, outfile))
Example #34
0
 def systemctl(self, cmd, *units):
     '''
     systemctl [enable|disable|mask] UNIT [UNIT...]
       Enable, disable, or mask the given systemd units.
       Examples:
         systemctl disable lvm2-monitor.service
         systemctl mask fedora-storage-init.service fedora-configure.service
     '''
     if cmd not in ('enable', 'disable', 'mask'):
         raise ValueError('unsupported systemctl cmd: %s' % cmd)
     if not units:
         logger.debug("systemctl: no units given for %s, ignoring", cmd)
         return
     self.mkdir("/run/systemd/system") # XXX workaround for systemctl bug
     systemctl = ('systemctl', '--root', self.outroot, '--no-reload',
                  '--quiet', cmd)
     # XXX for some reason 'systemctl enable/disable' always returns 1
     try:
         cmd = systemctl + units
         runcmd(cmd)
     except CalledProcessError:
         pass
Example #35
0
 def systemctl(self, cmd, *units):
     '''
     systemctl [enable|disable|mask] UNIT [UNIT...]
       Enable, disable, or mask the given systemd units.
       Examples:
         systemctl disable lvm2-monitor.service
         systemctl mask fedora-storage-init.service fedora-configure.service
     '''
     if cmd not in ('enable', 'disable', 'mask'):
         raise ValueError('unsupported systemctl cmd: %s' % cmd)
     if not units:
         logger.debug("systemctl: no units given for %s, ignoring", cmd)
         return
     self.mkdir("/run/systemd/system") # XXX workaround for systemctl bug
     systemctl = ('systemctl', '--root', self.outroot, '--no-reload',
                  '--quiet', cmd)
     # XXX for some reason 'systemctl enable/disable' always returns 1
     try:
         cmd = systemctl + units
         runcmd(cmd)
     except CalledProcessError:
         pass
Example #36
0
    def make_squashfs_test(self):
        """Test making a squashfs image"""
        with tempfile.TemporaryDirectory(prefix="lorax.test.") as work_dir:
            with tempfile.NamedTemporaryFile(
                    prefix="lorax.test.disk.") as disk_img:
                # Make a small ext4 disk image
                mksparse(disk_img.name, 42 * 1024**2)
                runcmd([
                    "mkfs.ext4", "-L", "Anaconda", "-b", "4096", "-m", "0",
                    disk_img.name
                ])
                opts = DataHolder(compression="xz", arch="x86_64")
                make_squashfs(opts, disk_img.name, work_dir)

                # Make sure it made an install.img
                self.assertTrue(
                    os.path.exists(joinpaths(work_dir, "images/install.img")))

                # Make sure it looks like a squashfs filesystem
                file_details = get_file_magic(
                    joinpaths(work_dir, "images/install.img"))
                self.assertTrue("Squashfs" in file_details)
Example #37
0
def loop_waitfor(loop_dev, outfile):
    """Make sure the loop device is attached to the outfile.

    It seems that on rare occasions losetup can return before the /dev/loopX is
    ready for use, causing problems with mkfs. This tries to make sure that the
    loop device really is associated with the backing file before continuing.

    Raise RuntimeError if it isn't setup after 5 tries.
    """
    for _x in range(0, 5):
        runcmd(["udevadm", "settle", "--timeout", "300"])
        ## XXX Note that losetup --list output can be truncated to 64 bytes in some
        ##     situations. Don't use it to lookup backing file, go the other way
        ##     and lookup the loop for the backing file. See util-linux lib/loopdev.c
        ##     loopcxt_get_backing_file()
        if get_loop_name(outfile) == os.path.basename(loop_dev):
            return

        # If this really is a race, give it some time to settle down
        time.sleep(1)

    raise RuntimeError("Unable to setup %s on %s" % (loop_dev, outfile))
Example #38
0
    def rebuild_initrds(self, add_args=None, backup="", prefix=""):
        '''Rebuild all the initrds in the tree. If backup is specified, each
        initrd will be renamed with backup as a suffix before rebuilding.
        If backup is empty, the existing initrd files will be overwritten.
        If suffix is specified, the existing initrd is untouched and a new
        image is built with the filename "${prefix}-${kernel.version}.img"

        If the initrd doesn't exist its name will be created based on the
        name of the kernel.
        '''
        add_args = add_args or []
        dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + add_args
        if not backup:
            dracut.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")

            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)
Example #39
0
def mkrootfsimg(rootdir, outfile, label, size=2, sysroot=""):
    """
    Make rootfs image from a directory

    :param str rootdir: Root directory
    :param str outfile: Path of output image file
    :param str label: Filesystem label
    :param int size: Size of the image in GiB, if None computed automatically
    :param str sysroot: path to system (deployment) root relative to physical root
    """
    if size:
        fssize = size * (1024*1024*1024) # 2GB sparse file compresses down to nothin'
    else:
        fssize = None       # Let mkext4img figure out the needed size

    mkext4img(rootdir, outfile, label=label, size=fssize)
    # Reset selinux context on new rootfs
    with LoopDev(outfile) as loopdev:
        with Mount(loopdev) as mnt:
            cmd = [ "setfiles", "-e", "/proc", "-e", "/sys", "-e", "/dev", "-e", "/install",
                    "/etc/selinux/targeted/contexts/files/file_contexts", "/"]
            root = join(mnt, sysroot.lstrip("/"))
            runcmd(cmd, root=root)
Example #40
0
    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
Example #41
0
    def run(self, dbo, product, version, release, variant="", bugurl="",
            isfinal=False, workdir=None, outputdir=None, buildarch=None, volid=None,
            domacboot=True, doupgrade=True, remove_temp=False,
            installpkgs=None, excludepkgs=None,
            size=2,
            add_templates=None,
            add_template_vars=None,
            add_arch_templates=None,
            add_arch_template_vars=None,
            verify=True):

        assert self._configured

        installpkgs = installpkgs or []
        excludepkgs = excludepkgs or []

        if domacboot:
            try:
                runcmd(["rpm", "-q", "hfsplus-tools"])
            except CalledProcessError:
                logger.critical("you need to install hfsplus-tools to create mac images")
                sys.exit(1)

        # set up work directory
        self.workdir = workdir or tempfile.mkdtemp(prefix="pylorax.work.")
        if not os.path.isdir(self.workdir):
            os.makedirs(self.workdir)

        # set up log directory
        logdir = self.conf.get("lorax", "logdir")
        if not os.path.isdir(logdir):
            os.makedirs(logdir)

        self.init_stream_logging()
        self.init_file_logging(logdir)

        logger.debug("version is %s", vernum)
        logger.debug("using work directory %s", self.workdir)
        logger.debug("using log directory %s", logdir)

        # set up output directory
        self.outputdir = outputdir or tempfile.mkdtemp(prefix="pylorax.out.")
        if not os.path.isdir(self.outputdir):
            os.makedirs(self.outputdir)
        logger.debug("using output directory %s", self.outputdir)

        # do we have root privileges?
        logger.info("checking for root privileges")
        if not os.geteuid() == 0:
            logger.critical("no root privileges")
            sys.exit(1)

        # is selinux disabled?
        # With selinux in enforcing mode the rpcbind package required for
        # dracut nfs module, which is in turn required by anaconda module,
        # will not get installed, because it's preinstall scriptlet fails,
        # resulting in an incomplete initial ramdisk image.
        # The reason is that the scriptlet runs tools from the shadow-utils
        # package in chroot, particularly groupadd and useradd to add the
        # required rpc group and rpc user. This operation fails, because
        # the selinux context on files in the chroot, that the shadow-utils
        # tools need to access (/etc/group, /etc/passwd, /etc/shadow etc.),
        # is wrong and selinux therefore disallows access to these files.
        logger.info("checking the selinux mode")
        if selinux.is_selinux_enabled() and selinux.security_getenforce():
            logger.critical("selinux must be disabled or in Permissive mode")
            sys.exit(1)

        # do we have a proper dnf base object?
        logger.info("checking dnf base object")
        if not isinstance(dbo, dnf.Base):
            logger.critical("no dnf base object")
            sys.exit(1)
        self.inroot = dbo.conf.installroot
        logger.debug("using install root: %s", self.inroot)

        if not buildarch:
            buildarch = get_buildarch(dbo)

        logger.info("setting up build architecture")
        self.arch = ArchData(buildarch)
        for attr in ('buildarch', 'basearch', 'libdir'):
            logger.debug("self.arch.%s = %s", attr, getattr(self.arch,attr))

        logger.info("setting up build parameters")
        self.product = DataHolder(name=product, version=version, release=release,
                                 variant=variant, bugurl=bugurl, isfinal=isfinal)
        logger.debug("product data: %s", self.product)

        # NOTE: if you change isolabel, you need to change pungi to match, or
        # the pungi images won't boot.
        isolabel = volid or "%s-%s-%s" % (self.product.name, self.product.version, self.arch.basearch)

        if len(isolabel) > 32:
            logger.fatal("the volume id cannot be longer than 32 characters")
            sys.exit(1)

        # NOTE: rb.root = dbo.conf.installroot (== self.inroot)
        rb = RuntimeBuilder(product=self.product, arch=self.arch,
                            dbo=dbo, templatedir=self.templatedir,
                            installpkgs=installpkgs,
                            excludepkgs=excludepkgs,
                            add_templates=add_templates,
                            add_template_vars=add_template_vars)

        logger.info("installing runtime packages")
        rb.install()

        # write .buildstamp
        buildstamp = BuildStamp(self.product.name, self.product.version,
                                self.product.bugurl, self.product.isfinal, self.arch.buildarch)

        buildstamp.write(joinpaths(self.inroot, ".buildstamp"))

        if self.debug:
            rb.writepkglists(joinpaths(logdir, "pkglists"))
            rb.writepkgsizes(joinpaths(logdir, "original-pkgsizes.txt"))

        logger.info("doing post-install configuration")
        rb.postinstall()

        # write .discinfo
        discinfo = DiscInfo(self.product.release, self.arch.basearch)
        discinfo.write(joinpaths(self.outputdir, ".discinfo"))

        logger.info("backing up installroot")
        installroot = joinpaths(self.workdir, "installroot")
        linktree(self.inroot, installroot)

        logger.info("generating kernel module metadata")
        rb.generate_module_data()

        logger.info("cleaning unneeded files")
        rb.cleanup()

        if verify:
            logger.info("verifying the installroot")
            if not rb.verify():
                sys.exit(1)
        else:
            logger.info("Skipping verify")

        if self.debug:
            rb.writepkgsizes(joinpaths(logdir, "final-pkgsizes.txt"))

        logger.info("creating the runtime image")
        runtime = "images/install.img"
        compression = self.conf.get("compression", "type")
        compressargs = self.conf.get("compression", "args").split()     # pylint: disable=no-member
        if self.conf.getboolean("compression", "bcj"):
            if self.arch.bcj:
                compressargs += ["-Xbcj", self.arch.bcj]
            else:
                logger.info("no BCJ filter for arch %s", self.arch.basearch)
        rb.create_runtime(joinpaths(installroot,runtime),
                          compression=compression, compressargs=compressargs,
                          size=size)
        rb.finished()

        logger.info("preparing to build output tree and boot images")
        treebuilder = TreeBuilder(product=self.product, arch=self.arch,
                                  inroot=installroot, outroot=self.outputdir,
                                  runtime=runtime, isolabel=isolabel,
                                  domacboot=domacboot, doupgrade=doupgrade,
                                  templatedir=self.templatedir,
                                  add_templates=add_arch_templates,
                                  add_template_vars=add_arch_template_vars,
                                  workdir=self.workdir)

        logger.info("rebuilding initramfs images")
        dracut_args = ["--xz", "--install", "/.buildstamp", "--no-early-microcode", "--add", "fips"]
        anaconda_args = dracut_args + ["--add", "anaconda pollcdrom qemu qemu-net"]

        # ppc64 cannot boot an initrd > 32MiB so remove some drivers
        if self.arch.basearch in ("ppc64", "ppc64le"):
            dracut_args.extend(["--omit-drivers", REMOVE_PPC64_DRIVERS])

            # Only omit dracut modules from the initrd so that they're kept for
            # upgrade.img
            anaconda_args.extend(["--omit", REMOVE_PPC64_MODULES])

        treebuilder.rebuild_initrds(add_args=anaconda_args)

        logger.info("populating output tree and building boot images")
        treebuilder.build()

        # write .treeinfo file and we're done
        treeinfo = TreeInfo(self.product.name, self.product.version,
                            self.product.variant, self.arch.basearch)
        for section, data in treebuilder.treeinfo_data.items():
            treeinfo.add_section(section, data)
        treeinfo.write(joinpaths(self.outputdir, ".treeinfo"))

        # cleanup
        if remove_temp:
            remove(self.workdir)
Example #42
0
 def implantisomd5(self):
     for section, data in self.treeinfo_data.items():
         if 'boot.iso' in data:
             iso = joinpaths(self.vars.outroot, data['boot.iso'])
             runcmd(["implantisomd5", iso])
Example #43
0
def linktree(src, dst):
    runcmd(["/bin/cp", "-al", src, dst])
Example #44
0
 def implantisomd5(self):
     for _section, data in self.treeinfo_data.items():
         if 'boot.iso' in data:
             iso = joinpaths(self.vars.outroot, data['boot.iso'])
             runcmd(["implantisomd5", iso])
Example #45
0
    def run(self,
            dbo,
            product,
            version,
            release,
            variant="",
            bugurl="",
            isfinal=False,
            workdir=None,
            outputdir=None,
            buildarch=None,
            volid=None,
            domacboot=True,
            doupgrade=True,
            remove_temp=False,
            installpkgs=None,
            excludepkgs=None,
            size=2,
            add_templates=None,
            add_template_vars=None,
            add_arch_templates=None,
            add_arch_template_vars=None,
            verify=True,
            user_dracut_args=None,
            squashfs_only=False):

        assert self._configured

        installpkgs = installpkgs or []
        excludepkgs = excludepkgs or []

        if domacboot:
            try:
                runcmd(["rpm", "-q", "hfsplus-tools"])
            except CalledProcessError:
                logger.critical(
                    "you need to install hfsplus-tools to create mac images")
                sys.exit(1)

        # set up work directory
        self.workdir = workdir or tempfile.mkdtemp(prefix="pylorax.work.")
        if not os.path.isdir(self.workdir):
            os.makedirs(self.workdir)

        # set up log directory
        logdir = self.conf.get("lorax", "logdir")
        if not os.path.isdir(logdir):
            os.makedirs(logdir)

        self.init_stream_logging()
        self.init_file_logging(logdir)

        logger.debug("version is %s", vernum)
        log_selinux_state()

        logger.debug("using work directory %s", self.workdir)
        logger.debug("using log directory %s", logdir)

        # set up output directory
        self.outputdir = outputdir or tempfile.mkdtemp(prefix="pylorax.out.")
        if not os.path.isdir(self.outputdir):
            os.makedirs(self.outputdir)
        logger.debug("using output directory %s", self.outputdir)

        # do we have root privileges?
        logger.info("checking for root privileges")
        if not os.geteuid() == 0:
            logger.critical("no root privileges")
            sys.exit(1)

        # do we have a proper dnf base object?
        logger.info("checking dnf base object")
        if not isinstance(dbo, dnf.Base):
            logger.critical("no dnf base object")
            sys.exit(1)
        self.inroot = dbo.conf.installroot
        logger.debug("using install root: %s", self.inroot)

        if not buildarch:
            buildarch = get_buildarch(dbo)

        logger.info("setting up build architecture")
        self.arch = ArchData(buildarch)
        for attr in ('buildarch', 'basearch', 'libdir'):
            logger.debug("self.arch.%s = %s", attr, getattr(self.arch, attr))

        logger.info("setting up build parameters")
        self.product = DataHolder(name=product,
                                  version=version,
                                  release=release,
                                  variant=variant,
                                  bugurl=bugurl,
                                  isfinal=isfinal)
        logger.debug("product data: %s", self.product)

        # NOTE: if you change isolabel, you need to change pungi to match, or
        # the pungi images won't boot.
        isolabel = volid or "%s-%s-%s" % (
            self.product.name, self.product.version, self.arch.basearch)

        if len(isolabel) > 32:
            logger.fatal("the volume id cannot be longer than 32 characters")
            sys.exit(1)

        # NOTE: rb.root = dbo.conf.installroot (== self.inroot)
        rb = RuntimeBuilder(product=self.product,
                            arch=self.arch,
                            dbo=dbo,
                            templatedir=self.templatedir,
                            installpkgs=installpkgs,
                            excludepkgs=excludepkgs,
                            add_templates=add_templates,
                            add_template_vars=add_template_vars)

        logger.info("installing runtime packages")
        rb.install()

        # write .buildstamp
        buildstamp = BuildStamp(self.product.name, self.product.version,
                                self.product.bugurl, self.product.isfinal,
                                self.arch.buildarch, self.product.variant)

        buildstamp.write(joinpaths(self.inroot, ".buildstamp"))

        if self.debug:
            rb.writepkglists(joinpaths(logdir, "pkglists"))
            rb.writepkgsizes(joinpaths(logdir, "original-pkgsizes.txt"))

        logger.info("doing post-install configuration")
        rb.postinstall()

        # write .discinfo
        discinfo = DiscInfo(self.product.release, self.arch.basearch)
        discinfo.write(joinpaths(self.outputdir, ".discinfo"))

        logger.info("backing up installroot")
        installroot = joinpaths(self.workdir, "installroot")
        linktree(self.inroot, installroot)

        logger.info("generating kernel module metadata")
        rb.generate_module_data()

        logger.info("cleaning unneeded files")
        rb.cleanup()

        if verify:
            logger.info("verifying the installroot")
            if not rb.verify():
                sys.exit(1)
        else:
            logger.info("Skipping verify")

        if self.debug:
            rb.writepkgsizes(joinpaths(logdir, "final-pkgsizes.txt"))

        logger.info("creating the runtime image")
        runtime = "images/install.img"
        compression = self.conf.get("compression", "type")
        compressargs = self.conf.get("compression", "args").split()  # pylint: disable=no-member
        if self.conf.getboolean("compression", "bcj"):
            if self.arch.bcj:
                compressargs += ["-Xbcj", self.arch.bcj]
            else:
                logger.info("no BCJ filter for arch %s", self.arch.basearch)
        if squashfs_only:
            # Create an ext4 rootfs.img and compress it with squashfs
            rb.create_squashfs_runtime(joinpaths(installroot, runtime),
                                       compression=compression,
                                       compressargs=compressargs,
                                       size=size)
        else:
            # Create an ext4 rootfs.img and compress it with squashfs
            rb.create_ext4_runtime(joinpaths(installroot, runtime),
                                   compression=compression,
                                   compressargs=compressargs,
                                   size=size)
        rb.finished()

        logger.info("preparing to build output tree and boot images")
        treebuilder = TreeBuilder(product=self.product,
                                  arch=self.arch,
                                  inroot=installroot,
                                  outroot=self.outputdir,
                                  runtime=runtime,
                                  isolabel=isolabel,
                                  domacboot=domacboot,
                                  doupgrade=doupgrade,
                                  templatedir=self.templatedir,
                                  add_templates=add_arch_templates,
                                  add_template_vars=add_arch_template_vars,
                                  workdir=self.workdir)

        logger.info("rebuilding initramfs images")
        if not user_dracut_args:
            dracut_args = DRACUT_DEFAULT
        else:
            dracut_args = []
            for arg in user_dracut_args:
                dracut_args += arg.split(" ", 1)

        anaconda_args = dracut_args + [
            "--add", "anaconda pollcdrom qemu qemu-net"
        ]

        # ppc64 cannot boot an initrd > 32MiB so remove some drivers
        if self.arch.basearch in ("ppc64", "ppc64le"):
            dracut_args.extend(["--omit-drivers", REMOVE_PPC64_DRIVERS])

            # Only omit dracut modules from the initrd so that they're kept for
            # upgrade.img
            anaconda_args.extend(["--omit", REMOVE_PPC64_MODULES])

        logger.info("dracut args = %s", dracut_args)
        logger.info("anaconda args = %s", anaconda_args)
        treebuilder.rebuild_initrds(add_args=anaconda_args)

        logger.info("populating output tree and building boot images")
        treebuilder.build()

        # write .treeinfo file and we're done
        treeinfo = TreeInfo(self.product.name, self.product.version,
                            self.product.variant, self.arch.basearch)
        for section, data in treebuilder.treeinfo_data.items():
            treeinfo.add_section(section, data)
        treeinfo.write(joinpaths(self.outputdir, ".treeinfo"))

        # cleanup
        if remove_temp:
            remove(self.workdir)
Example #46
0
 def Run(self, args):
     runcmd(["dracut"] + args, root=self.root)
Example #47
0
def linktree(src, dst):
    runcmd(["/bin/cp", "-al", src, dst])
Example #48
0
    def run(self,
            dbo,
            product,
            version,
            release,
            variant="",
            bugurl="",
            isfinal=False,
            workdir=None,
            outputdir=None,
            buildarch=None,
            volid=None,
            domacboot=True,
            doupgrade=True,
            remove_temp=False,
            installpkgs=None,
            excludepkgs=None,
            size=2,
            add_templates=None,
            add_template_vars=None,
            add_arch_templates=None,
            add_arch_template_vars=None,
            verify=True):

        assert self._configured

        installpkgs = installpkgs or []
        excludepkgs = excludepkgs or []

        if domacboot:
            try:
                runcmd(["rpm", "-q", "hfsplus-tools"])
            except CalledProcessError:
                logger.critical(
                    "you need to install hfsplus-tools to create mac images")
                sys.exit(1)

        # set up work directory
        self.workdir = workdir or tempfile.mkdtemp(prefix="pylorax.work.")
        if not os.path.isdir(self.workdir):
            os.makedirs(self.workdir)

        # set up log directory
        logdir = self.conf.get("lorax", "logdir")
        if not os.path.isdir(logdir):
            os.makedirs(logdir)

        self.init_stream_logging()
        self.init_file_logging(logdir)

        logger.debug("version is %s", vernum)
        logger.debug("using work directory %s", self.workdir)
        logger.debug("using log directory %s", logdir)

        # set up output directory
        self.outputdir = outputdir or tempfile.mkdtemp(prefix="pylorax.out.")
        if not os.path.isdir(self.outputdir):
            os.makedirs(self.outputdir)
        logger.debug("using output directory %s", self.outputdir)

        # do we have root privileges?
        logger.info("checking for root privileges")
        if not os.geteuid() == 0:
            logger.critical("no root privileges")
            sys.exit(1)

        # is selinux disabled?
        # With selinux in enforcing mode the rpcbind package required for
        # dracut nfs module, which is in turn required by anaconda module,
        # will not get installed, because it's preinstall scriptlet fails,
        # resulting in an incomplete initial ramdisk image.
        # The reason is that the scriptlet runs tools from the shadow-utils
        # package in chroot, particularly groupadd and useradd to add the
        # required rpc group and rpc user. This operation fails, because
        # the selinux context on files in the chroot, that the shadow-utils
        # tools need to access (/etc/group, /etc/passwd, /etc/shadow etc.),
        # is wrong and selinux therefore disallows access to these files.
        logger.info("checking the selinux mode")
        if selinux.is_selinux_enabled() and selinux.security_getenforce():
            logger.critical("selinux must be disabled or in Permissive mode")
            sys.exit(1)

        # do we have a proper dnf base object?
        logger.info("checking dnf base object")
        if not isinstance(dbo, dnf.Base):
            logger.critical("no dnf base object")
            sys.exit(1)
        self.inroot = dbo.conf.installroot
        logger.debug("using install root: %s", self.inroot)

        if not buildarch:
            buildarch = get_buildarch(dbo)

        logger.info("setting up build architecture")
        self.arch = ArchData(buildarch)
        for attr in ('buildarch', 'basearch', 'libdir'):
            logger.debug("self.arch.%s = %s", attr, getattr(self.arch, attr))

        logger.info("setting up build parameters")
        self.product = DataHolder(name=product,
                                  version=version,
                                  release=release,
                                  variant=variant,
                                  bugurl=bugurl,
                                  isfinal=isfinal)
        logger.debug("product data: %s", self.product)

        # NOTE: if you change isolabel, you need to change pungi to match, or
        # the pungi images won't boot.
        isolabel = volid or "%s-%s-%s" % (
            self.product.name, self.product.version, self.arch.basearch)

        if len(isolabel) > 32:
            logger.fatal("the volume id cannot be longer than 32 characters")
            sys.exit(1)

        # NOTE: rb.root = dbo.conf.installroot (== self.inroot)
        rb = RuntimeBuilder(product=self.product,
                            arch=self.arch,
                            dbo=dbo,
                            templatedir=self.templatedir,
                            installpkgs=installpkgs,
                            excludepkgs=excludepkgs,
                            add_templates=add_templates,
                            add_template_vars=add_template_vars)

        logger.info("installing runtime packages")
        rb.install()

        # write .buildstamp
        buildstamp = BuildStamp(self.product.name, self.product.version,
                                self.product.bugurl, self.product.isfinal,
                                self.arch.buildarch, self.product.variant)

        buildstamp.write(joinpaths(self.inroot, ".buildstamp"))

        if self.debug:
            rb.writepkglists(joinpaths(logdir, "pkglists"))
            rb.writepkgsizes(joinpaths(logdir, "original-pkgsizes.txt"))

        logger.info("doing post-install configuration")
        rb.postinstall()

        # write .discinfo
        discinfo = DiscInfo(self.product.release, self.arch.basearch)
        discinfo.write(joinpaths(self.outputdir, ".discinfo"))

        logger.info("backing up installroot")
        installroot = joinpaths(self.workdir, "installroot")
        linktree(self.inroot, installroot)

        logger.info("generating kernel module metadata")
        rb.generate_module_data()

        logger.info("cleaning unneeded files")
        rb.cleanup()

        if verify:
            logger.info("verifying the installroot")
            if not rb.verify():
                sys.exit(1)
        else:
            logger.info("Skipping verify")

        if self.debug:
            rb.writepkgsizes(joinpaths(logdir, "final-pkgsizes.txt"))

        logger.info("creating the runtime image")
        runtime = "images/install.img"
        compression = self.conf.get("compression", "type")
        compressargs = self.conf.get("compression", "args").split()  # pylint: disable=no-member
        if self.conf.getboolean("compression", "bcj"):
            if self.arch.bcj:
                compressargs += ["-Xbcj", self.arch.bcj]
            else:
                logger.info("no BCJ filter for arch %s", self.arch.basearch)
        rb.create_runtime(joinpaths(installroot, runtime),
                          compression=compression,
                          compressargs=compressargs,
                          size=size)
        rb.finished()

        logger.info("preparing to build output tree and boot images")
        treebuilder = TreeBuilder(product=self.product,
                                  arch=self.arch,
                                  inroot=installroot,
                                  outroot=self.outputdir,
                                  runtime=runtime,
                                  isolabel=isolabel,
                                  domacboot=domacboot,
                                  doupgrade=doupgrade,
                                  templatedir=self.templatedir,
                                  add_templates=add_arch_templates,
                                  add_template_vars=add_arch_template_vars,
                                  workdir=self.workdir)

        logger.info("rebuilding initramfs images")
        dracut_args = [
            "--xz", "--install", "/.buildstamp", "--no-early-microcode",
            "--add", "fips"
        ]
        anaconda_args = dracut_args + [
            "--add", "anaconda pollcdrom qemu qemu-net"
        ]

        # ppc64 cannot boot an initrd > 32MiB so remove some drivers
        if self.arch.basearch in ("ppc64", "ppc64le"):
            dracut_args.extend(["--omit-drivers", REMOVE_PPC64_DRIVERS])

            # Only omit dracut modules from the initrd so that they're kept for
            # upgrade.img
            anaconda_args.extend(["--omit", REMOVE_PPC64_MODULES])

        treebuilder.rebuild_initrds(add_args=anaconda_args)

        logger.info("populating output tree and building boot images")
        treebuilder.build()

        # write .treeinfo file and we're done
        treeinfo = TreeInfo(self.product.name, self.product.version,
                            self.product.variant, self.arch.basearch)
        for section, data in treebuilder.treeinfo_data.items():
            treeinfo.add_section(section, data)
        treeinfo.write(joinpaths(self.outputdir, ".treeinfo"))

        # cleanup
        if remove_temp:
            remove(self.workdir)