Example #1
0
class SELinux(object):
    """On SELinux enabled box, this plugin will pretend, that SELinux is disabled in build environment.

       - fake /proc/filesystems is mounted into build environment, excluding selinuxfs
       - option '--setopt=tsflags=nocontext' is appended to each 'yum' command
    """

    decorate(traceLog())

    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.conf = conf

        self.filesystems = self._selinuxCreateFauxFilesystems()
        self.chrootFilesystems = rootObj.makeChrootPath("/proc/filesystems")

        atexit.register(self._selinuxAtExit)

        self.rootObj.mounts.add(
            BindMountPoint(srcpath=self.filesystems,
                           bindpath=self.chrootFilesystems))

        if self._selinuxYumIsSetoptSupported():
            rootObj.addHook("preyum", self._selinuxPreYumHook)
            rootObj.addHook("postyum", self._selinuxPostYumHook)
        else:
            getLog().warning(
                "selinux: 'yum' does not support '--setopt' option")

    decorate(traceLog())

    def _selinuxCreateFauxFilesystems(self):
        (fd, path) = tempfile.mkstemp(prefix="mock-selinux-plugin.")

        host = open("/proc/filesystems")
        try:
            for line in host:
                if not "selinuxfs" in line:
                    os.write(fd, line)
        finally:
            host.close()

        os.close(fd)
        os.chmod(path, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)

        return path

    decorate(traceLog())

    def _selinuxAtExit(self):
        if os.path.exists(self.filesystems):
            try:
                os.unlink(self.filesystems)
            except OSError, e:
                getLog().warning(
                    "unable to delete selinux filesystems (%s): %s" %
                    (self.filesystems, e))
                pass
Example #2
0
    def test_generator(self, captured):
        trace_decorator.traceLog()(exampleGenerator)()

        self.assertEqual(2, len(captured))

        msg = captured[0][2][2]
        self.assertEqual("ENTER exampleGenerator()", msg)
        msg = captured[1][2][2]
        self.assertIn("LEAVE exampleGenerator --> <generator object exampleGenerator at ", msg)
Example #3
0
    def test_generator(self, captured):
        trace_decorator.traceLog()(exampleGenerator)()

        self.assertEqual(2, len(captured))

        msg = captured[0][2][2]
        self.assertEqual('ENTER exampleGenerator()', msg)
        msg = captured[1][2][2]
        self.assertIn(
            'LEAVE exampleGenerator --> <generator object exampleGenerator at ',
            msg)
Example #4
0
class Tmpfs(object):
    """Mounts a tmpfs on the chroot dir"""
    decorate(traceLog())

    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.conf = conf
        self.maxSize = self.conf['max_fs_size']
        self.mode = self.conf['mode']
        self.optArgs = ['-o', 'mode=%s' % self.mode]
        if self.maxSize:
            self.optArgs += ['-o', 'size=' + self.maxSize]
        rootObj.addHook("preinit", self._tmpfsMount)
        rootObj.addHook("preshell", self._tmpfsMount)
        rootObj.addHook("prechroot", self._tmpfsMount)
        rootObj.addHook("postshell", self._tmpfsUmount)
        rootObj.addHook("postbuild", self._tmpfsUmount)
        rootObj.addHook("postchroot", self._tmpfsUmount)
        rootObj.addHook("initfailed", self._tmpfsUmount)
        getLog().info("tmpfs initialized")

    decorate(traceLog())

    def _tmpfsMount(self):
        getLog().info("mounting tmpfs at %s." % self.rootObj.makeChrootPath())
        mountCmd = ["mount", "-n", "-t", "tmpfs"] + self.optArgs + \
                   ["mock_chroot_tmpfs", self.rootObj.makeChrootPath()]
        mockbuild.util.do(mountCmd, shell=False)

    decorate(traceLog())

    def _tmpfsUmount(self):
        force = False
        getLog().info("unmounting tmpfs.")
        umountCmd = ["umount", "-n", self.rootObj.makeChrootPath()]
        # since we're in a separate namespace, the mount will be cleaned up
        # on exit, so just warn if it fails here
        try:
            mockbuild.util.do(umountCmd, shell=False)
        except:
            getLog().warning(
                "tmpfs-plugin: exception while umounting tmpfs! (cwd: %s)" %
                os.getcwd())
            force = True

        if force:
            # try umounting with force option
            umountCmd = ["umount", "-n", "-f", self.rootObj.makeChrootPath()]
            try:
                mockbuild.util.do(umountCmd, shell=False)
            except:
                getLog().warning(
                    "tmpfs-plugin: exception while force umounting tmpfs! (cwd: %s)"
                    % os.getcwd())
Example #5
0
    def test_exception(self, captured):
        try:
            trace_decorator.traceLog()(exampleRaising)('aaa')
        except MyException:
            pass

        self.assertEqual(3, len(captured))
        msg, kw = captured[1][2][2], captured[1][3]
        self.assertTrue(kw['exc_info'])
        self.assertEquals("EXCEPTION: test exception\n", msg)
        msg = captured[2][2][2]
        self.assertEqual("LEAVE exampleRaising --> EXCEPTION RAISED\n", msg)
Example #6
0
    def test_exception(self, captured):
        try:
            trace_decorator.traceLog()(exampleRaising)("aaa")
        except MyException:
            pass

        self.assertEqual(3, len(captured))
        msg, kw = captured[1][2][2], captured[1][3]
        self.assertTrue(kw["exc_info"])
        self.assertEquals("EXCEPTION: test exception\n", msg)
        msg = captured[2][2][2]
        self.assertEqual("LEAVE exampleRaising --> EXCEPTION RAISED\n", msg)
Example #7
0
    def test_nested(self, captured):
        trace_decorator.traceLog()(exampleNested)(arg='ggg')

        self.assertEqual(4, len(captured))

        msg = captured[0][2][2]
        self.assertEqual("ENTER exampleNested(arg='ggg')", msg)
        msg = captured[1][2][2]
        self.assertEqual("ENTER exampleFunc('bbb', arg='ggg')", msg)
        msg = captured[2][2][2]
        self.assertEqual("LEAVE exampleFunc --> 42\n", msg)
        msg = captured[3][2][2]
        self.assertEqual("LEAVE exampleNested --> 42\n", msg)
