def do_status(self, arg):
        if not self.ctl.upcheck():
            return

        supervisor = self.ctl.get_supervisor()
        all_infos = supervisor.getAllProcessInfo()

        names = arg.split()
        if not names or "all" in names:
            matching_infos = all_infos
        else:
            matching_infos = []

            for name in names:
                bad_name = True
                group_name, process_name = split_namespec(name)

                for info in all_infos:
                    matched = info['group'] == group_name
                    if process_name is not None:
                        matched = matched and info['name'] == process_name

                    if matched:
                        bad_name = False
                        matching_infos.append(info)

                if bad_name:
                    if process_name is None:
                        msg = "%s: ERROR (no such group)" % group_name
                    else:
                        msg = "%s: ERROR (no such process)" % name
                    self.ctl.output(msg)
        self._show_statuses(matching_infos)
    def signalProcess(self, name, signal):
        """ Send an arbitrary UNIX signal to the process named by name

        @param string name    Name of the process to signal (or 'group:name')
        @param string signal  Signal to send, as name ('HUP') or number ('1')
        @return boolean
        """

        self._update('signalProcess')

        group, process = self._getGroupAndProcess(name)

        if process is None:
            group_name, process_name = split_namespec(name)
            return self.signalProcessGroup(group_name, signal=signal)

        try:
            sig = signal_number(signal)
        except ValueError:
            raise RPCError(Faults.BAD_SIGNAL, signal)

        if process.get_state() not in RUNNING_STATES:
            raise RPCError(Faults.NOT_RUNNING, name)

        msg = process.signal(sig)

        if not msg is None:
            raise RPCError(Faults.FAILED, msg)

        return True
    def do_clear(self, arg):
        if not self.ctl.upcheck():
            return

        names = arg.split()

        if not names:
            self.ctl.output('Error: clear requires a process name')
            self.help_clear()
            return

        supervisor = self.ctl.get_supervisor()

        if 'all' in names:
            results = supervisor.clearAllProcessLogs()
            for result in results:
                result = self._clearresult(result)
                self.ctl.output(result)
        else:
            for name in names:
                group_name, process_name = split_namespec(name)
                try:
                    result = supervisor.clearProcessLogs(name)
                except xmlrpclib.Fault, e:
                    error = self._clearresult({
                        'status': e.faultCode,
                        'name': process_name,
                        'group': group_name,
                        'description': e.faultString
                    })
                    self.ctl.output(error)
                else:
                    name = make_namespec(group_name, process_name)
                    self.ctl.output('%s: cleared' % name)
