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) 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: supervisor.clearProcessLogs(name) except xmlrpclib.Fault as 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)
def status(self, names): ''' status <name>\t\tGet status for a single process status <gname>:*\tGet status for all processes in a group status <name> <name>\tGet status for multiple named processes status\t\t\tGet all process status info ''' self.reread() all_infos = self.supervisor.getAllProcessInfo() if "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.logger.info(msg) return matching_infos
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 sendProcessSignal(self, name, signal = signal.SIGHUP): """ Send an arbitrary UNIX signal to the process named by name @param string name The name of the process to signal (or 'group:name') @param int signal the integer UNIX signal to send. SIGHUP by default. @return boolean result """ self._update('sendProcessSignal') group, process = self._getGroupAndProcess(name) if process is None: group_name, process_name = split_namespec(name) return self.sendGroupSignal(group_name, signal = signal) if process.get_state() not in RUNNING_STATES: raise RPCError(Faults.NOT_RUNNING) msg = process.signal(signal) if not msg is None: raise RPCError(Faults.FAILED, msg) cb = lambda: True cb.delay = 0 cb.rpcinterface = self return cb
def do_kill(self, arg): if not self.ctl.upcheck(): return args = arg.strip().split() if not args: self.ctl.output("Error: kill requires a signal and process name") self.help_kill() return signal = args[0] names = args[1:] if not names: self.ctl.output("Error: kill requires a process name") self.help_start() return for name in names: group_name, process_name = split_namespec(name) if process_name is None: results = self.laforge.killProcessGroup(group_name, signal) for result in results: result = self._killresult(result) self.ctl.output(result) else: try: result = self.laforge.killProcess(name, signal) except xmlrpclib.Fault, e: error = self._killresult({'status':e.faultCode, 'name':name, 'description':e.faultString}) self.ctl.output(error) else: self.ctl.output('%s: signal sent' % name)
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)
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 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 force_process_state(self, namespec, state): """ Publishes a fake process event showing a state for the process. """ application_name, process_name = split_namespec(namespec) # create payload from event payload = {'processname': process_name, 'groupname': application_name, 'state': state, 'now': int(time.time()), 'pid': 0, 'expected': False} self.logger.debug('payload={}'.format(payload)) self.publisher.send_process_event(payload)
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) 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 self.supervisord.options.logger.info( 'waiting for %s to stop' % process.config.name ) 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 as 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 as e: error = self._signalresult({'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: signalled' % name)
def start(self, names): ''' start <name>\t\tStart a process start <gname>:*\t\tStart all processes in a group start <name> <name>\tStart multiple processes or groups start all\t\tStart all processes ''' self.reread() if not names: self.logger.info("Error: start requires a process name") return [] results = [] if 'all' in names: results = self.supervisor.startAllProcesses() for result in results: result = self._startresult(result) self.logger.info(result) else: for name in names: group_name, process_name = split_namespec(name) if process_name is None: try: _results = self.supervisor.startProcessGroup(group_name) results.extend(_results) for result in _results: result = self._startresult(result) self.logger.info(result) except xmlrpclib.Fault, e: if e.faultCode == xmlrpc.Faults.BAD_NAME: error = "%s: ERROR (no such group)" % group_name self.logger.info(error) else: raise else: try: result = self.supervisor.startProcess(name) results.append(result) except xmlrpclib.Fault, e: error = self._startresult({'status': e.faultCode, 'name': process_name, 'group': group_name, 'description': e.faultString}) self.logger.info(error) else: name = make_namespec(group_name, process_name)
def stopProcess(self, name, wait=True): """ Stop a process named by name :param name: The name of the process to stop (or 'group:name') :type name: string :param wait: Wait for the process to be fully stopped :type wait: boolean :return: Always return True unless error :rtype: boolean """ 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) stopped = [] called = [] def killit(): if not called: if process.get_state() not in RUNNING_STATES: raise RPCError(Faults.NOT_RUNNING) # use a mutable for lexical scoping; see startProcess called.append(1) if not stopped: msg = process.stop() if msg is not None: raise RPCError(Faults.FAILED, msg) stopped.append(1) if wait: return NOT_DONE_YET else: return True if process.get_state() not in (ProcessStates.STOPPED, ProcessStates.EXITED): return NOT_DONE_YET else: return True killit.delay = 0.2 killit.rpcinterface = self return killit # deferred
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_stop(self, arg): if not self.ctl.upcheck(): return names = arg.split() supervisor = self.ctl.get_supervisor() if not names: self.ctl.output("Error: stop requires a process name") self.help_stop() return if "all" in names: results = supervisor.stopAllProcesses() for result in results: result = self._stopresult(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.stopProcessGroup(group_name) for result in results: result = self._stopresult(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.stopProcess(name) except xmlrpclib.Fault, e: error = self._stopresult( { "status": e.faultCode, "name": process_name, "group": group_name, "description": e.faultString, } ) self.ctl.output(error) else:
def do_stop(self, arg, exitOnError=True): if not self.ctl.upcheck(): return names = arg.split() supervisor = self.ctl.get_supervisor() if not names: self.handle_error('Error: stop requires a process name') self.help_stop() return if 'all' in names: results = supervisor.stopAllProcesses() for result in results: result = self._stopresult(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.stopProcessGroup(group_name) for result in results: result = self._stopresult(result) self.ctl.output(result) except xmlrpclib.Fault as e: if e.faultCode == xmlrpc.Faults.BAD_NAME: error = "%s: ERROR (no such group)" % group_name logOnly = not exitOnError self.handle_error(message=error, logOnly=logOnly) else: self.handle_error(unhandled=True) else: try: supervisor.stopProcess(name) except xmlrpclib.Fault as e: error = self._stopresult({'status': e.faultCode, 'name': process_name, 'group': group_name, 'description':e.faultString}) self.ctl.error_output(error) else: name = make_namespec(group_name, process_name) self.ctl.output('%s: stopped' % name)
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 as 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 as e: error = self._startresult({'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: started' % name)
def stop(self, names): ''' self.logger.info("stop <name>\t\tStop a process") self.logger.info("stop <gname>:*\t\tStop all processes in a group") self.logger.info("stop <name> <name>\tStop multiple processes or groups") self.logger.info("stop all\t\tStop all processes") ''' self.reread() results = [] if 'all' in names: results = self.supervisor.stopAllProcesses() for result in results: self.logger.info(result) else: for name in names: group_name, process_name = split_namespec(name) if process_name is None: try: _results = self.supervisor.stopProcessGroup(group_name) results.extend(_results) for result in _results: self.logger.info(result) except xmlrpclib.Fault, e: if e.faultCode == xmlrpc.Faults.BAD_NAME: error = "%s: ERROR (no such group)" % group_name self.logger.info(error) else: raise else: try: result = self.supervisor.stopProcess(name) results.append(result) except xmlrpclib.Fault, e: error = { 'status': e.faultCode, 'name': process_name, 'group': group_name, 'description': e.faultString} results.append(error) self.logger.info(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])
def killProcess(self, name, signal): """ Send signal to a process @param string signal Signal identifier @param string name Process name (or 'group:name', or 'group:*') @return boolean result Always true unless error """ self._update('killProcess') group, process = self._getGroupAndProcess(name) if process is None: group_name, process_name = split_namespec(name) return self.killProcessGroup(signal, group_name) sig = self._getSignalFromString(signal) if sig is None: raise RPCError(Faults.BAD_ARGUMENTS, signal) killed = [] called = [] kill = self.supervisord.options.kill def killit(): if not called: if process.get_state() not in RUNNING_STATES: raise RPCError(Faults.NOT_RUNNING) # use a mutable for lexical scoping; see startProcess called.append(1) if not killed: kill(process.pid, sig) killed.append(1) return True killit.delay = 0.2 killit.rpcinterface = self return killit # deferred
def do_start(self, arg): if not self.ctl.upcheck(): return names = arg.strip().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: results = supervisor.startProcessGroup(group_name) for result in results: result = self._startresult(result) self.ctl.output(result) else: try: result = supervisor.startProcess(name) except xmlrpclib.Fault, e: error = self._startresult({ 'status': e.faultCode, 'name': name, 'description': e.faultString }) self.ctl.output(error) else: self.ctl.output('%s: started' % name)
def do_kill(self, arg): if not self.ctl.upcheck(): return args = arg.strip().split() if not args: self.ctl.output("Error: kill requires a signal and process name") self.help_kill() return signal = args[0] names = args[1:] if not names: self.ctl.output("Error: kill requires a process name") self.help_start() return for name in names: group_name, process_name = split_namespec(name) if process_name is None: results = self.laforge.killProcessGroup(group_name, signal) for result in results: result = self._killresult(result) self.ctl.output(result) else: try: result = self.laforge.killProcess(name, signal) except xmlrpclib.Fault, e: error = self._killresult({ 'status': e.faultCode, 'name': name, 'description': e.faultString }) self.ctl.output(error) else: self.ctl.output('%s: signal sent' % name)
def do_start(self, arg): if not self.ctl.upcheck(): return code = None names = arg.strip().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, code = self._startresult(result) self.ctl.output(result) else: for name in names: group_name, process_name = split_namespec(name) if process_name is None: results = supervisor.startProcessGroup(group_name) for result in results: result, code = self._startresult(result) self.ctl.output(result) else: try: result = supervisor.startProcess(name) except xmlrpclib.Fault, e: error, code = self._startresult({'status':e.faultCode, 'name':name, 'description':e.faultString}) self.ctl.output(error) else: self.ctl.output('%s: started' % name)
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 as why: raise RPCError(Faults.NO_FILE, why.args[0]) except (BadCommand, NotExecutable, NoPermission) as why: raise RPCError(Faults.NOT_EXECUTABLE, why.args[0]) if process.get_state() in RUNNING_STATES: raise RPCError(Faults.ALREADY_STARTED, name) if process.get_state() == ProcessStates.UNKNOWN: raise RPCError(Faults.FAILED, "%s is in an unknown process state" % name) process.spawn() # We call reap() in order to more quickly obtain the side effects of # process.finish(), which reap() eventually ends up calling. This # might be the case if the spawn() was successful but then the process # died before its startsecs elapsed or it exited with an unexpected # exit code. In particular, finish() may set spawnerr, which we can # check and immediately raise an RPCError, avoiding the need to # defer by returning a callback. self.supervisord.reap() if process.spawnerr: raise RPCError(Faults.SPAWN_ERROR, name) # We call process.transition() in order to more quickly obtain its # side effects. In particular, it might set the process' state from # STARTING->RUNNING if the process has a startsecs==0. process.transition() if wait and process.get_state() != ProcessStates.RUNNING: # by default, this branch will almost always be hit for processes # with default startsecs configurations, because the default number # of startsecs for a process is "1", and the process will not have # entered the RUNNING state yet even though we've called # transition() on it. This is because a process is not considered # RUNNING until it has stayed up > startsecs. def onwait(): if process.spawnerr: raise RPCError(Faults.SPAWN_ERROR, name) state = process.get_state() if state not in (ProcessStates.STARTING, ProcessStates.RUNNING): raise RPCError(Faults.ABNORMAL_TERMINATION, name) if state == ProcessStates.RUNNING: return True return NOT_DONE_YET onwait.delay = 0.05 onwait.rpcinterface = self return onwait # deferred return True
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 as 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 as 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 as 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 as 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 else: def stopdone(): return 'Process %s stopped' % namespec stopdone.delay = 0.05 return stopdone elif action == 'restart': callback = rpcinterface.system.multicall( [ {'methodName':'supervisor.stopProcess', 'params': [namespec]}, {'methodName':'supervisor.startProcess', 'params': [namespec]}, ] ) def restartprocess(): result = callback() if result is NOT_DONE_YET: return NOT_DONE_YET return 'Process %s restarted' % namespec restartprocess.delay = 0.05 return restartprocess elif action == 'clearlog': try: callback = rpcinterface.supervisor.clearProcessLogs( namespec) except RPCError as e: def clearerr(): return 'unexpected rpc fault [%d] %s' % ( e.code, e.text) clearerr.delay = 0.05 return clearerr def clearlog(): return 'Log for %s cleared' % namespec clearlog.delay = 0.05 return clearlog raise ValueError(action)
def get_process(self, namespec): """ This method returns the process configuration related to a namespec. """ # WARN: the following line may throw a KeyError exception application_name, process_name = split_namespec(namespec) return self.supervisord.process_groups[application_name].processes[ process_name]
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 elif action == 'stop': callback = rpcinterface.supervisor.stopProcess(namespec) def stopprocess(): result = callback() if result is NOT_DONE_YET: return NOT_DONE_YET return 'Process %s stopped' % namespec stopprocess.delay = 0.05 return stopprocess elif action == 'restart': callback = rpcinterface.system.multicall( [ {'methodName':'supervisor.stopProcess', 'params': [namespec]}, {'methodName':'supervisor.startProcess', 'params': [namespec]}, ] ) def restartprocess(): result = callback() if result is NOT_DONE_YET: return NOT_DONE_YET return 'Process %s restarted' % namespec restartprocess.delay = 0.05 return restartprocess elif action == 'start': try: callback = rpcinterface.supervisor.startProcess( namespec) except RPCError, e: if e.code == Faults.SPAWN_ERROR: def spawnerr(): return 'Process %s spawn error' % namespec spawnerr.delay = 0.05 return spawnerr def startprocess(): if callback() is NOT_DONE_YET: return NOT_DONE_YET return 'Process %s started' % namespec startprocess.delay = 0.05 return startprocess elif action == 'clearlog': callback = rpcinterface.supervisor.clearProcessLog( namespec) def clearlog(): return 'Log for %s cleared' % namespec clearlog.delay = 0.05 return clearlog
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 as 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 as 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 as e: msg = 'unexpected rpc fault [%d] %s' % (e.code, e.text) def stoperr(): return msg stoperr.delay = 0.05 return stoperr if callable(bool_or_callback): def stopprocess(): try: result = bool_or_callback() except RPCError as 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 else: def stopdone(): return 'Process %s stopped' % namespec stopdone.delay = 0.05 return stopdone elif action == 'restart': results_or_callback = rpcinterface.system.multicall([ { 'methodName': 'supervisor.stopProcess', 'params': [namespec] }, { 'methodName': 'supervisor.startProcess', 'params': [namespec] }, ]) if callable(results_or_callback): callback = results_or_callback def restartprocess(): results = callback() if results is NOT_DONE_YET: return NOT_DONE_YET return 'Process %s restarted' % namespec restartprocess.delay = 0.05 return restartprocess else: def restartdone(): return 'Process %s restarted' % namespec restartdone.delay = 0.05 return restartdone elif action == 'clearlog': try: callback = rpcinterface.supervisor.clearProcessLogs( namespec) except RPCError as e: msg = 'unexpected rpc fault [%d] %s' % (e.code, e.text) def clearerr(): return msg clearerr.delay = 0.05 return clearerr def clearlog(): return 'Log for %s cleared' % namespec clearlog.delay = 0.05 return clearlog raise ValueError(action)
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 = sys.exc_info()[1] raise RPCError(Faults.NO_FILE, why.args[0]) except (NotExecutable, NoPermission): why = sys.exc_info()[1] raise RPCError(Faults.NOT_EXECUTABLE, why.args[0]) started = [] startsecs = process.config.startsecs def startit(): if not started: if process.get_state() in RUNNING_STATES: raise RPCError(Faults.ALREADY_STARTED, name) process.spawn() if process.spawnerr: raise RPCError(Faults.SPAWN_ERROR, name) # we use a list here to fake out lexical scoping; # using a direct assignment to 'started' in the # function appears to not work (symptom: 2nd or 3rd # call through, it forgets about 'started', claiming # it's undeclared). started.append(time.time()) if not wait or not startsecs: return True t = time.time() runtime = (t - started[0]) state = process.get_state() if state not in (ProcessStates.STARTING, ProcessStates.RUNNING): raise RPCError(Faults.ABNORMAL_TERMINATION, name) if runtime < startsecs: return NOT_DONE_YET if state == ProcessStates.RUNNING: return True raise RPCError(Faults.ABNORMAL_TERMINATION, name) startit.delay = 0.05 startit.rpcinterface = self return startit # deferred
def get_process(self, namespec): """ This method returns the process configuration related to a namespec. """ # WARN: the following line may throw a KeyError exception application_name, process_name = split_namespec(namespec) return self.supervisord.process_groups[application_name].processes[process_name]
def _get_application_process(self, namespec): """ Return the ApplicationStatus and ProcessStatus corresponding to the namespec. A BAD_NAME exception is raised if the application or the process is not found. """ application_name, process_name = split_namespec(namespec) return (self._get_application(application_name), self._get_process(namespec) if process_name else None)
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 as why: raise RPCError(Faults.NO_FILE, why.args[0]) except (NotExecutable, NoPermission) as why: raise RPCError(Faults.NOT_EXECUTABLE, why.args[0]) if process.get_state() in RUNNING_STATES: raise RPCError(Faults.ALREADY_STARTED, name) process.spawn() # We call reap() in order to more quickly obtain the side effects of # process.finish(), which reap() eventually ends up calling. This # might be the case if the spawn() was successful but then the process # died before its startsecs elapsed or it exited with an unexpected # exit code. In particular, finish() may set spawnerr, which we can # check and immediately raise an RPCError, avoiding the need to # defer by returning a callback. self.supervisord.reap() if process.spawnerr: raise RPCError(Faults.SPAWN_ERROR, name) # We call process.transition() in order to more quickly obtain its # side effects. In particular, it might set the process' state from # STARTING->RUNNING if the process has a startsecs==0. process.transition() if wait and process.get_state() != ProcessStates.RUNNING: # by default, this branch will almost always be hit for processes # with default startsecs configurations, because the default number # of startsecs for a process is "1", and the process will not have # entered the RUNNING state yet even though we've called # transition() on it. This is because a process is not considered # RUNNING until it has stayed up > startsecs. def onwait(): if process.spawnerr: raise RPCError(Faults.SPAWN_ERROR, name) process.transition() state = process.get_state() if state not in (ProcessStates.STARTING, ProcessStates.RUNNING): raise RPCError(Faults.ABNORMAL_TERMINATION, name) if state == ProcessStates.RUNNING: return True return NOT_DONE_YET onwait.delay = 0.05 onwait.rpcinterface = self return onwait # deferred return True
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 elif action == "stop": callback = rpcinterface.supervisor.stopProcess(namespec) def stopprocess(): result = callback() if result is NOT_DONE_YET: return NOT_DONE_YET return "Process %s stopped" % namespec stopprocess.delay = 0.05 return stopprocess elif action == "restart": callback = rpcinterface.system.multicall( [ {"methodName": "supervisor.stopProcess", "params": [namespec]}, {"methodName": "supervisor.startProcess", "params": [namespec]}, ] ) def restartprocess(): result = callback() if result is NOT_DONE_YET: return NOT_DONE_YET return "Process %s restarted" % namespec restartprocess.delay = 0.05 return restartprocess elif action == "start": try: callback = rpcinterface.supervisor.startProcess(namespec) except RPCError as 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 code %d" % e.code def starterr(): return "ERROR: Process %s: %s" % (namespec, msg) starterr.delay = 0.05 return starterr def startprocess(): try: result = callback() except RPCError as e: if e.code == Faults.SPAWN_ERROR: msg = "spawn error" elif e.code == Faults.ABNORMAL_TERMINATION: msg = "abnormal termination" else: msg = "unexpected rpc fault code %d" % e.code 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 elif action == "clearlog": callback = rpcinterface.supervisor.clearProcessLog(namespec) def clearlog(): return "Log for %s cleared" % namespec clearlog.delay = 0.05 return clearlog raise ValueError(action)
def get_program(self, namespec): """ Get a program from the context using its namespec. """ application_name, process_name = split_namespec(namespec) return self.get_application(application_name).get_program(process_name)
def make_callback(self, namespec, action): message = None 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 elif action == 'stop': callback = rpcinterface.supervisor.stopProcess(namespec) def stopprocess(): result = callback() if result is NOT_DONE_YET: return NOT_DONE_YET return 'Process %s stopped' % namespec stopprocess.delay = 0.05 return stopprocess elif action == 'restart': callback = rpcinterface.system.multicall([ { 'methodName': 'supervisor.stopProcess', 'params': [namespec] }, { 'methodName': 'supervisor.startProcess', 'params': [namespec] }, ]) def restartprocess(): result = callback() if result is NOT_DONE_YET: return NOT_DONE_YET return 'Process %s restarted' % namespec restartprocess.delay = 0.05 return restartprocess elif action == 'start': try: callback = rpcinterface.supervisor.startProcess( namespec) except RPCError, e: if e.code == Faults.SPAWN_ERROR: def spawnerr(): return 'Process %s spawn error' % namespec spawnerr.delay = 0.05 return spawnerr def startprocess(): if callback() is NOT_DONE_YET: return NOT_DONE_YET return 'Process %s started' % namespec startprocess.delay = 0.05 return startprocess elif action == 'clearlog': callback = rpcinterface.supervisor.clearProcessLog( namespec) def clearlog(): return 'Log for %s cleared' % namespec clearlog.delay = 0.05 return clearlog
def _get_application_process(self, namespec): """ Return the ApplicationStatus and ProcessStatus corresponding to the namespec. A BAD_NAME exception is raised if the application or the process is not found. """ application_name, process_name = split_namespec(namespec) return self._get_application(application_name), self._get_process(namespec) if process_name else None