Example #1
0
 def __init__(self,
              product,
              arch,
              yum,
              templatedir=None,
              add_templates=None,
              add_template_vars=None):
     root = yum.conf.installroot
     # use a copy of product so we can modify it locally
     product = product.copy()
     product.name = product.name.lower()
     self.vars = DataHolder(arch=arch,
                            product=product,
                            yum=yum,
                            root=root,
                            basearch=arch.basearch,
                            libdir=arch.libdir)
     self.yum = yum
     self._runner = LoraxTemplateRunner(inroot=root,
                                        outroot=root,
                                        yum=yum,
                                        templatedir=templatedir)
     self.add_templates = add_templates or []
     self.add_template_vars = add_template_vars or {}
     self._runner.defaults = self.vars
Example #2
0
 def __init__(self,
              product,
              arch,
              inroot,
              outroot,
              runtime,
              isolabel,
              domacboot=False,
              doupgrade=True,
              templatedir=None):
     # NOTE: if you pass an arg named "runtime" to a mako template it'll
     # clobber some mako internal variables - hence "runtime_img".
     self.vars = DataHolder(arch=arch,
                            product=product,
                            runtime_img=runtime,
                            runtime_base=basename(runtime),
                            inroot=inroot,
                            outroot=outroot,
                            basearch=arch.basearch,
                            libdir=arch.libdir,
                            isolabel=isolabel,
                            udev=udev_escape,
                            domacboot=domacboot,
                            doupgrade=doupgrade)
     self._runner = LoraxTemplateRunner(inroot,
                                        outroot,
                                        templatedir=templatedir)
     self._runner.defaults = self.vars
     self.templatedir = templatedir
Example #3
0
 def __init__(self, product, arch, yum, templatedir=None):
     root = yum.conf.installroot
     # use a copy of product so we can modify it locally
     product = product.copy()
     product.name = product.name.lower()
     self.vars = DataHolder(arch=arch, product=product, yum=yum, root=root,
                            basearch=arch.basearch, libdir=arch.libdir)
     self.yum = yum
     self._runner = LoraxTemplateRunner(inroot=root, outroot=root,
                                        yum=yum, templatedir=templatedir)
     self._runner.defaults = self.vars
Example #4
0
 def __init__(self, product, arch, inroot, outroot, runtime, isolabel, domacboot=False, doupgrade=True, templatedir=None):
     # NOTE: if you pass an arg named "runtime" to a mako template it'll
     # clobber some mako internal variables - hence "runtime_img".
     self.vars = DataHolder(arch=arch, product=product, runtime_img=runtime,
                            runtime_base=basename(runtime),
                            inroot=inroot, outroot=outroot,
                            basearch=arch.basearch, libdir=arch.libdir,
                            isolabel=isolabel, udev=udev_escape, domacboot=domacboot, doupgrade=doupgrade)
     self._runner = LoraxTemplateRunner(inroot, outroot, templatedir=templatedir)
     self._runner.defaults = self.vars
     self.templatedir = templatedir
Example #5
0
class RuntimeBuilder(object):
    '''Builds the anaconda runtime image.'''
    def __init__(self, product, arch, yum, templatedir=None):
        root = yum.conf.installroot
        # use a copy of product so we can modify it locally
        product = product.copy()
        product.name = product.name.lower()
        self.vars = DataHolder(arch=arch, product=product, yum=yum, root=root,
                               basearch=arch.basearch, libdir=arch.libdir)
        self.yum = yum
        self._runner = LoraxTemplateRunner(inroot=root, outroot=root,
                                           yum=yum, templatedir=templatedir)
        self._runner.defaults = self.vars

    def _install_branding(self):
        release = None
        for pkg in self.yum.whatProvides('/etc/system-release', None, None):
            if pkg.name.startswith('generic'):
                continue
            else:
                release = pkg.name
                break

        if not release:
            logger.error('could not get the release')
            return

        # release
        logger.info('got release: %s', release)
        self._runner.installpkg(release)

        # logos
        release, _suffix = release.split('-', 1)
        self._runner.installpkg('%s-logos' % release)

    def install(self):
        '''Install packages and do initial setup with runtime-install.tmpl'''
        self._install_branding()
        self._runner.run("runtime-install.tmpl")

    def writepkglists(self, pkglistdir):
        '''debugging data: write out lists of package contents'''
        if not os.path.isdir(pkglistdir):
            os.makedirs(pkglistdir)
        for pkgobj in self.yum.doPackageLists(pkgnarrow='installed').installed:
            with open(joinpaths(pkglistdir, pkgobj.name), "w") as fobj:
                for fname in pkgobj.filelist + pkgobj.dirlist:
                    fobj.write("{0}\n".format(fname))

    def postinstall(self):
        '''Do some post-install setup work with runtime-postinstall.tmpl'''
        # copy configdir into runtime root beforehand
        configdir = joinpaths(self._runner.templatedir,"config_files")
        configdir_path = "tmp/config_files"
        fullpath = joinpaths(self.vars.root, configdir_path)
        if os.path.exists(fullpath):
            remove(fullpath)
        copytree(configdir, fullpath)
        self._runner.run("runtime-postinstall.tmpl", configdir=configdir_path)

    def cleanup(self):
        '''Remove unneeded packages and files with runtime-cleanup.tmpl'''
        self._runner.run("runtime-cleanup.tmpl")

    def writepkgsizes(self, pkgsizefile):
        '''debugging data: write a big list of pkg sizes'''
        fobj = open(pkgsizefile, "w")
        getsize = lambda f: os.lstat(f).st_size if os.path.exists(f) else 0
        for p in sorted(self.yum.doPackageLists(pkgnarrow='installed').installed):
            pkgsize = sum(getsize(joinpaths(self.vars.root,f)) for f in p.filelist)
            fobj.write("{0.name}.{0.arch}: {1}\n".format(p, pkgsize))

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

    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 #6