Example #8
0
    def test_nested(self, captured):
        trace_decorator.traceLog()(exampleNested)(arg="ggg")

        self.assertEqual(4, len(captured))

        msg = captured[0][2][2]
        self.assertEqual("ENTER exampleNested(arg='ggg')", msg)
        msg = captured[1][2][2]
        self.assertEqual("ENTER exampleFunc('bbb', arg='ggg')", msg)
        msg = captured[2][2][2]
        self.assertEqual("LEAVE exampleFunc --> 42\n", msg)
        msg = captured[3][2][2]
        self.assertEqual("LEAVE exampleNested --> 42\n", msg)
Example #9
0
class MountPoint(object):
    '''base class for mounts'''
    decorate(traceLog())

    def __init__(self, mountsource, mountpath):
        self.mountpath = mountpath
        self.mountsource = mountsource

    decorate(traceLog())

    def ismounted(self):
        if self.mountpath in [x.split()[1] for x in open('/proc/mounts')]:
            return True
        return False
Example #10
0
class CCache(object):
    """enables ccache in buildroot/rpmbuild"""
    decorate(traceLog())

    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.ccache_opts = conf
        self.ccachePath = self.ccache_opts['dir'] % self.ccache_opts
        rootObj.ccacheObj = self
        rootObj.preExistingDeps.append("ccache")
        rootObj.addHook("prebuild", self._ccacheBuildHook)
        rootObj.addHook("preinit", self._ccachePreInitHook)
        rootObj.mounts.add(
            BindMountPoint(srcpath=self.ccachePath,
                           bindpath=rootObj.makeChrootPath("/tmp/ccache")))

    # =============
    # 'Private' API
    # =============
    # set the max size before we actually use it during a build. ccache itself
    # manages size and settings. we also set a few variables used by ccache to
    # find the shared cache.
    decorate(traceLog())

    def _ccacheBuildHook(self):
        self.rootObj.doChroot(
            ["ccache", "-M",
             str(self.ccache_opts['max_cache_size'])],
            shell=False)

    # set up the ccache dir.
    # we also set a few variables used by ccache to find the shared cache.
    decorate(traceLog())

    def _ccachePreInitHook(self):
        getLog().info("enabled ccache")
        envupd = {"CCACHE_DIR": "/tmp/ccache", "CCACHE_UMASK": "002"}
        if self.ccache_opts.get('compress') is not None:
            envupd["CCACHE_COMPRESS"] = str(self.ccache_opts['compress'])
        self.rootObj.env.update(envupd)

        mockbuild.util.mkdirIfAbsent(
            self.rootObj.makeChrootPath('/tmp/ccache'))
        mockbuild.util.mkdirIfAbsent(self.ccachePath)
        self.rootObj.uidManager.changeOwner(self.ccachePath)
Example #11
0
class RootCache(object):
    """caches root environment in a tarball"""
    decorate(traceLog())
    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.root_cache_opts = conf
        self.rootSharedCachePath = self.root_cache_opts['dir'] % self.root_cache_opts
        self.rootCacheFile = os.path.join(self.rootSharedCachePath, "cache.tar")
        self.rootCacheLock = None
        self.compressProgram = self.root_cache_opts['compress_program']
        if self.compressProgram == 'pigz' and not os.path.exists('/usr/bin/pigz'):
            getLog().warning("specified 'pigz' as the root cache compress program but not available; using gzip")
            self.compressProgram = 'gzip'
        if self.compressProgram:
             self.compressArgs = ['--use-compress-program', self.compressProgram]
             self.rootCacheFile = self.rootCacheFile + self.root_cache_opts['extension']
        else:
             self.compressArgs = []
        rootObj.rootCacheObj = self
        rootObj.addHook("preinit", self._rootCachePreInitHook)
        rootObj.addHook("preshell", self._rootCachePreShellHook)
        rootObj.addHook("prechroot", self._rootCachePreShellHook)
        rootObj.addHook("preyum", self._rootCachePreYumHook)
        rootObj.addHook("postinit", self._rootCachePostInitHook)
        rootObj.addHook("postshell", self._rootCachePostShellHook)
        rootObj.addHook("postchroot", self._rootCachePostShellHook)
        rootObj.addHook("postyum", self._rootCachePostShellHook)
        self.exclude_dirs = self.root_cache_opts['exclude_dirs']
        self.exclude_tar_cmds = [ "--exclude=" + dir for dir in self.exclude_dirs]

    # =============
    # 'Private' API
    # =============
    decorate(traceLog())
    def _rootCacheLock(self, shared=1):
        lockType = fcntl.LOCK_EX
        if shared: lockType = fcntl.LOCK_SH
        try:
            fcntl.lockf(self.rootCacheLock.fileno(), lockType | fcntl.LOCK_NB)
        except IOError, e:
            self.rootObj.start("Waiting for rootcache lock")
            fcntl.lockf(self.rootCacheLock.fileno(), lockType)
            self.rootObj.finish("Waiting for rootcache lock")
Example #12
0
    def test_capture(self, captured):
        trace_decorator.traceLog()(exampleFunc)('aaa')
        callLineno = getLineno() - 1

        expectations = [(default_logger, logging.INFO,
                         (filename, callLineno, "ENTER exampleFunc('aaa')"), {
                             'exc_info': None,
                             'args': [],
                             'func': 'test_capture'
                         }),
                        (default_logger, logging.INFO,
                         (filename, getLineno(exampleFunc),
                          "LEAVE exampleFunc --> 42\n"), {
                              'exc_info': None,
                              'args': [],
                              'func': 'exampleFunc'
                          })]

        self.assertEqual(expectations, captured)
