Пример #1
0
 def do_mounts(self, rootdir, mounts):
     if not mounts:
         return
     self.logger.info('New runroot')
     self.logger.info("Runroot mounts: %s" % mounts)
     fn = '%s/tmp/runroot_mounts' % rootdir
     fslog = open(fn, 'a')
     logfile = "%s/do_mounts.log" % self.workdir
     uploadpath = self.getUploadDir()
     error = None
     for dev, path, type, opts in mounts:
         if not path.startswith('/'):
             raise koji.GenericError("invalid mount point: %s" % path)
         mpoint = "%s%s" % (rootdir, path)
         if opts is None:
             opts = []
         else:
             opts = opts.split(',')
         if 'bind' in opts:
             #make sure dir exists
             if not os.path.isdir(dev):
                 error = koji.GenericError(
                     "No such directory or mount: %s" % dev)
                 break
             type = 'none'
         if 'bg' in opts:
             error = koji.GenericError(
                 "bad config: background mount not allowed")
             break
         opts = ','.join(opts)
         cmd = ['mount', '-t', type, '-o', opts, dev, mpoint]
         self.logger.info("Mount command: %r" % cmd)
         koji.ensuredir(mpoint)
         if compat_mode:
             status = log_output(cmd[0],
                                 cmd,
                                 logfile,
                                 uploadpath,
                                 logerror=True,
                                 append=True)
         else:
             status = log_output(self.session,
                                 cmd[0],
                                 cmd,
                                 logfile,
                                 uploadpath,
                                 logerror=True,
                                 append=True)
         if not _isSuccess(status):
             error = koji.GenericError("Unable to mount %s: %s" \
                     % (mpoint, _parseStatus(status, cmd)))
             break
         fslog.write("%s\n" % mpoint)
         fslog.flush()
     fslog.close()
     if error is not None:
         self.undo_mounts(rootdir, fatal=False)
         raise error
Пример #2
0
 def do_mounts(self, rootdir, mounts):
     if not mounts:
         return
     self.logger.info('New runroot')
     self.logger.info("Runroot mounts: %s" % mounts)
     fn = '%s/tmp/runroot_mounts' % rootdir
     fslog = file(fn, 'a')
     logfile = "%s/do_mounts.log" % self.workdir
     uploadpath = self.getUploadDir()
     error = None
     for dev,path,type,opts in mounts:
         if not path.startswith('/'):
             raise koji.GenericError("invalid mount point: %s" % path)
         mpoint = "%s%s" % (rootdir,path)
         if opts is None:
             opts = []
         else:
             opts = opts.split(',')
         if 'bind' in opts:
             #make sure dir exists
             if not os.path.isdir(dev):
                 error = koji.GenericError("No such directory or mount: %s" % dev)
                 break
             type = 'none'
             if path is None:
                 #shorthand for "same path"
                 path = dev
         if 'bg' in opts:
             error = koji.GenericError("bad config: background mount not allowed")
             break
         opts = ','.join(opts)
         cmd = ['mount', '-t', type, '-o', opts, dev, mpoint]
         self.logger.info("Mount command: %r" % cmd)
         koji.ensuredir(mpoint)
         if compat_mode:
             status = log_output(cmd[0], cmd, logfile, uploadpath, logerror=True, append=True)
         else:
             status = log_output(self.session, cmd[0], cmd, logfile, uploadpath, logerror=True, append=True)
         if not _isSuccess(status):
             error = koji.GenericError("Unable to mount %s: %s" \
                     % (mpoint, _parseStatus(status, cmd)))
             break
         fslog.write("%s\n" % mpoint)
         fslog.flush()
     fslog.close()
     if error is not None:
         self.undo_mounts(rootdir, fatal=False)
         raise error
