def anaconda_cleanup(dirinstall_path): """ Cleanup any leftover mounts from anaconda :param str dirinstall_path: Path where anaconda mounts things :returns: True if cleanups were successful. False if any of them failed. If anaconda crashes it may leave things mounted under this path. It will typically be set to /mnt/sysimage/ Attempts to cleanup may also fail. Catch these and continue trying the other mountpoints. """ rc = True dirinstall_path = os.path.abspath(dirinstall_path) # unmount filesystems for mounted in reversed(open("/proc/mounts").readlines()): (_device, mountpoint, _rest) = mounted.split(" ", 2) if mountpoint.startswith(dirinstall_path) and os.path.ismount( mountpoint): try: umount(mountpoint) except subprocess.CalledProcessError: log.error("Cleanup of %s failed. See program.log for details", mountpoint) rc = False return rc
def mount_boot_part_over_root(img_mount): """ Mount boot partition to /boot of root fs mounted in img_mount Used for OSTree so it finds deployment configurations on live rootfs param img_mount: object with mounted disk image root partition type img_mount: imgutils.PartitionMount """ root_dir = img_mount.mount_dir is_boot_part = lambda dir: os.path.exists(dir + "/loader.0") tmp_mount_dir = tempfile.mkdtemp(prefix="lmc-tmpdir-") sysroot_boot_dir = None for dev, _size in img_mount.loop_devices: if dev is img_mount.mount_dev: continue try: mount("/dev/mapper/" + dev, mnt=tmp_mount_dir) if is_boot_part(tmp_mount_dir): umount(tmp_mount_dir) sysroot_boot_dir = joinpaths(root_dir, "boot") mount("/dev/mapper/" + dev, mnt=sysroot_boot_dir) break else: umount(tmp_mount_dir) except subprocess.CalledProcessError as e: log.debug("Looking for boot partition error: %s", e) remove(tmp_mount_dir) return sysroot_boot_dir
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
def anaconda_cleanup(dirinstall_path): """ Cleanup any leftover mounts from anaconda :param str dirinstall_path: Path where anaconda mounts things :returns: True if cleanups were successful. False if any of them failed. If anaconda crashes it may leave things mounted under this path. It will typically be set to /mnt/sysimage/ Attempts to cleanup may also fail. Catch these and continue trying the other mountpoints. Anaconda may also leave /run/anaconda.pid behind, clean that up as well. """ # Anaconda may not clean up its /var/run/anaconda.pid file # Make sure the process is really finished (it should be, since it was started from a subprocess call) # and then remove the pid file. if os.path.exists("/var/run/anaconda.pid"): # lorax-composer runs anaconda using unshare so the pid is always 1 if open("/var/run/anaconda.pid").read().strip() == "1": os.unlink("/var/run/anaconda.pid") rc = True dirinstall_path = os.path.abspath(dirinstall_path) # unmount filesystems for mounted in reversed(open("/proc/mounts").readlines()): (_device, mountpoint, _rest) = mounted.split(" ", 2) if mountpoint.startswith(dirinstall_path) and os.path.ismount(mountpoint): try: umount(mountpoint) except subprocess.CalledProcessError: log.error("Cleanup of %s failed. See program.log for details", mountpoint) rc = False return rc
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)
def make_live_images(opts, work_dir, disk_img): """ Create live images from direcory or rootfs image :param opts: options passed to livemedia-creator :type opts: argparse options :param str work_dir: Directory for storing results :param str disk_img: Path to disk image (fsimage or partitioned) :returns: Path of directory with created images or None :rtype: str fsck.ext4 is run on the rootfs_image to make sure there are no errors and to zero out any deleted blocks to make it compress better. If this fails for any reason it will return None and log the error. """ sys_root = "" squashfs_root_dir = joinpaths(work_dir, "squashfs_root") liveos_dir = joinpaths(squashfs_root_dir, "LiveOS") os.makedirs(liveos_dir) rootfs_img = joinpaths(liveos_dir, "rootfs.img") if opts.fs_image or opts.no_virt: # Find the ostree root in the fsimage if opts.ostree: with Mount(disk_img, opts="loop") as mnt_dir: sys_root = find_ostree_root(mnt_dir) # Try to hardlink the image, if that fails, copy it rc = execWithRedirect("/bin/ln", [disk_img, rootfs_img]) if rc != 0: shutil.copy2(disk_img, rootfs_img) else: is_root_part = None if opts.ostree: is_root_part = lambda dir: os.path.exists(dir + "/ostree/deploy") with PartitionMount(disk_img, mount_ok=is_root_part) as img_mount: if img_mount and img_mount.mount_dir: try: mounted_sysroot_boot_dir = None if opts.ostree: sys_root = find_ostree_root(img_mount.mount_dir) mounted_sysroot_boot_dir = mount_boot_part_over_root( img_mount) if opts.live_rootfs_keep_size: size = img_mount.mount_size / 1024**3 else: size = opts.live_rootfs_size or None log.info("Creating live rootfs image") mkrootfsimg(img_mount.mount_dir, rootfs_img, "LiveOS", size=size, sysroot=sys_root) finally: if mounted_sysroot_boot_dir: umount(mounted_sysroot_boot_dir) log.debug("sys_root = %s", sys_root) # Make sure free blocks are actually zeroed so it will compress rc = execWithRedirect("/usr/sbin/fsck.ext4", ["-y", "-f", "-E", "discard", rootfs_img]) if rc != 0: log.error("Problem zeroing free blocks of %s", disk_img) return None log.info("Packing live rootfs image") add_pxe_args = [] live_image_name = "live-rootfs.squashfs.img" compression, compressargs = squashfs_args(opts) mksquashfs(squashfs_root_dir, joinpaths(work_dir, live_image_name), compression, compressargs) log.info("Rebuilding initramfs for live") with Mount(rootfs_img, opts="loop") as mnt_dir: try: mount(joinpaths(mnt_dir, "boot"), opts="bind", mnt=joinpaths(mnt_dir, sys_root, "boot")) rebuild_initrds_for_live(opts, joinpaths(mnt_dir, sys_root), work_dir) finally: umount(joinpaths(mnt_dir, sys_root, "boot"), delete=False) remove(squashfs_root_dir) if opts.ostree: add_pxe_args.append("ostree=/%s" % sys_root) template = joinpaths(opts.lorax_templates, "pxe-live/pxe-config.tmpl") create_pxe_config(template, work_dir, live_image_name, add_pxe_args) return work_dir
def umount(self): """Unmount the iso""" if not self.initrd_path: umount(self.mount_dir)
def umount( self ): """Unmount the iso""" if not self.initrd_path: umount(self.mount_dir)