Exemplo n.º 1
0
class OperateCmd(QueryCmd):
    """An operation command will query the database and run an arbitrary
    operation on each object returned."""

    # the default set of options for all operation commands
    options = [
        CmdLineTool.StrListOption("-c", "--cols",
                                  help="list of columns that will be "
                                       "printed for each each row."),

        CmdLineTool.StrListOption("-s", "--sortby",
                                  help="sort the results in a specified "
                                       "order before performing any "
                                       "operations."),

        CmdLineTool.BooleanOption("--ns", "--nosort", dest="nosort",
                                  help="do not sort the results"),

        CmdLineTool.IntOption    ("--limit",
                                  help="only operate on the first l rows"),

        ] + CmdLineTool.CmdLineTool.options

    def __init__(self, table, *args, **kwargs):
        # call the super
        super(OperateCmd, self).__init__(table, *args, **kwargs)

        # if a list of objects is provided at the command line, then
        # subclasses can fill in this value.  Setting this will prevent
        # the database from being contacted
        self.objects = []

    def parseArgs(self, *args, **kwargs):
        result = super(OperateCmd, self).parseArgs(*args, **kwargs)
        
        # make sure a where exists
        if not self.where:
            raise OptionParser.HelpRequest(self.getHelpStr())

        # make sure a value is set for options we are not supporting, but
        # that the super expects to exist.

        for name,default in (("distinct", None),
                             ("delimiter", ' '),
                             ("raw", False),
                             ("timefmt", None),
                             ("noformat", False),
                             ("noheader", False)):
            self.opts.__dict__.setdefault(name, default)

        return result

    def opendb(self):
        """We don't need to open the database if the objects member is set."""
        if not self.objects:
            super(OperateCmd, self).opendb()

    def getNewObjs(self, num, curr, objs, distinct):
        """Return at most 'num' new objects for the operationLoop.  The
        objects returned are tq Operation Job or Task objects.  By
        default the mrd cursor is checked for waiting job objects, but
        a list can be provided which will be modified."""

        # a list of all the operation objects we are going to return
        newobjs = []
        # loop until we have enough objects
        while len(newobjs) < num and curr < len(objs):
            obj = objs[curr]
            curr += 1
            # check if this object is distinct
            if not self.isDistinct(obj, distinct):
                if self.parent.opts.debug: print 'already worked on'
                continue

            # skip over this object if we don't have permission
            if not (self.parent.force or obj.hasPermission()):
                msg = "permission denied: not job owner"
                if self.parent.color:
                    msg = terminal.TerminalColor('red').colorStr(msg)
                print self.formatter.format(obj), msg
                continue

            # we passed all the tests, so add it to the list
            newobjs.append(obj)

        return newobjs,curr

    def processResult(self, qresult):
        """Process and print all the objects returned from the query."""

        # if we had no results, then do nothing
        if not qresult or \
           (self.opts.limit is not None and self.opts.limit < 0):
            return

        # make sure the query result doesn't cache objects after they are
        # created, as we will only need them once.
        if isinstance(qresult, Database.QueryResult):
            qresult.cacheObjects = False

        file = sys.stdout

        # set the widths of our formatter so everything is neatly spaced
        if not self.opts.noformat:
            self.formatter.setWidths(qresult)

        # print a header
        if not self.opts.noheader:
            print >>file, self.formatter.header()

        # keep track of which objects are distinct
        distinct = {}

        # our current list of objects that have had the operation started,
        # but the operation has not finished.  Typically because the dispatcher
        # is busy reading from it and would block the process.
        queue = []

        # keep track of how many objects we've worked on
        workedon = 0
        # time we last created an object (only useful when pausing between
        # operations).
        lastcreate = 0

        # make sure threads is set to at least one
        if self.parent.threads < 1:
            self.parent.threads = 1

        # setup a blocking flag
        if not self.parent.yes or self.parent.threads <= 1:
            self.blocking = True
        else:
            self.blocking = False

        # keep track of our current index into the query result.
        curr = 0

        try:
            # start operating on the objects
            while True:
                # if we are running in parallel mode (i.e. non-blocking) we
                # want to have as many concurrent connections as possible.
                # Thus make sure the queue size is always the size of
                # self.threads, or at least as big as it can be.

                newobjs = []

                # check if we need to pause inbetween operations
                if self.parent.pause > 0:
                    # how much time has passed since our last object create
                    elapsed = self.parent.pause - (time.time() - lastcreate)
                    # if we don't have any objects on the queue, and 'pause'
                    # seconds hasn't elapsed
                    if not queue and elapsed > 0:
                        time.sleep(elapsed)
                        elapsed = 0

                    # add another item to the queue
                    if elapsed <= 0 and len(queue) < self.parent.threads:
                        newobjs,curr = self.getNewObjs(1, curr,
                                                       qresult, distinct)
                        lastcreate = time.time()

                else:
                    # get however many more we can take on now
                    newobjs,curr = self.getNewObjs(
                        self.parent.threads - len(queue),
                        curr, qresult, distinct)

                # if we have nothing left, then we're all done!
                if not (queue or newobjs) or \
                   (not queue and \
                    self.opts.limit not in [None, 0] and \
                    self.opts.limit <= workedon):
                    break

                # start the new operations now.  If we are in blocking
                # mode, (self.yesToAll == False or self.threads <= 1),
                # then the entire operation will be done here.  If we are
                # in parallel mode (i.e. non-blocking), then the connect
                # will initialize here, raise a WouldBlock exception, and
                # be put onto the queue.
                for obj in newobjs:
                    try:
                        # work on this object
                        self.processObject(obj)
                    except Sockets.WouldBlock:
                        # if this would block, then add it to the queue
                        queue.append(obj)
                    except Sockets.SocketError, err:
                        # catch any other socket related error
                        obj.post(self, str(err), error=True)
                        obj.close()
                    except EngineClient.EngineClientError, err:
                        obj.post(self, str(err), error=True)
                        obj.close()
                    except:
Exemplo n.º 2
0
class TractorCLT(CmdLineTool.MultiCmdLineTool):
    """The main command object for the cli just includes all the sub-command objects."""
    version = "2.0"
    DEFAULT_THREADS = 10
    DEFAULT_TIMEOUT = 30
    DEFAULT_TIMEFMT = os.environ.get("TRACTOR_TIMEFMT")

    # setup all the commands in this app
    commands = {
        "jobs"          : ListCmds.JobsCmd,
        "tasks"         : ListCmds.TasksCmd,
        "commands"      : ListCmds.CommandsCmd,
        "cmds"          : ListCmds.CommandsCmd,
        "invocations"   : ListCmds.InvocationsCmd,
        "invos"         : ListCmds.InvocationsCmd,
        "blades"        : ListCmds.BladesCmd,
        "params"        : ListCmds.ParamsCmd,

        "chcrews"       : JobCmds.ChangeCrewsCmd,
        "chpri"         : JobCmds.ChangePriorityCmd,
        "delay"         : JobCmds.DelayJobCmd,
        "delete"        : JobCmds.DeleteJobCmd,
        "jattr"         : JobCmds.ChangeJobAttributeCmd,
        "pause"         : JobCmds.PauseJobCmd,
        "interrupt"     : JobCmds.InterruptJobCmd,
        "restart"       : JobCmds.RestartJobCmd,
        "retryallerrs"  : JobCmds.RetryAllErrorsCmd,
        "skipallerrs"   : JobCmds.SkipAllErrorsCmd,
        "undelay"       : JobCmds.UndelayJobCmd,
        "undelete"      : JobCmds.UndeleteJobCmd,
        "unpause"       : JobCmds.UnpauseJobCmd,

        "retry"         : TaskCmds.RetryTaskCmd,
        "resume"        : TaskCmds.ResumeTaskCmd,
        "skip"          : TaskCmds.SkipTaskCmd,
        "log"           : TaskCmds.PrintLogCmd,

        "chkeys"        : CommandCmds.ChangeKeysCmd,
        "cattr"         : CommandCmds.ChangeCommandAttributeCmd,
        
        "nimby"         : BladeCmds.NimbyBladeCmd,
        "unnimby"       : BladeCmds.UnnimbyBladeCmd,
        "trace"         : BladeCmds.TraceBladeCmd,

        "help"          : HelpCmds.MainHelp,
        None            : HelpCmds.MainHelp,

        "alias"         : HelpCmds.AliasHelp,
        }

    # command only viewable by rpg folk
    adminCommands = {
        }

    # command aliases
    aliases = {
        "aliases"   : "alias",
        "machs"     : "machines",
        "queue"     : "jobs -s pri,-spooled not errwait and",
        }

    # set the options that the main program will have
    options = [
        CmdLineTool.BooleanOption ("-y", "--yes",
                                   help="answer 'yes' to all questions"),
        
        CmdLineTool.BooleanOption ("-a", "--archives",
                                   help="search archive tables"),
        
        CmdLineTool.BooleanOption ("--force",
                                   help="force all operations.  This will "
                                        "allow any operation to be performed "
                                        "on a task or job, even if you are "
                                        "not the owner."),

        CmdLineTool.BooleanOption ("--nocolor", dest="color", default=True,
                                   help="do not display any output in color."),
        
        CmdLineTool.BooleanOption ("--zeros",
                                   help="some fields do not display a value "
                                        "if it is equal to zero, this will "
                                        "force zeros to be printed no matter "
                                        "what."),

        CmdLineTool.BooleanOption ("--nothreads", dest="threads", const=1,
                                   help="do not use threads, when performing "
                                        "task/job operations, threads are "
                                        "only used when --yes is applied."),

        CmdLineTool.IntOption     ("--threads", default=DEFAULT_THREADS,
                                   help="maximum number of concurrent "
                                        "threads, default=%d, setting this "
                                        "to 1 or lower is the same as "
                                        "--nothreads." % DEFAULT_THREADS),

        CmdLineTool.SecondsOption ("-p", "--pause",
                                   help="pause p seconds inbetween each "
                                        "action (e.g. retry, skip, etc.) "
                                        "This can be a floating point value."),

        CmdLineTool.SecondsOption ("-t", "--timeout", default=DEFAULT_TIMEOUT,
                                   help="timeout in seconds before canceling "
                                        "an operation, default=%d seconds." %
                                   DEFAULT_TIMEOUT),

        CmdLineTool.BooleanOption ("--login", default=False,
                                   help="explicitly log in to engine rather than use existing session id "
                                   "query"),

        CmdLineTool.BooleanOption ("--logout", default=False,
                                   help="automatically log out from engine after performing "
                                   "query"),

        DBCmdLineTool.RawDataOption(),
        
        DBCmdLineTool.TimeFormatOption(default=DEFAULT_TIMEFMT),
        
        DBCmdLineTool.FullTimeOption(),
        
        CmdLineTool.StringOption   ("--engine",
                                    help="<hostname>:<port> of engine"),
        CmdLineTool.StringOption   ("-u", "--user", help="engine username"),
        CmdLineTool.StringOption   ("--password", "--pw", help="engine user password"),
        CmdLineTool.StringOption   ("--password-file", "--pwfile", help="path to json file containing engine username and password"),
        CmdLineTool.BooleanOption  ("--traceback", help="show full traceback on exceptions (developer option)"),

        CmdLineTool.BooleanOption  ("-d", "--debug", help="display debug info"),

        CmdLineTool.VersionOption  ("-v", "--version", help="display version info"),
        
        ] + CmdLineTool.MultiCmdLineTool.options


    def __init__(self, *args, **kwds):
        self.__userPrefs = None
        super(TractorCLT, self).__init__(*args, **kwds)

    def getUserPrefs(self):
        """Return a pointer to the user prefs object."""
        if self.__userPrefs is None:
            self.__userPrefs = {} # cli.UserPrefs()
        return self.__userPrefs
    userPrefs = property(fget=getUserPrefs)

    def parseArgs(self, *args, **kwds):
        super(TractorCLT, self).parseArgs(*args, **kwds)

        self.opts.nocolor = not self.opts.color
        # set all the options as members of ourself
        for var in ("yes", "force", "color", "zeros", "threads", "pause",
                    "timeout"):
            setattr(self, var, getattr(self.opts, var))

        global ShowFullTraceback
        ShowFullTraceback = self.opts.traceback

    def getHelpStr(self):
        """Print a custom help message."""
        # get the help command
        helpcmd = self.getCommand("help")
        # run the main help
        helpcmd.run()

    def getNewCommand(self, cmd, *args, **kwds):
        """Get a L{CmdLineTool} instance that should be used for the
        provided command.

        @param cmd: name of the command being referenced.
        @type cmd: string

        @return: L{CmdLineTool} that will be used
        @rtype: L{CmdLineTool} instance
        """
        kwds["raiseArgErrors"] = True
        try:
            return self.commands[cmd](*args, **kwds)
        except KeyError:
            raise CmdLineTool.UnknownCommand(cmd)

    def getCommandToRun(self):
        try:
            return super(TractorCLT, self).getCommandToRun()
        except CmdLineTool.UnknownCommand, err:
            # check for the fields command which we will redirect to the
            # main help command
            if self.args and self.args[0] == "fields":
                command = "help"
                cmdobj = self.getCommand(command)
                args = ["fields"] + self.args[1:]

                return (command, cmdobj, args)

            # check the user prefs for command aliases
            try:
                alias = self.userPrefs.aliases.command[self.args[0]]
            except (AttributeError, KeyError):
                # check the global command alias list
                alias = self.aliases.get(self.args[0])

            if alias:
                # check for additional arguments in the alias
                import rpg.stringutil as stringutil
                aliasArgs = stringutil.quotedSplit(alias, removeQuotes=True)
                command   = aliasArgs[0]
                cmdobj    = self.getCommand(command)
                args      = aliasArgs[1:] + self.args[1:]
                return (command, cmdobj, args)

            raise CmdLineTool.UnknownCommand, err