Example #13
0
class PackageState(object):
    """dumps out a list of packages available and in the chroot"""
    decorate(traceLog())

    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.avail_done = False
        self.inst_done = False
        self.online = rootObj.online
        rootObj.addHook("postyum", self._availablePostYumHook)
        rootObj.addHook("prebuild", self._installedPreBuildHook)

    decorate(traceLog())

    def _availablePostYumHook(self):
        if self.online and not self.avail_done:
            self.rootObj.uidManager.dropPrivsTemp()
            self.rootObj.start("Outputting list of available packages")
            out_file = self.rootObj.resultdir + '/available_pkgs'
            cmd = "/usr/bin/repoquery -c %s/etc/yum.conf %s > %s" % (
                self.rootObj.makeChrootPath(), repoquery_avail_opts, out_file)
            mockbuild.util.do(cmd, shell=True)
            self.avail_done = True
            self.rootObj.finish("Outputting list of available packages")
            self.rootObj.uidManager.restorePrivs()

    decorate(traceLog())

    def _installedPreBuildHook(self):
        if self.online and not self.inst_done:
            self.rootObj.start("Outputting list of installed packages")
            fd, fn = tempfile.mkstemp()
            fo = os.fdopen(fd, 'w')
            fo.write('[main]\ninstallroot=%s' % self.rootObj.makeChrootPath())
            fo.flush()
            fo.close()
            out_file = self.rootObj.resultdir + '/installed_pkgs'
            cmd = "/usr/bin/repoquery -c %s %s > %s" % (
                fn, repoquery_install_opts, out_file)
            mockbuild.util.do(cmd, shell=True, environ=self.rootObj.env)
            self.inst_done = True
            os.unlink(fn)
            self.rootObj.finish("Outputting list of installed packages")
Example #14
0
    def test_capture(self, captured):
        trace_decorator.traceLog()(exampleFunc)("aaa")
        callLineno = getLineno() - 1

        expectations = [
            (
                default_logger,
                logging.INFO,
                (filename, callLineno, "ENTER exampleFunc('aaa')"),
                {"exc_info": None, "args": [], "func": "test_capture"},
            ),
            (
                default_logger,
                logging.INFO,
                (filename, getLineno(exampleFunc), "LEAVE exampleFunc --> 42\n"),
                {"exc_info": None, "args": [], "func": "exampleFunc"},
            ),
        ]

        self.assertEqual(expectations, captured)
Example #15
0
class BindMountPoint(MountPoint):
    '''class for managing bind-mounts in the chroot'''
    decorate(traceLog())

    def __init__(self, srcpath, bindpath):
        MountPoint.__init__(self, mountsource=srcpath, mountpath=bindpath)
        self.srcpath = srcpath
        self.bindpath = bindpath
        self.mounted = self.ismounted()

    decorate(traceLog())

    def mount(self):
        if not self.mounted:
            cmd = ['/bin/mount', '-n', '--bind', self.srcpath, self.bindpath]
            try:
                mockbuild.util.do(cmd)
            except mockbuild.exception.Error, e:
                return False
        self.mounted = True
        return True
Example #16
0
class ChrootScan(object):
    """scan chroot for files of interest, copying to resultdir with relative paths"""
    decorate(traceLog())

    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.scan_opts = conf
        self.regexes = self.rootObj.pluginConf['chroot_scan_opts']['regexes']
        self.resultdir = os.path.join(rootObj.resultdir, "chroot_scan")
        rootObj.scanObj = self
        rootObj.addHook("postbuild", self._scanChroot)
        getLog().info("chroot_scan: initialized")

    decorate(traceLog())

    def _scanChroot(self):
        regexstr = "|".join(self.regexes)
        regex = re.compile(regexstr)
        chroot = self.rootObj.makeChrootPath()
        mockbuild.util.mkdirIfAbsent(self.resultdir)
        count = 0
        logger = getLog()
        logger.debug("chroot_scan: Starting scan of %s" % chroot)
        copied = []
        for root, dirs, files in os.walk(chroot):
            for f in files:
                m = regex.search(f)
                if m:
                    srcpath = os.path.join(root, f)
                    subprocess.call("cp --parents %s %s" %
                                    (srcpath, self.resultdir),
                                    shell=True)
                    count += 1
                    copied.append(srcpath)
        logger.debug("chroot_scan: finished with %d files found" % count)
        if count:
            logger.info("chroot_scan: %d files copied to %s" %
                        (count, self.resultdir))
            logger.info("%s" % "\n".join(copied))
Example #17
0
class YumCache(object):
    """caches root environment in a tarball"""
    decorate(traceLog())

    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.yum_cache_opts = conf
        self.yumSharedCachePath = self.yum_cache_opts[
            'dir'] % self.yum_cache_opts
        self.online = rootObj.online
        rootObj.yum_cacheObj = self
        rootObj.addHook("preyum", self._yumCachePreYumHook)
        rootObj.addHook("postyum", self._yumCachePostYumHook)
        rootObj.addHook("preinit", self._yumCachePreInitHook)
        rootObj.mounts.add(
            BindMountPoint(srcpath=self.yumSharedCachePath,
                           bindpath=rootObj.makeChrootPath('/var/cache/yum')))
        mockbuild.util.mkdirIfAbsent(self.yumSharedCachePath)
        self.yumCacheLock = open(
            os.path.join(self.yumSharedCachePath, "yumcache.lock"), "a+")

    # =============
    # 'Private' API
    # =============
    # lock the shared yum cache (when enabled) before any access
    # by yum, and prior to cleaning it. This prevents simultaneous access from
    # screwing things up. This can possibly happen, eg. when running multiple
    # mock instances with --uniqueext=
    decorate(traceLog())

    def _yumCachePreYumHook(self):
        try:
            fcntl.lockf(self.yumCacheLock.fileno(),
                        fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError, e:
            self.rootObj.start("Waiting for yumcache lock")
            fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_EX)
            self.rootObj.finish("Waiting for yumcache lock")