Пример #3
0
    def handler(
        self,
        root,
        arch,
        command,
        keep=False,
        packages=[],
        mounts=[],
        repo_id=None,
        skip_setarch=False,
        weight=None,
        upload_logs=None,
    ):
        """Create a buildroot and run a command (as root) inside of it

        Command may be a string or a list.

        Returns a message indicating success if the command was successful, and
        raises an error otherwise.  Command output will be available in
        runroot.log in the task output directory on the hub.

        skip_setarch is a rough approximation of an old hack

        the keep option is not used. keeping for compatibility for now...

        upload_logs is list of absolute paths which will be uploaded for
        archiving on hub. It always consists of /tmp/runroot.log, but can be
        used for additional logs (pungi.log, etc.)
        """
        if weight is not None:
            weight = max(weight, 0.5)
            self.session.host.setTaskWeight(self.id, weight)
        # noarch is funny
        if arch == "noarch":
            # we need a buildroot arch. Pick one that:
            #  a) this host can handle
            #  b) the build tag can support
            #  c) is canonical
            host_arches = self.session.host.getHost()["arches"]
            if not host_arches:
                raise koji.BuildError, "No arch list for this host"
            tag_arches = self.session.getBuildConfig(root)["arches"]
            if not tag_arches:
                raise koji.BuildError, "No arch list for tag: %s" % root
            # index canonical host arches
            host_arches = dict([(koji.canonArch(a), 1) for a in host_arches.split()])
            # pick the first suitable match from tag's archlist
            for br_arch in tag_arches.split():
                br_arch = koji.canonArch(br_arch)
                if host_arches.has_key(br_arch):
                    # we're done
                    break
            else:
                # no overlap
                raise koji.BuildError, "host does not match tag arches: %s (%s)" % (root, tag_arches)
        else:
            br_arch = arch
        if repo_id:
            repo_info = self.session.repoInfo(repo_id, strict=True)
            if repo_info["tag_name"] != root:
                raise koji.BuildError, "build tag (%s) does not match repo tag (%s)" % (root, repo_info["tag_name"])
            if repo_info["state"] not in (koji.REPO_STATES["READY"], koji.REPO_STATES["EXPIRED"]):
                raise koji.BuildError, "repos in the %s state may not be used by runroot" % koji.REPO_STATES[
                    repo_info["state"]
                ]
        else:
            repo_info = self.session.getRepo(root)
        if not repo_info:
            # wait for it
            task_id = self.session.host.subtask(method="waitrepo", arglist=[root, None, None], parent=self.id)
            repo_info = self.wait(task_id)[task_id]
        if compat_mode:
            broot = BuildRoot(root, br_arch, self.id, repo_id=repo_info["id"])
        else:
            broot = BuildRoot(self.session, self.options, root, br_arch, self.id, repo_id=repo_info["id"])
            broot.workdir = self.workdir
        broot.init()
        rootdir = broot.rootdir()
        # workaround for rpm oddness
        os.system('rm -f "%s"/var/lib/rpm/__db.*' % rootdir)
        # update buildroot state (so that updateBuildRootList() will work)
        self.session.host.setBuildRootState(broot.id, "BUILDING")
        try:
            if packages:
                # pkglog = '%s/%s' % (broot.resultdir(), 'packages.log')
                pkgcmd = ["--install"] + packages
                status = broot.mock(pkgcmd)
                self.session.host.updateBuildRootList(broot.id, broot.getPackageList())
                if not _isSuccess(status):
                    raise koji.BuildrootError, _parseStatus(status, pkgcmd)

            if isinstance(command, str):
                cmdstr = command
            else:
                # we were passed an arglist
                # we still have to run this through the shell (for redirection)
                # but we can preserve the list structure precisely with careful escaping
                cmdstr = " ".join(["'%s'" % arg.replace("'", r"'\''") for arg in command])
            # A nasty hack to put command output into its own file until mock can be
            # patched to do something more reasonable than stuff everything into build.log
            cmdargs = [
                "/bin/sh",
                "-c",
                "{ %s; } < /dev/null 2>&1 | /usr/bin/tee /tmp/runroot.log; exit ${PIPESTATUS[0]}" % cmdstr,
            ]

            # always mount /mnt/redhat (read-only)
            # always mount /mnt/iso (read-only)
            # also need /dev bind mount
            self.do_mounts(rootdir, [self._get_path_params(x) for x in self.config["default_mounts"]])
            self.do_extra_mounts(rootdir, mounts)
            mock_cmd = ["chroot"]
            if skip_setarch:
                # we can't really skip it, but we can set it to the current one instead of of the chroot one
                myarch = platform.uname()[5]
                mock_cmd.extend(["--arch", myarch])
            mock_cmd.append("--")
            mock_cmd.extend(cmdargs)
            rv = broot.mock(mock_cmd)
            log_paths = ["/tmp/runroot.log"]
            if upload_logs is not None:
                log_paths += upload_logs
            for log_path in log_paths:
                self.uploadFile(rootdir + log_path)
        finally:
            # mock should umount its mounts, but it will not handle ours
            self.undo_mounts(rootdir, fatal=False)
            broot.expire()
        if isinstance(command, str):
            cmdlist = command.split()
        else:
            cmdlist = command
        cmdlist = [param for param in cmdlist if "=" not in param]
        if cmdlist:
            cmd = os.path.basename(cmdlist[0])
        else:
            cmd = "(none)"
        if _isSuccess(rv):
            return "%s completed successfully" % cmd
        else:
            raise koji.BuildrootError, _parseStatus(rv, cmd)