0
class TreeBuilder(object):
    '''Builds the arch-specific boot images.
    inroot should be the installtree root (the newly-built runtime dir)'''
    def __init__(self, product, arch, inroot, outroot, runtime, isolabel, domacboot=False, doupgrade=True, templatedir=None):
        # NOTE: if you pass an arg named "runtime" to a mako template it'll
        # clobber some mako internal variables - hence "runtime_img".
        self.vars = DataHolder(arch=arch, product=product, runtime_img=runtime,
                               runtime_base=basename(runtime),
                               inroot=inroot, outroot=outroot,
                               basearch=arch.basearch, libdir=arch.libdir,
                               isolabel=isolabel, udev=udev_escape, domacboot=domacboot, doupgrade=doupgrade)
        self._runner = LoraxTemplateRunner(inroot, outroot, templatedir=templatedir)
        self._runner.defaults = self.vars
        self.templatedir = templatedir

    @property
    def kernels(self):
        return findkernels(root=self.vars.inroot)

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

    def build(self):
        templatefile = templatemap[self.vars.arch.basearch]
        self._runner.run(templatefile, kernels=self.kernels)
        self.treeinfo_data = self._runner.results.treeinfo
        self.implantisomd5()

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

    @property
    def dracut_hooks_path(self):
        """ Return the path to the lorax dracut hooks scripts

            Use the configured share dir if it is setup,
            otherwise default to /usr/share/lorax/dracut_hooks
        """
        if self.templatedir:
            return joinpaths(self.templatedir, "dracut_hooks")
        else:
            return "/usr/share/lorax/dracut_hooks"

    def copy_dracut_hooks(self, hooks):
        """ Copy the hook scripts in hooks into the installroot's /tmp/
        and return a list of commands to pass to dracut when creating the
        initramfs

        hooks is a list of tuples with the name of the hook script and the
        target dracut hook directory
        (eg. [("99anaconda-copy-ks.sh", "/lib/dracut/hooks/pre-pivot")])
        """
        dracut_commands = []
        for hook_script, dracut_path in hooks:
            src = joinpaths(self.dracut_hooks_path, hook_script)
            if not os.path.exists(src):
                logger.error("Missing lorax dracut hook script %s" % (src))
                continue
            dst = joinpaths(self.vars.inroot, "/tmp/", hook_script)
            copy2(src, dst)
            dracut_commands += ["--include", joinpaths("/tmp/", hook_script),
                                dracut_path]
        return dracut_commands