Example #18
0
class Mount(object):
    """mount dirs into chroot"""
    decorate(traceLog())
    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.opts = conf
        rootObj.mountObj = self
        rootObj.addHook("preinit", self._mountPreInitHook)
        rootObj.addHook("preshell", self._mountPreInitHook)
        rootObj.addHook("prechroot", self._mountPreInitHook)
        for device, dest_dir, vfstype, mount_opts in self.opts['dirs']:
            if vfstype:
                vfstype = "-t " + vfstype
            else:
                vfstype = ""
            rootObj.mounts.add(FileSystemMountPoint(rootObj.makeChrootPath(dest_dir),
                                                    filetype=vfstype,
                                                    device=device,
                                                    options=mount_opts))
    decorate(traceLog())
    def _mountPreInitHook(self):
        for device, dest_dir, vfstype, mount_opts in self.opts['dirs']:
            mockbuild.util.mkdirIfAbsent(self.rootObj.makeChrootPath(dest_dir))
Example #19
0
class BindMount(object):
    """bind mount dirs from host into chroot"""
    decorate(traceLog())

    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.bind_opts = conf
        rootObj.bindMountObj = self
        rootObj.addHook("preinit", self._bindMountPreInitHook)
        rootObj.addHook("preshell", self._bindMountPreInitHook)
        rootObj.addHook("prechroot", self._bindMountPreInitHook)
        for srcdir, destdir in self.bind_opts['dirs']:
            rootObj.mounts.add(
                BindMountPoint(srcpath=srcdir,
                               bindpath=rootObj.makeChrootPath(destdir)))

    decorate(traceLog())

    def _bindMountPreInitHook(self):
        create_dirs = self.rootObj.pluginConf['bind_mount_opts']['create_dirs']
        for srcdir, destdir in self.bind_opts['dirs']:
            if create_dirs: mockbuild.util.mkdirIfAbsent(srcdir)
            mockbuild.util.mkdirIfAbsent(self.rootObj.makeChrootPath(destdir))
Example #20
0
class FileSystemMountPoint(MountPoint):
    '''class for managing filesystem mounts in the chroot'''
    decorate(traceLog())

    def __init__(self, path, filetype=None, device=None, options=None):
        if not path:
            raise RuntimeError, "no path specified for mountpoint"
        if not filetype:
            raise RuntimeError, "no filetype specified for mountpoint"
        if filetype == 'pts' or filetype == 'proc' or filetype == 'sys':
            device = filetype
        if not device:
            raise RuntimeError, "no device file specified for mountpoint"

        MountPoint.__init__(self, mountsource=device, mountpath=path)
        self.device = device
        self.path = path
        self.filetype = filetype
        self.options = options
        self.mounted = self.ismounted()

    decorate(traceLog())

    def mount(self):
        if self.mounted:
            return

        cmd = ['/bin/mount', '-n', '-t', self.filetype]
        if self.options:
            cmd += ['-o', self.options]
        cmd += [self.device, self.path]
        try:
            mockbuild.util.do(cmd)
        except mockbuild.exception.Error, e:
            return False
        self.mounted = True
        return True
Example #21
0
class Mounts(object):
    '''class to manage all mountpoints'''
    decorate(traceLog())

    def __init__(self, rootObj):
        self.rootObj = rootObj
        self.mounts = [
            FileSystemMountPoint(filetype='proc',
                                 device='mock_chroot_proc',
                                 path=rootObj.makeChrootPath('/proc')),
            FileSystemMountPoint(filetype='sysfs',
                                 device='mock_chroot_sys',
                                 path=rootObj.makeChrootPath('/sys')),
            FileSystemMountPoint(filetype='tmpfs',
                                 device='mock_chroot_shmfs',
                                 path=rootObj.makeChrootPath('/dev/shm')),
        ]
        opts = 'gid=%d,mode=0620,ptmxmode=0666' % grp.getgrnam('tty').gr_gid
        if mockbuild.util.cmpKernelVer(os.uname()[2], '2.6.29') >= 0:
            opts += ',newinstance'
        self.mounts.append(
            FileSystemMountPoint(filetype='devpts',
                                 device='mock_chroot_devpts',
                                 path=rootObj.makeChrootPath('/dev/pts'),
                                 options=opts))

    decorate(traceLog())

    def add(self, mount):
        self.mounts.append(mount)

    decorate(traceLog())

    def mountall(self):
        for m in self.mounts:
            m.mount()

    decorate(traceLog())

    def umountall(self, force=False, nowarn=False):
        for m in reversed(self.mounts):
            m.umount()

    decorate(traceLog())

    def get_mounted(self):
        return [m.mountpath for m in self.mounts if m.ismounted()]

    decorate(traceLog())

    def get_mountpoints(self):
        return [m.mountpath for m in self.mounts]
