def chat_with_a_client(sock, addr, instance_globals, container): connection = ServerCommandConnection(sock) instance = {'globals': instance_globals, 'connection': connection} try: sock.send(b'Papa is home. Type "help" for commands.\n> ') while True: one_line = connection.readline() args = [] acc = '' if one_line: for arg in one_line.split(' '): if arg: if arg[-1] == '\\': acc += arg[:-1] + ' ' else: acc += arg args.append(acc.strip()) acc = '' if acc: args.append(acc) try: command = lookup_command(args) except Error as e: reply = 'Error: {0}\n'.format(e) else: try: reply = command(sock, args, instance) or '\n' except CloseSocket as e: if e.final_message: send_with_retry(sock, cast_bytes(e.final_message)) break except papa.utils.Error as e: reply = 'Error: {0}\n'.format(e) except Exception as e: reply = 'Error: {0}\n'.format(e) if reply[-1] != '\n': reply += '\n> ' else: reply += '> ' reply = cast_bytes(reply) else: reply = b'> ' send_with_retry(sock, reply) except socket.error: pass try: sock.close() except socket.error: pass if container: thread_object = container[0] instance_globals['active_threads'].remove(thread_object) instance_globals['inactive_threads'].append((addr, thread_object))
def watch_command(sock, args, instance): """Watch a process""" instance_globals = instance['globals'] all_processes = instance_globals['processes'] with instance_globals['lock']: procs = dict((name, {'p': proc, 't': 0, 'closed': False}) for name, proc in wildcard_iter(all_processes, args, True)) if not procs: raise utils.Error('Nothing to watch') send_with_retry(sock, cast_bytes('Watching {0}\n'.format(len(procs)))) return _do_watch(sock, procs, instance)
def _do_watch(sock, procs, instance): instance_globals = instance['globals'] all_processes = instance_globals['processes'] connection = instance['connection'] poller = Poller(sock) delay = .1 while True: data = [] for name, proc in procs.items(): t, l = proc['p'].watch() if l: for item in l: if item.type == OutputQueue.CLOSED: data.append( cast_bytes('closed:{0}:{1}:{2}'.format( name, item.timestamp, item.data))) proc['closed'] = True else: data.append( cast_bytes('{0}:{1}:{2}:{3}'.format( 'out' if item.type == OutputQueue.STDOUT else 'err', name, item.timestamp, len(item.data)))) data.append(item.data) proc['t'] = t if data: delay = .05 data.append(b'] ') out = b'\n'.join(data) send_with_retry(sock, out) one_line = connection.readline().lower() closed = [] for name, proc in procs.items(): t = proc['t'] if t: proc['p'].remove_output(t) if proc['closed']: closed.append(name) if closed: with instance_globals['lock']: for name in closed: closed_proc = procs.pop(name, None) if closed_proc and 'p' in closed_proc: log.info('Removed process %s', closed_proc['p']) all_processes.pop(name, None) if not procs: return 'Nothing left to watch' if one_line == 'q': return 'Stopped watching' else: if poller.poll(delay): return 'Client closed connection' if delay < 1.0: delay += .05
def process_command(sock, args, instance): """Create a process. You need to specify a name, followed by name=value pairs for the process options, followed by the command and args to execute. The name must not contain spaces. Process options are: uid - the username or user ID to use when starting the process gid - the group name or group ID to use when starting the process working_dir - must be an absolute path if specified output - size of each output buffer (default is 1m) You can also specify environment variables by prefixing the name with 'env.' and rlimits by prefixing the name with 'rlimit.' Examples: make process sf uid=1001 gid=2000 working_dir=/sf/bin/ output=1m /sf/bin/uwsgi --ini uwsgi-live.ini --socket fd://27 --stats 127.0.0.1:8090 make process nginx /usr/local/nginx/sbin/nginx """ if not args: raise Error('Process requires a name') name = args.pop(0) env = {} rlimits = {} kwargs = {} for key, value in extract_name_value_pairs(args).items(): if key.startswith('env.'): env[key[4:]] = value elif key.startswith('rlimit.'): key = key[7:] try: rlimits[getattr(resource, 'RLIMIT_%s' % key.upper())] = int(value) except AttributeError: raise utils.Error('Unknown rlimit "%s"' % key) except ValueError: raise utils.Error( 'The rlimit value for "%s" must be an integer, not "%s"' % (key, value)) else: kwargs[key] = value watch = int(kwargs.pop('watch', 0)) p = Process(name, args, env, rlimits, instance, **kwargs) with instance['globals']['lock']: result = p.spawn() if watch: send_with_retry(sock, cast_bytes('{0}\n'.format(result))) return _do_watch(sock, {name: { 'p': result, 't': 0, 'closed': False }}, instance) return str(result)
def watch_command(sock, args, instance): """Watch a process""" instance_globals = instance['globals'] all_processes = instance_globals['processes'] with instance_globals['lock']: procs = dict((name, { 'p': proc, 't': 0, 'closed': False }) for name, proc in wildcard_iter(all_processes, args, True)) if not procs: raise utils.Error('Nothing to watch') send_with_retry(sock, cast_bytes('Watching {0}\n'.format(len(procs)))) return _do_watch(sock, procs, instance)
def _do_watch(sock, procs, instance): instance_globals = instance['globals'] all_processes = instance_globals['processes'] connection = instance['connection'] poller = Poller(sock) delay = .1 while True: data = [] for name, proc in procs.items(): t, l = proc['p'].watch() if l: for item in l: if item.type == OutputQueue.CLOSED: data.append(cast_bytes('closed:{0}:{1}:{2}'.format(name, item.timestamp, item.data))) proc['closed'] = True else: data.append(cast_bytes('{0}:{1}:{2}:{3}'.format('out' if item.type == OutputQueue.STDOUT else 'err', name, item.timestamp, len(item.data)))) data.append(item.data) proc['t'] = t if data: delay = .05 data.append(b'] ') out = b'\n'.join(data) send_with_retry(sock, out) one_line = connection.readline().lower() closed = [] for name, proc in procs.items(): t = proc['t'] if t: proc['p'].remove_output(t) if proc['closed']: closed.append(name) if closed: with instance_globals['lock']: for name in closed: closed_proc = procs.pop(name, None) if closed_proc and 'p' in closed_proc: log.info('Removed process %s', closed_proc['p']) all_processes.pop(name, None) if not procs: return 'Nothing left to watch' if one_line == 'q': return 'Stopped watching' else: if poller.poll(delay): return 'Client closed connection' if delay < 1.0: delay += .05
def process_command(sock, args, instance): """Create a process. You need to specify a name, followed by name=value pairs for the process options, followed by the command and args to execute. The name must not contain spaces. Process options are: uid - the username or user ID to use when starting the process gid - the group name or group ID to use when starting the process working_dir - must be an absolute path if specified output - size of each output buffer (default is 1m) You can also specify environment variables by prefixing the name with 'env.' and rlimits by prefixing the name with 'rlimit.' Examples: make process sf uid=1001 gid=2000 working_dir=/sf/bin/ output=1m /sf/bin/uwsgi --ini uwsgi-live.ini --socket fd://27 --stats 127.0.0.1:8090 make process nginx /usr/local/nginx/sbin/nginx """ if not args: raise Error('Process requires a name') name = args.pop(0) env = {} rlimits = {} kwargs = {} for key, value in extract_name_value_pairs(args).items(): if key.startswith('env.'): env[key[4:]] = value elif key.startswith('rlimit.'): key = key[7:] try: rlimits[getattr(resource, 'RLIMIT_%s' % key.upper())] = int(value) except AttributeError: raise utils.Error('Unknown rlimit "%s"' % key) except ValueError: raise utils.Error('The rlimit value for "%s" must be an integer, not "%s"' % (key, value)) else: kwargs[key] = value watch = int(kwargs.pop('watch', 0)) p = Process(name, args, env, rlimits, instance, **kwargs) with instance['globals']['lock']: result = p.spawn() if watch: send_with_retry(sock, cast_bytes('{0}\n'.format(result))) return _do_watch(sock, {name: {'p': result, 't': 0, 'closed': False}}, instance) return str(result)
def close(self): if self.connection: # if the server is waiting for an ack, we can if self._need_ack: send_with_retry(self.connection.sock, b'q\n') self._need_ack = False self.connection.get_full_response() # we can only recover the connection if we were able to send # the quit ack. otherwise close the connection and let the # socket die if not self.papa_object.connection: self.papa_object.connection = self.connection else: self.connection.close() else: self.connection.close() self.connection = None
def acknowledge(self): if self._need_ack: send_with_retry(self.connection.sock, b'\n') self._need_ack = False
def send_command(self, command): if isinstance(command, list): command = ' '.join(c.replace(' ', '\ ').replace('\n', '\ ') for c in command if c) command = b(command) send_with_retry(self.sock, command + b'\n')
import sys import socket from papa.utils import cast_string, send_with_retry, recv_with_retry __author__ = 'Scott Maxwell' if len(sys.argv) != 2: sys.stderr.write('Need one port number\n') sys.exit(1) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('127.0.0.1', int(sys.argv[1]))) send_with_retry(sock, b'howdy\n') data = recv_with_retry(sock) sys.stdout.write(cast_string(data)) sock.close()
import sys import socket from papa.utils import cast_string, send_with_retry, recv_with_retry __author__ = 'Scott Maxwell' if len(sys.argv) != 2: sys.stderr.write('Need one file descriptor\n') sys.exit(1) listen_socket = socket.fromfd(int(sys.argv[1]), socket.AF_INET, socket.SOCK_STREAM) sock, address = listen_socket.accept() while True: data = recv_with_retry(sock) if data: send_with_retry(sock, data) sys.stdout.write(cast_string(data)) else: break sock.close()
def send_command(self, command): if isinstance(command, list): command = ' '.join( c.replace(' ', '\ ').replace('\n', '\ ') for c in command if c) command = b(command) send_with_retry(self.sock, command + b'\n')