Esempio n. 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)
         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
Esempio n. 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
     with open(fn, 'a') as fslog:
         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)
             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()
     if error is not None:
         self.undo_mounts(rootdir, fatal=False)
         raise error
Esempio n. 3
0
    def handler(self, root, arch, command, keep=False, packages=[], mounts=[], repo_id=None, skip_setarch=False, weight=None, upload_logs=None, new_chroot=False):
        """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 br_arch in host_arches:
                    #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]
        broot = BuildRoot(self.session, self.options, root, br_arch, self.id, repo_id=repo_info['id'], setup_dns=True)
        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 /builddir/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 new_chroot:
                mock_cmd.append('--new-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 = ['/builddir/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))
Esempio n. 4
0
    def handler(self, root, arch, command, keep=False, packages=[], mounts=[], repo_id=None, skip_setarch=False, weight=None, upload_logs=None, new_chroot=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 = set([koji.canonArch(a) 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 br_arch in host_arches:
                    #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]
        broot = BuildRoot(self.session, self.options, root, br_arch, self.id,
                repo_id=repo_info['id'], setup_dns=True,
                internal_dev_setup=self.config['internal_dev_setup'])
        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 /builddir/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 new_chroot:
                mock_cmd.append('--new-chroot')
            elif new_chroot is False: # None -> no option added
                mock_cmd.append('--old-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 = ['builddir/runroot.log']
            if upload_logs is not None:
                log_paths += upload_logs
            for log_path in log_paths:
                self.uploadFile(os.path.join(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))