class O0g3(object):
    """Source mount dirs from host into chroot"""

    decorate(traceLog())

    def __init__(self, root, opts):
        self.root = root
        self.opts = opts
        self.O0g3s = {
            "gcc": "/usr/share/mock-O0g3-plugin/gcc-O0g3",
            "cc": "/usr/share/mock-O0g3-plugin/cc-O0g3",
            "g++": "/usr/share/mock-O0g3-plugin/g++-O0g3",
            "c++": "/usr/share/mock-O0g3-plugin/c++-O0g3",
            "strip": "/usr/share/mock-O0g3-plugin/strip-O0g3",
        }
        self.suffix = "O0g3"

        # See http://www.redhat.com/archives/rpm-list/2003-February/msg00174.html
        root.yumInstall("redhat-rpm-config")

        root.addHook("prebuild", self.prebuild)
        root.addHook("postbuild", self.postbuild)

    decorate(traceLog())

    def prebuild(self):
        self.modifySpec()
        for k in self.O0g3s:
            self.replace(k)

    decorate(traceLog())

    def postbuild(self):
        for k in self.O0g3s:
            self.revert(k)

    def modifySpec(self):
        getLog().info("Modify the spec file")
        root = self.root
        specs = glob.glob(root.makeChrootPath(root.builddir, "SPECS",
                                              "*.spec"))
        spec = specs[0]
        chrootspec = spec.replace(root.makeChrootPath(),
                                  '')  # get rid of rootdir prefix
        root.doChroot(
            [
                "sed", "-i", "-e",
                's/^Release: .*/\\0.%s/' %
                (self.suffix), "-e", "1i %define debug_package %{nil}", "-e",
                "1i %define debug_packages %{nil}", "-e",
                "1i %define __strip :", chrootspec
            ],
            shell=False,
            logger=root.build_log,
            timeout=0,
            uid=root.chrootuid,
            gid=root.chrootgid,
        )

    def makeOriginalPath(self, cmd):
        return self.root.makeChrootPath("/usr/bin" + "/" + cmd)

    def makeBackupPath(self, cmd):
        return self.root.makeChrootPath("/usr/bin" + "/" + "_" + cmd)

    def replace(self, cmd):
        getLog().info("Replace " + cmd)
        root = self.root
        original = self.makeOriginalPath(cmd)
        backup = self.makeBackupPath(cmd)
        f = open(original, mode='r')
        l = f.readline()
        f.close()
        if l != "#!/bin/bash":
            try:
                root.uidManager.becomeUser(0, 0)
                getLog().info("mv " + original + " " + backup)
                mockbuild.util.do(["/bin/mv", original, backup], shell=False)
                getLog().info("cp " + self.O0g3s[cmd] + " " + original)
                mockbuild.util.do(["/bin/cp", self.O0g3s[cmd], original],
                                  shell=False)
            finally:
                root.uidManager.restorePrivs()

    def revert(self, cmd):
        getLog().info("Revert " + cmd)
        root = self.root
        original = self.makeOriginalPath(cmd)
        backup = self.makeBackupPath(cmd)
        if os.path.exists(backup):
            try:
                root.uidManager.becomeUser(0, 0)
                getLog().info("mv " + backup + " " + original)
                mockbuild.util.do(["/bin/mv", backup, original], shell=False)
            finally:
                root.uidManager.restorePrivs()
Example #23
0
class Root(object):
    """controls setup of chroot environment"""
    decorate(traceLog())

    def __init__(self, config, uidManager):
        self._state = []
        self.uidManager = uidManager
        self._hooks = {}
        self.chrootWasCached = False
        self.chrootWasCleaned = False
        self.preExistingDeps = []
        self.logging_initialized = False
        self.buildrootLock = None
        self.version = config['version']

        self.sharedRootName = config['root']
        if config.has_key('unique-ext'):
            config['root'] = "%s-%s" % (config['root'], config['unique-ext'])

        self.basedir = os.path.join(config['basedir'], config['root'])
        self.rpmbuild_arch = config['rpmbuild_arch']
        self._rootdir = os.path.join(self.basedir, 'root')
        self.homedir = config['chroothome']
        self.builddir = os.path.join(self.homedir, 'build')

        # Environment
        self.env = config['environment']

        # proxy settings
        for proto in ('http', 'https', 'ftp', 'no'):
            key = '%s_proxy' % proto
            value = config.get(key)
            if value:
                os.environ[key] = value
                self.env[key] = value

        # result dir
        self.resultdir = config['resultdir'] % config

        self.root_log = getLog("mockbuild")
        self.build_log = getLog("mockbuild.Root.build")
        self._state_log = getLog("mockbuild.Root.state")

        # config options
        self.configs = config['config_paths']
        self.config_name = config['chroot_name']
        self.chrootuid = config['chrootuid']
        self.chrootuser = '******'
        self.chrootgid = config['chrootgid']
        self.chrootgroup = 'mockbuild'
        self.yum_conf_content = config['yum.conf']
        self.yum_priorities_conf_content = config['priorities.conf']
        self.yum_rhnplugin_conf_content = config['rhnplugin.conf']
        self.use_host_resolv = config['use_host_resolv']
        self.chroot_file_contents = config['files']
        self.chroot_setup_cmd = config['chroot_setup_cmd']
        if isinstance(self.chroot_setup_cmd, basestring):
            # accept strings in addition to other sequence types
            self.chroot_setup_cmd = self.chroot_setup_cmd.split()
        self.yum_path = '/usr/bin/yum'
        self.yum_builddep_path = '/usr/bin/yum-builddep'
        self.yum_builddep_opts = config['yum_builddep_opts']
        self.macros = config['macros']
        self.more_buildreqs = config['more_buildreqs']
        self.cache_topdir = config['cache_topdir']
        self.cachedir = os.path.join(self.cache_topdir, self.sharedRootName)
        self.useradd = config['useradd']
        self.online = config['online']
        self.internal_dev_setup = config['internal_dev_setup']

        self.plugins = config['plugins']
        self.pluginConf = config['plugin_conf']
        self.pluginDir = config['plugin_dir']
        for key in self.pluginConf.keys():
            if not key.endswith('_opts'): continue
            self.pluginConf[key]['basedir'] = self.basedir
            self.pluginConf[key]['cache_topdir'] = self.cache_topdir
            self.pluginConf[key]['cachedir'] = self.cachedir
            self.pluginConf[key]['root'] = self.sharedRootName

        # mount/umount
        self.mounts = mockbuild.mounts.Mounts(self)

        self.build_log_fmt_str = config['build_log_fmt_str']
        self.root_log_fmt_str = config['root_log_fmt_str']
        self._state_log_fmt_str = config['state_log_fmt_str']

        self.start("init plugins")
        self._initPlugins()
        self.finish("init plugins")

        # do we allow interactive root shells?
        self.no_root_shells = config['no_root_shells']

        # default to not doing selinux things
        self.selinux = False

        # if the selinux plugin is disabled and we have SELinux enabled
        # on the host, we need to do SELinux things, so set the selinux
        # state variable to true
        if self.pluginConf[
                'selinux_enable'] == False and mockbuild.util.selinuxEnabled():
            self.selinux = True

    # =============
    #  'Public' API
    # =============
    decorate(traceLog())

    def addHook(self, stage, function):
        hooks = self._hooks.get(stage, [])
        if function not in hooks:
            hooks.append(function)
            self._hooks[stage] = hooks

    decorate(traceLog())

    def state(self):
        if not len(self._state):
            raise mockbuild.exception.StateError, "state called on empty state stack"
        return self._state[-1]

    def start(self, state):
        if state == None:
            raise mockbuild.exception.StateError, "start called with None State"
        self._state.append(state)
        self._state_log.info("Start: %s" % state)

    def finish(self, state):
        if len(self._state) == 0:
            raise mockbuild.exception.StateError, "finish called on empty state list"
        current = self._state.pop()
        if state != current:
            raise mockbuild.exception.StateError, "state finish mismatch: current: %s, state: %s" % (
                current, state)
        self._state_log.info("Finish: %s" % state)

    def alldone(self):
        if len(self._state) != 0:
            raise mockbuild.exception.StateError, "alldone called with pending states: %s" % ",".join(
                self._state)

    decorate(traceLog())

    def clean(self):
        """clean out chroot with extreme prejudice :)"""
        from signal import SIGKILL
        self.tryLockBuildRoot()
        self.start("clean chroot")
        self._callHooks('clean')
        mockbuild.util.orphansKill(self.makeChrootPath())
        self._umountall(nowarn=True)
        self._unlock_and_rm_chroot()
        self.chrootWasCleaned = True
        self.finish("clean chroot")
        self.unlockBuildRoot()

    decorate(traceLog())

    def _unlock_and_rm_chroot(self):
        if not os.path.exists(self.basedir):
            return
        t = self.basedir + ".tmp"
        if os.path.exists(t):
            mockbuild.util.rmtree(t, selinux=self.selinux)
        os.rename(self.basedir, t)
        self.buildrootLock.close()
        try:
            mockbuild.util.rmtree(t, selinux=self.selinux)
        except OSError, e:
            self.root_log.error(e)
            self.root_log.error("contents of /proc/mounts:\n%s" %
                                open('/proc/mounts').read())
            self.root_log.error("looking for users of %s" % t)
            self._show_path_user(t)
            raise
        self.root_log.info("chroot (%s) unlocked and deleted" % self.basedir)