Пример #4
0
    def handler(self,
                root,
                arch,
                command,
                keep=False,
                packages=[],
                mounts=[],
                repo_id=None,
                skip_setarch=False,
                weight=None,
                upload_logs=None):
        """Create a buildroot and run a command (as root) inside of it

        Command may be a string or a list.

        Returns a message indicating success if the command was successful, and
        raises an error otherwise.  Command output will be available in
        runroot.log in the task output directory on the hub.

        skip_setarch is a rough approximation of an old hack

        the keep option is not used. keeping for compatibility for now...

        upload_logs is list of absolute paths which will be uploaded for
        archiving on hub. It always consists of /tmp/runroot.log, but can be
        used for additional logs (pungi.log, etc.)
        """
        if weight is not None:
            weight = max(weight, 0.5)
            self.session.host.setTaskWeight(self.id, weight)
        #noarch is funny
        if arch == "noarch":
            #we need a buildroot arch. Pick one that:
            #  a) this host can handle
            #  b) the build tag can support
            #  c) is canonical
            host_arches = self.session.host.getHost()['arches']
            if not host_arches:
                raise koji.BuildError, "No arch list for this host"
            tag_arches = self.session.getBuildConfig(root)['arches']
            if not tag_arches:
                raise koji.BuildError, "No arch list for tag: %s" % root
            #index canonical host arches
            host_arches = dict([(koji.canonArch(a), 1)
                                for a in host_arches.split()])
            #pick the first suitable match from tag's archlist
            for br_arch in tag_arches.split():
                br_arch = koji.canonArch(br_arch)
                if host_arches.has_key(br_arch):
                    #we're done
                    break
            else:
                #no overlap
                raise koji.BuildError, "host does not match tag arches: %s (%s)" % (
                    root, tag_arches)
        else:
            br_arch = arch
        if repo_id:
            repo_info = self.session.repoInfo(repo_id, strict=True)
            if repo_info['tag_name'] != root:
                raise koji.BuildError, "build tag (%s) does not match repo tag (%s)" % (
                    root, repo_info['tag_name'])
            if repo_info['state'] not in (koji.REPO_STATES['READY'],
                                          koji.REPO_STATES['EXPIRED']):
                raise koji.BuildError, "repos in the %s state may not be used by runroot" % koji.REPO_STATES[
                    repo_info['state']]
        else:
            repo_info = self.session.getRepo(root)
        if not repo_info:
            #wait for it
            task_id = self.session.host.subtask(method='waitrepo',
                                                arglist=[root, None, None],
                                                parent=self.id)
            repo_info = self.wait(task_id)[task_id]
        if compat_mode:
            broot = BuildRoot(root, br_arch, self.id, repo_id=repo_info['id'])
        else:
            broot = BuildRoot(self.session,
                              self.options,
                              root,
                              br_arch,
                              self.id,
                              repo_id=repo_info['id'])
            broot.workdir = self.workdir
        broot.init()
        rootdir = broot.rootdir()
        #workaround for rpm oddness
        os.system('rm -f "%s"/var/lib/rpm/__db.*' % rootdir)
        #update buildroot state (so that updateBuildRootList() will work)
        self.session.host.setBuildRootState(broot.id, 'BUILDING')
        try:
            if packages:
                #pkglog = '%s/%s' % (broot.resultdir(), 'packages.log')
                pkgcmd = ['--install'] + packages
                status = broot.mock(pkgcmd)
                self.session.host.updateBuildRootList(broot.id,
                                                      broot.getPackageList())
                if not _isSuccess(status):
                    raise koji.BuildrootError, _parseStatus(status, pkgcmd)

            if isinstance(command, str):
                cmdstr = command
            else:
                #we were passed an arglist
                #we still have to run this through the shell (for redirection)
                #but we can preserve the list structure precisely with careful escaping
                cmdstr = ' '.join(
                    ["'%s'" % arg.replace("'", r"'\''") for arg in command])
            # A nasty hack to put command output into its own file until mock can be
            # patched to do something more reasonable than stuff everything into build.log
            cmdargs = [
                '/bin/sh', '-c',
                "{ %s; } < /dev/null 2>&1 | /usr/bin/tee /tmp/runroot.log; exit ${PIPESTATUS[0]}"
                % cmdstr
            ]

            # always mount /mnt/redhat (read-only)
            # always mount /mnt/iso (read-only)
            # also need /dev bind mount
            self.do_mounts(rootdir, [
                self._get_path_params(x) for x in self.config['default_mounts']
            ])
            self.do_extra_mounts(rootdir, mounts)
            mock_cmd = ['chroot']
            if skip_setarch:
                #we can't really skip it, but we can set it to the current one instead of of the chroot one
                myarch = platform.uname()[5]
                mock_cmd.extend(['--arch', myarch])
            mock_cmd.append('--')
            mock_cmd.extend(cmdargs)
            rv = broot.mock(mock_cmd)
            log_paths = ['/tmp/runroot.log']
            if upload_logs is not None:
                log_paths += upload_logs
            for log_path in log_paths:
                self.uploadFile(rootdir + log_path)
        finally:
            # mock should umount its mounts, but it will not handle ours
            self.undo_mounts(rootdir, fatal=False)
            broot.expire()
        if isinstance(command, str):
            cmdlist = command.split()
        else:
            cmdlist = command
        cmdlist = [param for param in cmdlist if '=' not in param]
        if cmdlist:
            cmd = os.path.basename(cmdlist[0])
        else:
            cmd = '(none)'
        if _isSuccess(rv):
            return '%s completed successfully' % cmd
        else:
            raise koji.BuildrootError, _parseStatus(rv, cmd)