Esempio n. 4
0
    def handle_request(self, request):
        if request.command != 'GET':
            request.error (400) # bad request
            return

        path, params, query, fragment = request.split_uri()

        if '%' in path:
            path = http_server.unquote(path)

        # strip off all leading slashes
        while path and path[0] == '/':
            path = path[1:]

        path, process_name_and_channel = path.split('/', 1)

        try:
            process_name, channel = process_name_and_channel.split('/', 1)
        except ValueError:
            # no channel specified, default channel to stdout
            process_name = process_name_and_channel
            channel = 'stdout'

        from docker_supervisor.options import split_namespec
        group_name, process_name = split_namespec(process_name)

        group = self.supervisord.process_groups.get(group_name)
        if group is None:
            request.error(404) # not found
            return

        process = group.processes.get(process_name)
        if process is None:
            request.error(404) # not found
            return

        logfile = getattr(process.config, '%s_logfile' % channel, None)

        if logfile is None or not os.path.exists(logfile):
            # XXX problematic: processes that don't start won't have a log
            # file and we probably don't want to go into fatal state if we try
            # to read the log of a process that did not start.
            request.error(410) # gone
            return

        mtime = os.stat(logfile)[stat.ST_MTIME]
        request['Last-Modified'] = http_date.build_http_date(mtime)
        request['Content-Type'] = 'text/plain'
        # the lack of a Content-Length header makes the outputter
        # send a 'Transfer-Encoding: chunked' response

        request.push(tail_f_producer(request, logfile, 1024))

        request.done()
    def stopProcess(self, name, wait=True):
        """ Stop a process named by name

        @param string name  The name of the process to stop (or 'group:name')
        @param boolean wait        Wait for the process to be fully stopped
        @return boolean result     Always return True unless error
        """
        self._update('stopProcess')

        group, process = self._getGroupAndProcess(name)

        if process is None:
            group_name, process_name = split_namespec(name)
            return self.stopProcessGroup(group_name, wait)

        if process.get_state() not in RUNNING_STATES:
            raise RPCError(Faults.NOT_RUNNING, name)

        msg = process.stop()
        if msg is not None:
            raise RPCError(Faults.FAILED, msg)

        # We'll try to reap any killed child. FWIW, reap calls waitpid, and
        # then, if waitpid returns a pid, calls finish() on the process with
        # that pid, which drains any I/O from the process' dispatchers and
        # changes the process' state.  I chose to call reap without once=True
        # because we don't really care if we reap more than one child.  Even if
        # we only reap one child. we may not even be reaping the child that we
        # just stopped (this is all async, and process.stop() may not work, and
        # we'll need to wait for SIGKILL during process.transition() as the
        # result of normal select looping).

        self.supervisord.reap()

        if wait and process.get_state() not in STOPPED_STATES:

            def onwait():
                # process will eventually enter a stopped state by
                # virtue of the supervisord.reap() method being called
                # during normal operations
                process.stop_report()
                if process.get_state() not in STOPPED_STATES:
                    return NOT_DONE_YET
                return True

            onwait.delay = 0
            onwait.rpcinterface = self
            return onwait # deferred

        return True
    def do_signal(self, arg):
        if not self.ctl.upcheck():
            return

        args = arg.split()
        if len(args) < 2:
            self.ctl.output(
                'Error: signal requires a signal name and a process name')
            self.help_signal()
            return

        sig = args[0]
        names = args[1:]
        supervisor = self.ctl.get_supervisor()

        if 'all' in names:
            results = supervisor.signalAllProcesses(sig)
            for result in results:
                result = self._signalresult(result)
                self.ctl.output(result)

        else:
            for name in names:
                group_name, process_name = split_namespec(name)
                if process_name is None:
                    try:
                        results = supervisor.signalProcessGroup(
                            group_name, sig)
                        for result in results:
                            result = self._signalresult(result)
                            self.ctl.output(result)
                    except xmlrpclib.Fault, e:
                        if e.faultCode == xmlrpc.Faults.BAD_NAME:
                            error = "%s: ERROR (no such group)" % group_name
                            self.ctl.output(error)
                        else:
                            raise
                else:
                    try:
                        supervisor.signalProcess(name, sig)
                    except xmlrpclib.Fault, e:
                        error = self._signalresult({
                            'status': e.faultCode,
                            'name': process_name,
                            'group': group_name,
                            'description': e.faultString
                        })
                        self.ctl.output(error)
                    else:
    def _getGroupAndProcess(self, name):
        # get process to start from name
        group_name, process_name = split_namespec(name)

        group = self.supervisord.process_groups.get(group_name)
        if group is None:
            raise RPCError(Faults.BAD_NAME, name)

        if process_name is None:
            return group, None

        process = group.processes.get(process_name)
        if process is None:
            raise RPCError(Faults.BAD_NAME, name)

        return group, process
    def do_start(self, arg):
        if not self.ctl.upcheck():
            return

        names = arg.split()
        supervisor = self.ctl.get_supervisor()

        if not names:
            self.ctl.output("Error: start requires a process name")
            self.help_start()
            return

        if 'all' in names:
            results = supervisor.startAllProcesses()
            for result in results:
                result = self._startresult(result)
                self.ctl.output(result)

        else:
            for name in names:
                group_name, process_name = split_namespec(name)
                if process_name is None:
                    try:
                        results = supervisor.startProcessGroup(group_name)
                        for result in results:
                            result = self._startresult(result)
                            self.ctl.output(result)
                    except xmlrpclib.Fault, e:
                        if e.faultCode == xmlrpc.Faults.BAD_NAME:
                            error = "%s: ERROR (no such group)" % group_name
                            self.ctl.output(error)
                        else:
                            raise
                else:
                    try:
                        result = supervisor.startProcess(name)
                    except xmlrpclib.Fault, e:
                        error = self._startresult({
                            'status': e.faultCode,
                            'name': process_name,
                            'group': group_name,
                            'description': e.faultString
                        })
                        self.ctl.output(error)
                    else:
    def startProcess(self, name, wait=True):
        """ Start a process

        @param string name Process name (or ``group:name``, or ``group:*``)
        @param boolean wait Wait for process to be fully started
        @return boolean result     Always true unless error

        """
        self._update('startProcess')
        group, process = self._getGroupAndProcess(name)
        if process is None:
            group_name, process_name = split_namespec(name)
            return self.startProcessGroup(group_name, wait)

        # test filespec, don't bother trying to spawn if we know it will
        # eventually fail
        try:
            filename, argv = process.get_execv_args()
        except NotFound, why:
            raise RPCError(Faults.NO_FILE, why.args[0])