Example #7
0
class RuntimeBuilder(object):
    '''Builds the anaconda runtime image.'''
    def __init__(self,
                 product,
                 arch,
                 yum,
                 templatedir=None,
                 add_templates=None,
                 add_template_vars=None):
        root = yum.conf.installroot
        # use a copy of product so we can modify it locally
        product = product.copy()
        product.name = product.name.lower()
        self.vars = DataHolder(arch=arch,
                               product=product,
                               yum=yum,
                               root=root,
                               basearch=arch.basearch,
                               libdir=arch.libdir)
        self.yum = yum
        self._runner = LoraxTemplateRunner(inroot=root,
                                           outroot=root,
                                           yum=yum,
                                           templatedir=templatedir)
        self.add_templates = add_templates or []
        self.add_template_vars = add_template_vars or {}
        self._runner.defaults = self.vars

    def _install_branding(self):
        release = None
        for pkg in self.yum.whatProvides('/etc/system-release', None, None):
            if pkg.name.startswith('generic'):
                continue
            else:
                release = pkg.name
                break

        if not release:
            logger.error('could not get the release')
            return

        # release
        logger.info('got release: %s', release)
        self._runner.installpkg(release)

        # logos
        release, _suffix = release.split('-', 1)
        self._runner.installpkg('%s-logos' % release)

    def install(self):
        '''Install packages and do initial setup with runtime-install.tmpl'''
        self._install_branding()
        self._runner.run("runtime-install.tmpl")
        for tmpl in self.add_templates:
            self._runner.run(tmpl, **self.add_template_vars)

    def writepkglists(self, pkglistdir):
        '''debugging data: write out lists of package contents'''
        if not os.path.isdir(pkglistdir):
            os.makedirs(pkglistdir)
        for pkgobj in self.yum.doPackageLists(pkgnarrow='installed').installed:
            with open(joinpaths(pkglistdir, pkgobj.name), "w") as fobj:
                for fname in pkgobj.filelist + pkgobj.dirlist:
                    fobj.write("{0}\n".format(fname))

    def postinstall(self):
        '''Do some post-install setup work with runtime-postinstall.tmpl'''
        # copy configdir into runtime root beforehand
        configdir = joinpaths(self._runner.templatedir, "config_files")
        configdir_path = "tmp/config_files"
        fullpath = joinpaths(self.vars.root, configdir_path)
        if os.path.exists(fullpath):
            remove(fullpath)
        copytree(configdir, fullpath)
        self._runner.run("runtime-postinstall.tmpl", configdir=configdir_path)

    def cleanup(self):
        '''Remove unneeded packages and files with runtime-cleanup.tmpl'''
        self._runner.run("runtime-cleanup.tmpl")

    def writepkgsizes(self, pkgsizefile):
        '''debugging data: write a big list of pkg sizes'''
        fobj = open(pkgsizefile, "w")
        getsize = lambda f: os.lstat(f).st_size if os.path.exists(f) else 0
        for p in sorted(
                self.yum.doPackageLists(pkgnarrow='installed').installed):
            pkgsize = sum(
                getsize(joinpaths(self.vars.root, f)) for f in p.filelist)
            fobj.write("{0.name}.{0.arch}: {1}\n".format(p, pkgsize))

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

    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")
        os.makedirs(joinpaths(workdir, "LiveOS"))

        imgutils.mkrootfsimg(self.vars.root,
                             joinpaths(workdir, "LiveOS/rootfs.img"),
                             "Anaconda",
                             size=size)

        # squash the live rootfs and clean up workdir
        imgutils.mksquashfs(workdir, outfile, compression, compressargs)
        remove(workdir)
Example #8
0
class TreeBuilder(object):
    '''Builds the arch-specific boot images.
    inroot should be the installtree root (the newly-built runtime dir)'''
    def __init__(self,
                 product,
                 arch,
                 inroot,
                 outroot,
                 runtime,
                 isolabel,
                 domacboot=False,
                 doupgrade=True,
                 templatedir=None,
                 add_templates=None,
                 add_template_vars=None,
                 workdir=None):

        # NOTE: if you pass an arg named "runtime" to a mako template it'll
        # clobber some mako internal variables - hence "runtime_img".
        self.vars = DataHolder(arch=arch,
                               product=product,
                               runtime_img=runtime,
                               runtime_base=basename(runtime),
                               inroot=inroot,
                               outroot=outroot,
                               basearch=arch.basearch,
                               libdir=arch.libdir,
                               isolabel=isolabel,
                               udev=udev_escape,
                               domacboot=domacboot,
                               doupgrade=doupgrade,
                               workdir=workdir)
        self._runner = LoraxTemplateRunner(inroot,
                                           outroot,
                                           templatedir=templatedir)
        self._runner.defaults = self.vars
        self.add_templates = add_templates or []
        self.add_template_vars = add_template_vars or {}
        self.templatedir = templatedir

    @property
    def kernels(self):
        return findkernels(root=self.vars.inroot)

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

    def build(self):
        templatefile = templatemap[self.vars.arch.basearch]
        for tmpl in self.add_templates:
            self._runner.run(tmpl, **self.add_template_vars)
        self._runner.run(templatefile, kernels=self.kernels)
        self.treeinfo_data = self._runner.results.treeinfo
        self.implantisomd5()

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

    @property
    def dracut_hooks_path(self):
        """ Return the path to the lorax dracut hooks scripts

            Use the configured share dir if it is setup,
            otherwise default to /usr/share/lorax/dracut_hooks
        """
        if self.templatedir:
            return joinpaths(self.templatedir, "dracut_hooks")
        else:
            return "/usr/share/lorax/dracut_hooks"

    def copy_dracut_hooks(self, hooks):
        """ Copy the hook scripts in hooks into the installroot's /tmp/
        and return a list of commands to pass to dracut when creating the
        initramfs

        hooks is a list of tuples with the name of the hook script and the
        target dracut hook directory
        (eg. [("99anaconda-copy-ks.sh", "/lib/dracut/hooks/pre-pivot")])
        """
        dracut_commands = []
        for hook_script, dracut_path in hooks:
            src = joinpaths(self.dracut_hooks_path, hook_script)
            if not os.path.exists(src):
                logger.error("Missing lorax dracut hook script %s" % (src))
                continue
            dst = joinpaths(self.vars.inroot, "/tmp/", hook_script)
            copy2(src, dst)
            dracut_commands += [
                "--include",
                joinpaths("/tmp/", hook_script), dracut_path
            ]
        return dracut_commands