Example #24
0
    def test_default_logger(self, captured):
        trace_decorator.traceLog()(exampleFunc)('aaa')

        loggers = [call[0] for call in captured]
        self.assertEqual([default_logger] * 2, loggers)
Example #25
0
def exampleNested(**kwargs):
    return trace_decorator.traceLog()(exampleFunc)('bbb', **kwargs)
Example #26
0
    def test_custom_logger(self, captured):
        logger = type('custom_logger', (), {})
        trace_decorator.traceLog(logger)(exampleFunc)('aaa')

        loggers = [call[0] for call in captured]
        self.assertEqual([logger] * 2, loggers)
Example #27
0
class scmWorker(object):
    """Build RPMs from SCM"""
    decorate(traceLog())

    def __init__(self, log, opts):
        self.log = log
        self.log.debug("Initializing SCM integration...")

        self.method = opts['method']
        if self.method == "cvs":
            self.get = opts['cvs_get']
        elif self.method == "svn":
            self.get = opts['svn_get']
        elif self.method == "git":
            self.get = opts['git_get']
        else:
            self.log.error("Unsupported SCM method: " + self.method)
            sys.exit(5)

        self.branch = None
        self.postget = None
        if 'branch' in opts:
            self.branch = opts['branch']
        if self.branch:
            if self.method == "cvs":
                self.get = self.get.replace("SCM_BRN", "-r " + self.branch)
            elif self.method == "git":
                self.postget = "git checkout " + self.branch
            elif self.method == "svn":
                self.get = self.get.replace("SCM_BRN", self.branch)
            else:
                self.log.error("Unsupported SCM method: " + self.method)
                sys.exit(5)
        elif self.method == "svn":
            self.get = self.get.replace("SCM_BRN", "trunk")
        self.get = self.get.replace("SCM_BRN", "")

        if 'package' in opts:
            self.pkg = opts['package']
        else:
            self.log.error("Trying to use SCM, package not defined")
            sys.exit(5)
        self.get = self.get.replace("SCM_PKG", self.pkg)

        self.spec = opts['spec']
        self.spec = self.spec.replace("SCM_PKG", self.pkg)

        self.ext_src_dir = opts['ext_src_dir']
        self.write_tar = opts['write_tar']

        self.git_timestamps = opts['git_timestamps']

        self.log.debug("SCM checkout command: " + self.get)
        self.log.debug("SCM checkout post command: " + str(self.postget))
        self.environ = os.environ.copy()
        # Set HOME properly while checking out from SCM since tools like
        # Subversion might have there settings needed to carry out checkout
        # non-interactively
        self.environ['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
        self.environ['CVS_RSH'] = "ssh"
        if not self.environ.has_key('SSH_AUTH_SOCK'):
            self.environ['SSH_AUTH_SOCK'] = pwd.getpwuid(
                os.getuid()).pw_dir + "/.ssh/auth_sock"

    decorate(traceLog())

    def get_sources(self):
        self.wrk_dir = tempfile.mkdtemp(".mock-scm." + self.pkg)
        self.src_dir = self.wrk_dir + "/" + self.pkg
        self.log.debug("SCM checkout directory: " + self.wrk_dir)
        mockbuild.util.do(shlex.split(self.get),
                          shell=False,
                          cwd=self.wrk_dir,
                          env=self.environ)
        if self.postget:
            mockbuild.util.do(shlex.split(self.postget),
                              shell=False,
                              cwd=self.src_dir,
                              env=self.environ)
        self.log.debug("Fetched sources from SCM")

    decorate(traceLog())

    def adjust_git_timestamps(self):
        dir = os.getcwd()
        self.log.debug("Adjusting timestamps in " + self.src_dir)
        os.chdir(self.src_dir)
        proc = subprocess.Popen(['git', 'ls-files', '-z'],
                                shell=False,
                                stdout=subprocess.PIPE)
        for f in proc.communicate()[0].split('\0')[:-1]:
            rev = subprocess.Popen(
                ['git', 'rev-list', 'HEAD', f],
                shell=False,
                stdout=subprocess.PIPE).stdout.readlines()[0].rstrip('\n')
            ts = subprocess.Popen(
                [
                    'git', 'show', '--pretty=format:%ai', '--abbrev-commit',
                    rev, f
                ],
                shell=False,
                stdout=subprocess.PIPE).stdout.readlines()[0].rstrip('\n')
            subprocess.Popen(['touch', '-d', ts, f], shell=False)
        os.chdir(dir)

    decorate(traceLog())

    def prepare_sources(self):
        # import rpm after setarch
        import rpm
        self.log.debug("Preparing SCM sources")

        # Check some helper files
        if os.path.exists(self.src_dir + "/.write_tar"):
            self.log.debug(
                ".write_tar detected, will write tarball on the fly")
            self.write_tar = True

        # Figure out the spec file
        sf = self.src_dir + "/" + self.spec
        if not os.path.exists(sf):
            sf = self.src_dir + "/" + self.spec.lower()
        if not os.path.exists(sf):
            self.log.error("Can't find spec file %s" % self.src_dir + "/" +
                           self.spec)
            self.clean()
            sys.exit(5)
        self.spec = sf

        # Dig out some basic information from the spec file
        self.sources = []
        self.name = self.version = None
        ts = rpm.ts()
        rpm_spec = ts.parseSpec(self.spec)
        self.name = rpm.expandMacro("%{name}")
        self.version = rpm.expandMacro("%{version}")
        try:
            sources_list = rpm_spec.sources()
        except:
            sources_list = rpm_spec.sources
        for (filename, num, flags) in sources_list:
            self.sources.append(filename.split("/")[-1])
        self.log.debug("Sources: %s" % self.sources)

        # Adjust timestamps for Git checkouts
        if self.method == "git" and self.git_timestamps:
            self.adjust_git_timestamps()

        # Generate a tarball from the checked out sources if needed
        if str(self.write_tar).lower() == "true":
            tardir = self.name + "-" + self.version
            tarball = tardir + ".tar.gz"
            taropts = ""

            proc = subprocess.Popen(['tar', '--help'],
                                    shell=False,
                                    stdout=subprocess.PIPE)
            if "--exclude-vcs" in proc.communicate()[0]:
                taropts = "--exclude-vcs"

            self.log.debug("Writing " + self.src_dir + "/" + tarball + "...")
            dir = os.getcwd()
            os.chdir(self.wrk_dir)
            os.rename(self.name, tardir)
            cmd = "tar czf " + tarball + " " + taropts + " " + tardir
            mockbuild.util.do(shlex.split(cmd),
                              shell=False,
                              cwd=self.wrk_dir,
                              env=self.environ)
            os.rename(tarball, tardir + "/" + tarball)
            os.rename(tardir, self.name)
            os.chdir(dir)

        # Get possible external sources from an external sources directory
        for f in self.sources:
            if not os.path.exists(self.src_dir + "/" + f) and \
                   os.path.exists(self.ext_src_dir + "/" + f):
                self.log.debug("Copying " + self.ext_src_dir + "/" + f +
                               " to " + self.src_dir + "/" + f)
                shutil.copy2(self.ext_src_dir + "/" + f,
                             self.src_dir + "/" + f)

        self.log.debug("Prepared sources for building src.rpm")

        return (self.src_dir, self.spec)

    decorate(traceLog())

    def clean(self):
        self.log.debug("Clean SCM checkout directory")
        mockbuild.util.rmtree(self.wrk_dir)
Example #28
0
    def test_custom_logger_fn(self, captured):
        logger = type("custom_logger", (), {})
        trace_decorator.traceLog()(exampleFunc)("aaa", logger=logger)

        loggers = [call[0] for call in captured]
        self.assertEqual([logger] * 2, loggers)
Example #29
0
def exampleNested(**kwargs):
    return trace_decorator.traceLog()(exampleFunc)("bbb", **kwargs)
Example #30
0
    def test_string_logger(self, captured):
        trace_decorator.traceLog('fake_logger')(exampleFunc)('aaa')

        loggers = [call[0] for call in captured]
        self.assertEqual(['fake_logger'] * 2, loggers)
class SourceRescue(object):
    """Rescuing rpmbuild -bp result"""
    decorate(traceLog())

    def __init__(self, root, opts):
        self.result = -2
        self.root = root
        self.opts = opts
        self.shelterdir = opts.get("shelterdir",
                                   False) or (root.resultdir + "/" + "srpmix")
        self.dont_make_patch_backup = opts.get("dont_make_patch_backup", True)
        self.salt = '.' + 'df6056a7-d1fc-4cc3-b831-6aac00e7f73a'
        if not self.shelterdir:
            raise RuntimeError, "Neither \"shelterdir\" config parameter nor \"resultdir\" config parameter given"
        if os.path.exists(self.shelterdir):
            raise RuntimeError, "%s already exists" % self.shelterdir

        root.addHook("prebuild", self.prebuild)
        root.addHook("postbuild", self.postbuild)

    decorate(traceLog())

    def prebuild(self):
        root = self.root

        specs = glob.glob(root.makeChrootPath(root.builddir, "SPECS",
                                              "*.spec"))
        spec = specs[0]
        self.wash_spec(spec)

        getLog().info("Synthesizing source code")
        chrootspec = spec.replace(root.makeChrootPath(),
                                  '')  # get rid of rootdir prefix
        try:
            root.doChroot([
                "bash", "--login", "-c",
                'rpmbuild -bp --target %s --nodeps %s' %
                (root.rpmbuild_arch, chrootspec)
            ],
                          shell=False,
                          logger=root.build_log,
                          timeout=0,
                          uid=root.chrootuid,
                          gid=root.chrootgid,
                          raiseExc=True)
        except:
            getLog().info("Failed in synthesizing")
            self.result = -1
            raise SourceSOS

        getLog().info("Rescuing source code to %s" % self.shelterdir)
        bd_out = root.makeChrootPath(root.builddir)
        os.system("chmod -R a+r %s" % bd_out)
        os.system("find %s -type d -print0 | xargs -0 chmod a+x" % bd_out)
        shutil.copytree(bd_out, self.shelterdir, symlinks=True)
        os.system("find %s -name '*%s' -print0 | xargs -0 rm -f" %
                  (self.shelterdir, self.salt))
        os.system("mv %sb %s" % (spec, spec))
        self.result = 0
        raise SourceSOS

    decorate(traceLog())

    def wash_spec(self, spec):
        if self.dont_make_patch_backup:
            self.wash__dont_make_patch_backup(spec)

    decorate(traceLog())

    def wash__dont_make_patch_backup(self, spec):
        os.system("cp %s %sb" % (spec, spec))
        sed = "sed -i -e 's/\\(^%%patch[0-9]\\+.*\\)[ \\t]-b[ \\t]\+[^ \\t]\+\\(.*\\)/\\1 -b %s \\2/' %s"
        os.system(sed % (self.salt, spec))

    decorate(traceLog())

    def postbuild(self):
        self.root.clean()
        sys.exit(self.result)
Example #32
0
    def test_default_logger(self, captured):
        trace_decorator.traceLog()(exampleFunc)("aaa")

        loggers = [call[0] for call in captured]
        self.assertEqual([default_logger] * 2, loggers)
Example #33
0
config_opts['plugin_conf']['mount_opts']['dirs'].append(("/dev/device", "/mount/path/in/chroot/", "vfstype", "mount_options"))

# A real life example:
config_opts['plugin_conf']['mount_opts']['dirs'].append(("server.example.com:/exports/data", "/mnt/data", "nfs", "rw,hard,intr,nosuid,nodev,noatime,tcp"))
"""


import mockbuild.util
from mockbuild.trace_decorator import decorate, traceLog
from mockbuild.mounts import FileSystemMountPoint

requires_api_version = "1.0"


# plugin entry point
decorate(traceLog())
def init(rootObj, conf):
    Mount(rootObj, conf)


# classes
class Mount(object):
    """mount dirs into chroot"""
    decorate(traceLog())
    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.opts = conf
        rootObj.mountObj = self
        rootObj.addHook("preinit", self._mountPreInitHook)
        rootObj.addHook("preshell", self._mountPreInitHook)
        rootObj.addHook("prechroot", self._mountPreInitHook)
Example #34
0
    def test_string_logger(self, captured):
        trace_decorator.traceLog("fake_logger")(exampleFunc)("aaa")

        loggers = [call[0] for call in captured]
        self.assertEqual(["fake_logger"] * 2, loggers)
Example #35
0
# vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0:
# License: GPL2 or later see COPYING
# Written by Michael Brown
# Copyright (C) 2007 Michael E Brown <*****@*****.**>

# python library imports
import os

# our imports
from mockbuild.trace_decorator import decorate, traceLog, getLog
import mockbuild.util

requires_api_version = "1.0"

# plugin entry point
decorate(traceLog())
def init(rootObj, conf):
    system_ram_bytes = os.sysconf(os.sysconf_names['SC_PAGE_SIZE']) * os.sysconf(os.sysconf_names['SC_PHYS_PAGES'])
    system_ram_mb = system_ram_bytes / (1024 * 1024)
    if system_ram_mb > conf['required_ram_mb']:
        Tmpfs(rootObj, conf)
    else:
        getLog().warning("Tmpfs plugin disabled. "
            "System does not have the required amount of RAM to enable the tmpfs plugin. "
            "System has %sMB RAM, but the config specifies the minimum required is %sMB RAM. "
            %
            (system_ram_mb, conf['required_ram_mb']))

# classes
class Tmpfs(object):
    """Mounts a tmpfs on the chroot dir"""
Example #36
0
class uidManager(object):
    decorate(traceLog())
    def __init__(self, unprivUid=-1, unprivGid=-1):
        self.privStack = []
        self.unprivUid = unprivUid
        self.unprivGid = unprivGid

    decorate(traceLog())
    def becomeUser(self, uid, gid=-1):
        # save current ruid, euid, rgid, egid
        self._push()
        self._becomeUser(uid, gid)

    decorate(traceLog())
    def dropPrivsTemp(self):
        # save current ruid, euid, rgid, egid
        self._push()
        self._becomeUser(self.unprivUid, self.unprivGid)

    decorate(traceLog())
    def restorePrivs(self):
        # back to root first
        self._elevatePrivs()

        # then set saved
        privs = self.privStack.pop()
        os.setregid(privs['rgid'], privs['egid'])
        setresuid(privs['ruid'], privs['euid'])

    decorate(traceLog())
    def dropPrivsForever(self):
        self._elevatePrivs()
        os.setregid(self.unprivGid, self.unprivGid)
        os.setreuid(self.unprivUid, self.unprivUid)

    decorate(traceLog())
    def _push(self):
         # save current ruid, euid, rgid, egid
        self.privStack.append({
            "ruid": os.getuid(),
            "euid": os.geteuid(),
            "rgid": os.getgid(),
            "egid": os.getegid(),
            })

    decorate(traceLog())
    def _elevatePrivs(self):
        setresuid(0, 0, 0)
        os.setregid(0, 0)

    decorate(traceLog())
    def _becomeUser(self, uid, gid=None):
        self._elevatePrivs()
        if gid is not None:
            os.setregid(gid, gid)
        setresuid(uid, uid, 0)

    decorate(traceLog())
    def changeOwner(self, path, uid=None, gid=None):
        self._elevatePrivs()
        if uid is None:
            uid = self.unprivUid
        if gid is None:
            gid = self.unprivGid
        os.chown(path, uid, gid)