Esempio n. 10
0
    def make_callback(self, namespec, action):
        supervisord = self.context.supervisord

        # the rpc interface code is already written to deal properly in a
        # deferred world, so just use it
        main = ('supervisor', SupervisorNamespaceRPCInterface(supervisord))
        system = ('system', SystemNamespaceRPCInterface([main]))

        rpcinterface = RootRPCInterface([main, system])

        if action:

            if action == 'refresh':

                def donothing():
                    message = 'Page refreshed at %s' % time.ctime()
                    return message

                donothing.delay = 0.05
                return donothing

            elif action == 'stopall':
                callback = rpcinterface.supervisor.stopAllProcesses()

                def stopall():
                    if callback() is NOT_DONE_YET:
                        return NOT_DONE_YET
                    else:
                        return 'All stopped at %s' % time.ctime()

                stopall.delay = 0.05
                return stopall

            elif action == 'restartall':
                callback = rpcinterface.system.multicall([{
                    'methodName':
                    'supervisor.stopAllProcesses'
                }, {
                    'methodName':
                    'supervisor.startAllProcesses'
                }])

                def restartall():
                    result = callback()
                    if result is NOT_DONE_YET:
                        return NOT_DONE_YET
                    return 'All restarted at %s' % time.ctime()

                restartall.delay = 0.05
                return restartall

            elif namespec:

                def wrong():
                    return 'No such process named %s' % namespec

                wrong.delay = 0.05
                group_name, process_name = split_namespec(namespec)
                group = supervisord.process_groups.get(group_name)
                if group is None:
                    return wrong
                process = group.processes.get(process_name)
                if process is None:
                    return wrong

                if action == 'start':
                    try:
                        bool_or_callback = (
                            rpcinterface.supervisor.startProcess(namespec))
                    except RPCError, e:
                        if e.code == Faults.NO_FILE:
                            msg = 'no such file'
                        elif e.code == Faults.NOT_EXECUTABLE:
                            msg = 'file not executable'
                        elif e.code == Faults.ALREADY_STARTED:
                            msg = 'already started'
                        elif e.code == Faults.SPAWN_ERROR:
                            msg = 'spawn error'
                        elif e.code == Faults.ABNORMAL_TERMINATION:
                            msg = 'abnormal termination'
                        else:
                            msg = 'unexpected rpc fault [%d] %s' % (e.code,
                                                                    e.text)

                        def starterr():
                            return 'ERROR: Process %s: %s' % (namespec, msg)

                        starterr.delay = 0.05
                        return starterr

                    if callable(bool_or_callback):

                        def startprocess():
                            try:
                                result = bool_or_callback()
                            except RPCError, e:
                                if e.code == Faults.SPAWN_ERROR:
                                    msg = 'spawn error'
                                elif e.code == Faults.ABNORMAL_TERMINATION:
                                    msg = 'abnormal termination'
                                else:
                                    msg = 'unexpected rpc fault [%d] %s' % (
                                        e.code, e.text)
                                return 'ERROR: Process %s: %s' % (namespec,
                                                                  msg)

                            if result is NOT_DONE_YET:
                                return NOT_DONE_YET
                            return 'Process %s started' % namespec

                        startprocess.delay = 0.05
                        return startprocess
                    else:

                        def startdone():
                            return 'Process %s started' % namespec

                        startdone.delay = 0.05
                        return startdone

                elif action == 'stop':
                    try:
                        bool_or_callback = (
                            rpcinterface.supervisor.stopProcess(namespec))
                    except RPCError, e:

                        def stoperr():
                            return 'unexpected rpc fault [%d] %s' % (e.code,
                                                                     e.text)

                        stoperr.delay = 0.05
                        return stoperr

                    if callable(bool_or_callback):

                        def stopprocess():
                            try:
                                result = bool_or_callback()
                            except RPCError, e:
                                return 'unexpected rpc fault [%d] %s' % (
                                    e.code, e.text)
                            if result is NOT_DONE_YET:
                                return NOT_DONE_YET
                            return 'Process %s stopped' % namespec

                        stopprocess.delay = 0.05
                        return stopprocess