def test_ok(self): from supervisor.childutils import listener from supervisor.dispatchers import PEventListenerDispatcher begin = as_string(PEventListenerDispatcher.RESULT_TOKEN_START) stdout = StringIO() listener.ok(stdout) self.assertEqual(stdout.getvalue(), begin + '2\nOK')
def test_token(self): from supervisor.childutils import listener from supervisor.dispatchers import PEventListenerDispatcher token = PEventListenerDispatcher.READY_FOR_EVENTS_TOKEN stdout = StringIO() listener.ready(stdout) self.assertEqual(stdout.getvalue(), token)
def test_token(self): from supervisor.childutils import listener from supervisor.dispatchers import PEventListenerDispatcher token = as_string(PEventListenerDispatcher.READY_FOR_EVENTS_TOKEN) stdout = StringIO() listener.ready(stdout) self.assertEqual(stdout.getvalue(), token)
def test_fail(self): from supervisor.childutils import listener from supervisor.dispatchers import PEventListenerDispatcher begin = as_string(PEventListenerDispatcher.RESULT_TOKEN_START) stdout = StringIO() listener.fail(stdout) self.assertEqual(stdout.getvalue(), begin + '4\nFAIL')
def test_ok(self): from supervisor.childutils import listener from supervisor.dispatchers import PEventListenerDispatcher begin = PEventListenerDispatcher.RESULT_TOKEN_START stdout = StringIO() listener.ok(stdout) self.assertEqual(stdout.getvalue(), begin + '2\nOK')
def signal(self, sig): """Send a signal to the subprocess, without intending to kill it. Return None if the signal was sent, or an error message string if an error occurred or if the subprocess is not running. """ options = self.config.options if not self.pid: msg = ("attempted to send %s sig %s but it wasn't running" % (self.logname, signame(sig))) options.logger.debug(msg) return msg options.logger.debug('sending %s (pid %s) sig %s' % (self.logname, self.pid, signame(sig))) self._assertInState(ProcessStates.RUNNING, ProcessStates.STARTING, ProcessStates.STOPPING) try: options.kill(self.pid, sig) except: io = StringIO() traceback.print_exc(file=io) tb = io.getvalue() msg = 'unknown problem sending sig %s (%s):%s' % (self.logname, self.pid, tb) options.logger.critical(msg) self.change_state(ProcessStates.UNKNOWN) self.pid = 0 return msg return None
def test_fail(self): from supervisor.childutils import listener from supervisor.dispatchers import PEventListenerDispatcher begin = PEventListenerDispatcher.RESULT_TOKEN_START stdout = StringIO() listener.fail(stdout) self.assertEqual(stdout.getvalue(), begin + '4\nFAIL')
def continue_request(self, data, request): logger = self.supervisord.options.logger try: params, method = self.loads(data) # no <methodName> in the request or name is an empty string if not method: logger.trace('XML-RPC request received with no method name') request.error(400) return # we allow xml-rpc clients that do not send empty <params> # when there are no parameters for the method call if params is None: params = () try: logger.trace('XML-RPC method called: %s()' % method) value = self.call(method, params) # application-specific: instead of we never want to # marshal None (even though we could by saying allow_none=True # in dumps within xmlrpc_marshall), this is meant as # a debugging fixture, see issue 223. assert value is not None, ( 'return value from method %r with params %r is None' % (method, params) ) logger.trace('XML-RPC method %s() returned successfully' % method) except RPCError as err: # turn RPCError reported by method into a Fault instance value = xmlrpclib.Fault(err.code, err.text) logger.trace('XML-RPC method %s() returned fault: [%d] %s' % ( method, err.code, err.text)) if isinstance(value, types.FunctionType): # returning a function from an RPC method implies that # this needs to be a deferred response (it needs to block). pushproducer = request.channel.push_with_producer pushproducer(DeferredXMLRPCResponse(request, value)) else: # if we get anything but a function, it implies that this # response doesn't need to be deferred, we can service it # right away. body = xmlrpc_marshal(value) request['Content-Type'] = 'text/xml' request['Content-Length'] = len(body) request.push(body) request.done() except: io = StringIO() traceback.print_exc(file=io) val = io.getvalue() logger.critical(val) # internal error, report as HTTP server error request.error(500)
def test_send(self): from supervisor.childutils import pcomm stdout = StringIO() pcomm.send('hello', stdout) from supervisor.events import ProcessCommunicationEvent begin = ProcessCommunicationEvent.BEGIN_TOKEN end = ProcessCommunicationEvent.END_TOKEN self.assertEqual(stdout.getvalue(), '%s%s%s' % (begin, 'hello', end))
def test_send(self): from supervisor.childutils import listener from supervisor.dispatchers import PEventListenerDispatcher begin = PEventListenerDispatcher.RESULT_TOKEN_START stdout = StringIO() msg = 'the body data ya fool\n' listener.send(msg, stdout) expected = '%s%s\n%s' % (begin, len(msg), msg) self.assertEqual(stdout.getvalue(), expected)
def test_send(self): from supervisor.childutils import listener from supervisor.dispatchers import PEventListenerDispatcher begin = as_string(PEventListenerDispatcher.RESULT_TOKEN_START) stdout = StringIO() msg = 'the body data ya fool\n' listener.send(msg, stdout) expected = '%s%s\n%s' % (begin, len(msg), msg) self.assertEqual(stdout.getvalue(), expected)
def signal(self, sig): """Send a signal to the subprocess, without intending to kill it. Return None if the signal was sent, or an error message string if an error occurred or if the subprocess is not running. """ options = self.config.options if not self.pid: msg = ("attempted to send %s sig %s but it wasn't running" % (self.config.name, signame(sig))) options.logger.debug(msg) return msg options.logger.debug('sending %s (pid %s) sig %s' % (self.config.name, self.pid, signame(sig)) ) self._assertInState( ProcessStates.RUNNING, ProcessStates.STARTING, ProcessStates.STOPPING ) try: options.kill(self.pid, sig) except ValueError as e: # signal not supported msg = 'problem sending sig %s (%s): %s' % ( self.config.name, self.pid, str(e)) io = StringIO() traceback.print_exc(file=io) tb = io.getvalue() options.logger.error(tb) return msg except: io = StringIO() traceback.print_exc(file=io) tb = io.getvalue() msg = 'unknown problem sending sig %s (%s):%s' % ( self.config.name, self.pid, tb) options.logger.critical(msg) self.change_state(ProcessStates.UNKNOWN) self.pid = 0 return msg
def test_error(self): inst = self._makeOne() try: old_stderr = sys.stderr stderr = StringIO() sys.stderr = stderr self.assertEqual(inst.error('url', 'error'), None) self.assertEqual(stderr.getvalue(), 'url error\n') finally: sys.stderr = old_stderr
def test_feed(self): inst = self._makeOne() try: old_stdout = sys.stdout stdout = StringIO() sys.stdout = stdout inst.feed('url', 'data') self.assertEqual(stdout.getvalue(), 'data') finally: sys.stdout = old_stdout
def test_wait(self): from supervisor.childutils import listener class Dummy: def readline(self): return 'len:5' def read(self, *ignored): return 'hello' stdin = Dummy() stdout = StringIO() headers, payload = listener.wait(stdin, stdout) self.assertEqual(headers, {'len':'5'}) self.assertEqual(payload, 'hello') self.assertEqual(stdout.getvalue(), 'READY\n')
def test_main_noprofile(self): from supervisor.supervisord import main conf = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'fixtures', 'donothing.conf') new_stdout = StringIO() old_stdout = sys.stdout try: tempdir = tempfile.mkdtemp() log = os.path.join(tempdir, 'log') pid = os.path.join(tempdir, 'pid') sys.stdout = new_stdout main(args=['-c', conf, '-l', log, '-j', pid, '-n'], test=True) finally: sys.stdout = old_stdout shutil.rmtree(tempdir) output = new_stdout.getvalue() self.assertTrue(output.find('supervisord started') != 1, output)
def more(self): if self.finished: return "" try: response = self.callback() if response is NOT_DONE_YET: return NOT_DONE_YET self.finished = True return self.sendresponse(response) except: io = StringIO() traceback.print_exc(file=io) # this should go to the main supervisor log file self.request.channel.server.logger.log("Web interface error", io.getvalue()) self.finished = True self.request.error(500)
def more(self): if self.finished: return '' try: response = self.callback() if response is NOT_DONE_YET: return NOT_DONE_YET self.finished = True return self.sendresponse(response) except: io = StringIO() traceback.print_exc(file=io) # this should go to the main supervisor log file self.request.channel.server.logger.log('Web interface error', io.getvalue()) self.finished = True self.request.error(500)
def test_main_noprofile(self): from supervisor.supervisord import main conf = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'fixtures', 'donothing.conf') new_stdout = StringIO() old_stdout = sys.stdout try: tempdir = tempfile.mkdtemp() log = os.path.join(tempdir, 'log') pid = os.path.join(tempdir, 'pid') sys.stdout = new_stdout main(args=['-c', conf, '-l', log, '-j', pid, '-n'], test=True) finally: sys.stdout = old_stdout shutil.rmtree(tempdir) output = new_stdout.getvalue() self.assertTrue(output.find('supervisord started') != 1, output)
def test_main_profile(self): from supervisor.supervisord import main conf = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'fixtures', 'donothing.conf') new_stdout = StringIO() new_stdout.fileno = lambda: 1 old_stdout = sys.stdout try: tempdir = tempfile.mkdtemp() log = os.path.join(tempdir, 'log') pid = os.path.join(tempdir, 'pid') sys.stdout = new_stdout main(args=['-c', conf, '-l', log, '-j', pid, '-n', '--profile_options=cumulative,calls'], test=True) finally: sys.stdout = old_stdout shutil.rmtree(tempdir) output = new_stdout.getvalue() self.assertTrue('cumulative time, call count' in output, output)
def test_silent_on(self): from supervisor.supervisord import main conf = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'fixtures', 'donothing.conf') new_stdout = StringIO() new_stdout.fileno = lambda: 1 old_stdout = sys.stdout try: tempdir = tempfile.mkdtemp() log = os.path.join(tempdir, 'log') pid = os.path.join(tempdir, 'pid') sys.stdout = new_stdout main(args=['-c', conf, '-l', log, '-j', pid, '-n', '-s'], test=True) finally: sys.stdout = old_stdout shutil.rmtree(tempdir) output = new_stdout.getvalue() self.assertEqual(len(output), 0)
def handle_request(self, request): path = request.split_uri()[0] self.hit_counter.increment() if path == self.statusdir: # and not a subdirectory up_time = ''.join(english_time(long(time.time()) - START_TIME)) request['Content-Type'] = 'text/html' request.push('<html>' '<title>Medusa Status Reports</title>' '<body bgcolor="#ffffff">' '<h1>Medusa Status Reports</h1>' '<b>Up:</b> %s' % up_time) for i in range(len(self.objects)): try: request.push(self.objects[i].status()) except: import traceback stream = StringIO() traceback.print_exc(None, stream) request.push( '<h2><font color="red">Error in Channel %3d: %s</font><pre>%s</pre>' % (i, escape(repr( self.objects[i])), escape(stream.getvalue()))) request.push('<hr>\r\n') request.push( '<p><a href="%s/channel_list">Channel List</a>' '<hr>' '<img src="%s/medusa.gif" align=right width=%d height=%d>' '</body></html>' % (self.statusdir, self.statusdir, medusa_gif.width, medusa_gif.height)) request.done() elif path == self.statusdir + '/channel_list': request['Content-Type'] = 'text/html' request.push('<html><body>') request.push(channel_list_producer(self.statusdir)) request.push( '<hr>' '<img src="%s/medusa.gif" align=right width=%d height=%d>' % (self.statusdir, medusa_gif.width, medusa_gif.height) + '</body></html>') request.done() elif path == self.statusdir + '/medusa.gif': request['Content-Type'] = 'image/gif' request['Content-Length'] = len(medusa_gif.data) request.push(medusa_gif.data) request.done() elif path == self.statusdir + '/close_zombies': message = ('<h2>Closing all zombie http client connections...</h2>' '<p><a href="%s">Back to the status page</a>' % self.statusdir) request['Content-Type'] = 'text/html' request['Content-Length'] = len(message) request.push(message) now = int(time.time()) for channel in asyncore.socket_map.keys(): if channel.__class__ == http_server.http_channel: if channel != request.channel: if (now - channel.creation_time ) > channel.zombie_timeout: channel.close() request.done() # Emergency Debug Mode # If a server is running away from you, don't KILL it! # Move all the AF_INET server ports and perform an autopsy... # [disabled by default to protect the innocent] elif self.allow_emergency_debug and path == self.statusdir + '/emergency_debug': request.push('<html>Moving All Servers...</html>') request.done() for channel in asyncore.socket_map.keys(): if channel.accepting: if type(channel.addr) is type(()): ip, port = channel.addr channel.socket.close() channel.del_channel() channel.addr = (ip, port + 10000) fam, typ = channel.family_and_type channel.create_socket(fam, typ) channel.set_reuse_addr() channel.bind(channel.addr) channel.listen(5) else: m = self.hyper_regex.match(path) if m: oid = int(m.group(1)) for object in self.hyper_objects: if id(object) == oid: if hasattr(object, 'hyper_respond'): object.hyper_respond(self, path, request) else: request.error(404) return
def handle_request (self, request): path = request.split_uri()[0] self.hit_counter.increment() if path == self.statusdir: # and not a subdirectory up_time = ''.join(english_time(long(time.time()) - START_TIME)) request['Content-Type'] = 'text/html' request.push ( '<html>' '<title>Medusa Status Reports</title>' '<body bgcolor="#ffffff">' '<h1>Medusa Status Reports</h1>' '<b>Up:</b> %s' % up_time ) for i in range(len(self.objects)): try: request.push (self.objects[i].status()) except: import traceback stream = StringIO() traceback.print_exc(None,stream) request.push('<h2><font color="red">Error in Channel %3d: %s</font><pre>%s</pre>' % (i,escape(repr(self.objects[i])), escape(stream.getvalue()))) request.push ('<hr>\r\n') request.push ( '<p><a href="%s/channel_list">Channel List</a>' '<hr>' '<img src="%s/medusa.gif" align=right width=%d height=%d>' '</body></html>' % ( self.statusdir, self.statusdir, medusa_gif.width, medusa_gif.height ) ) request.done() elif path == self.statusdir + '/channel_list': request['Content-Type'] = 'text/html' request.push ('<html><body>') request.push(channel_list_producer(self.statusdir)) request.push ( '<hr>' '<img src="%s/medusa.gif" align=right width=%d height=%d>' % ( self.statusdir, medusa_gif.width, medusa_gif.height ) + '</body></html>' ) request.done() elif path == self.statusdir + '/medusa.gif': request['Content-Type'] = 'image/gif' request['Content-Length'] = len(medusa_gif.data) request.push (medusa_gif.data) request.done() elif path == self.statusdir + '/close_zombies': message = ( '<h2>Closing all zombie http client connections...</h2>' '<p><a href="%s">Back to the status page</a>' % self.statusdir ) request['Content-Type'] = 'text/html' request['Content-Length'] = len (message) request.push (message) now = int (time.time()) for channel in asyncore.socket_map.keys(): if channel.__class__ == http_server.http_channel: if channel != request.channel: if (now - channel.creation_time) > channel.zombie_timeout: channel.close() request.done() # Emergency Debug Mode # If a server is running away from you, don't KILL it! # Move all the AF_INET server ports and perform an autopsy... # [disabled by default to protect the innocent] elif self.allow_emergency_debug and path == self.statusdir + '/emergency_debug': request.push ('<html>Moving All Servers...</html>') request.done() for channel in asyncore.socket_map.keys(): if channel.accepting: if type(channel.addr) is type(()): ip, port = channel.addr channel.socket.close() channel.del_channel() channel.addr = (ip, port+10000) fam, typ = channel.family_and_type channel.create_socket (fam, typ) channel.set_reuse_addr() channel.bind (channel.addr) channel.listen(5) else: m = self.hyper_regex.match (path) if m: oid = int(m.group(1)) for object in self.hyper_objects: if id (object) == oid: if hasattr (object, 'hyper_respond'): object.hyper_respond (self, path, request) else: request.error (404) return
def kill(self, sig): """Send a signal to the subprocess. This may or may not kill it. Return None if the signal was sent, or an error message string if an error occurred or if the subprocess is not running. """ now = time.time() options = self.config.options # Properly stop processes in BACKOFF state. if self.state == ProcessStates.BACKOFF: msg = "Attempted to kill %s, which is in BACKOFF state." % self.config.name options.logger.debug(msg) self.change_state(ProcessStates.STOPPED) return if not self.pid: msg = "Attempted to kill %s with sig %s but it wasn't running" % ( self.config.name, signame(sig)) options.logger.debug(msg) return msg # If we're in the stopping state, then we've already sent the stop # signal and this is the kill signal if self.state == ProcessStates.STOPPING: killasgroup = self.config.killasgroup else: killasgroup = self.config.stopasgroup as_group = "" if killasgroup: as_group = "process group " options.logger.debug( 'killing %s (pid %s) %swith signal %s' % (self.config.name, self.pid, as_group, signame(sig))) # RUNNING/STARTING/STOPPING -> STOPPING self.killing = 1 self.delay = now + self.config.stopwaitsecs # we will already be in the STOPPING state if we're doing a # SIGKILL as a result of overrunning stopwaitsecs self._assertInState(ProcessStates.RUNNING, ProcessStates.STARTING, ProcessStates.STOPPING) self.change_state(ProcessStates.STOPPING) pid = self.pid if killasgroup: # send to the whole process group instead pid = -self.pid try: options.kill(pid, sig) except: io = StringIO() traceback.print_exc(file=io) tb = io.getvalue() msg = 'Unknown problem killing %s (%s):%s' % (self.config.name, self.pid, tb) options.logger.critical(msg) self.change_state(ProcessStates.UNKNOWN) self.pid = 0 self.killing = 0 self.delay = 0 return msg
def test_main_writes_data_out_that_looks_like_a_config_file(self): sio = StringIO() confecho.main(out=sio) output = sio.getvalue() self.assertTrue("[supervisord]" in output)
def kill(self, sig): """Send a signal to the subprocess. This may or may not kill it. Return None if the signal was sent, or an error message string if an error occurred or if the subprocess is not running. """ now = time.time() options = self.config.options # Properly stop processes in BACKOFF state. if self.state == ProcessStates.BACKOFF: msg = ("Attempted to kill %s, which is in BACKOFF state." % (self.config.name)) options.logger.debug(msg) self.change_state(ProcessStates.STOPPED) return None if not self.pid: msg = ("attempted to kill %s with sig %s but it wasn't running" % (self.config.name, signame(sig))) options.logger.debug(msg) return msg #If we're in the stopping state, then we've already sent the stop #signal and this is the kill signal if self.state == ProcessStates.STOPPING: killasgroup = self.config.killasgroup else: killasgroup = self.config.stopasgroup as_group = "" if killasgroup: as_group = "process group " options.logger.debug('killing %s (pid %s) %swith signal %s' % (self.config.name, self.pid, as_group, signame(sig)) ) # RUNNING/STARTING/STOPPING -> STOPPING self.killing = 1 self.delay = now + self.config.stopwaitsecs # we will already be in the STOPPING state if we're doing a # SIGKILL as a result of overrunning stopwaitsecs self._assertInState(ProcessStates.RUNNING,ProcessStates.STARTING, ProcessStates.STOPPING) self.change_state(ProcessStates.STOPPING) pid = self.pid if killasgroup: # send to the whole process group instead pid = -self.pid try: options.kill(pid, sig) except: io = StringIO() traceback.print_exc(file=io) tb = io.getvalue() msg = 'unknown problem killing %s (%s):%s' % (self.config.name, self.pid, tb) options.logger.critical(msg) self.change_state(ProcessStates.UNKNOWN) self.pid = 0 self.killing = 0 self.delay = 0 return msg return None