""" Query the heartbeat server from the command line. As an argument, takes either server:port or the falcon run directory (if not argument is given, uses the current directory). """ import argparse import collections import os import re import socket import sys STATE_FN = 'state.py' # taken from network_based.py STATE_DIR = 'mypwatcher' # taken from pwatcher_bridge.py # send message delimited with a \0 def socket_send(socket, message): socket.sendall(b'{}\0'.format(message)) # receive all of \0 delimited message # may discard content past \0, if any, so not safe to call twice on same socket def socket_read(socket): buffer = bytearray(b' ' * 256) nbytes = socket.recv_into(buffer, 256) if nbytes == 0: # empty message return message = '' while nbytes != 0: try: # index() raises when it can't find the character i = buffer[:nbytes].index('\0') message += str(buffer[:i]) # discard past delimiter break except ValueError: # haven't reached end yet message += str(buffer) nbytes = socket.recv_into(buffer, 256) return message # get server and port from watcher state file def use_state(filename): with open(filename, 'r') as f: for line in f: match = re.match(r" 'server': \('([^']+)', (\d+)\)", line) if match: return (match.group(1), int(match.group(2))) print('Error: could not find server info in state file {}'.format(filename)) def parse_args(): parser = argparse.ArgumentParser(description='query falcon network based heartbeat server') parser.add_argument('-s', '--server', help='') parser.add_argument('-f', '--file', help='location of pwatcher state file') parser.add_argument('-d', '--debug', default=False, action='store_const', const=True, help='get server state instead of process list') parser.add_argument('sf', nargs='?', help='specify server or file') return parser.parse_args() # parse command line argument (if any) to find server info def find_server(args): i = 0 if args.server: i += 1 if args.file: i += 1 if args.sf: i += 1 if i > 1: raise Exception('Error: may only specify server once. Try "--help".') if args.sf: if os.path.exists(args.sf): args.file = args.sf else: try: args.sf.index(':') except ValueError: print('Error: could not parse argument as file or server:port: {}'.format(args.sf)) return args.server = args.sf if args.server: try: i = args.server.index(':') except ValueError: print('Error: could not parse argument as server:port: {}'.format(args.server)) return server = args.server[:i] port = int(args.server[i + 1:]) return (server, port) if not args.file: args.file = '.' if os.path.isfile(args.file): return use_state(args.file) elif os.path.isdir(args.file): if os.path.isfile(os.path.join(args.file, STATE_FN)): return use_state(os.path.join(args.file, STATE_FN)) elif os.path.isfile(os.path.join(args.file, STATE_DIR, STATE_FN)): return use_state(os.path.join(args.file, STATE_DIR, STATE_FN)) print('Error: could not find state file: {}'.format(args.file)) def main(): args = parse_args() server = find_server(args) if not server: sys.exit(1) s = socket.socket() s.connect(server) if args.debug: socket_send(s, 'D') server_state = socket_read(s) s.close() state = eval(server_state) for jobid, val in state.items(): print('{}: {} {} {} {}'.format(jobid, val[0], val[1], val[2], val[3])) else: socket_send(s, 'L') jobids = socket_read(s) s.close() for jobid in jobids.split(): s = socket.socket() s.connect(server) socket_send(s, 'Q {}'.format(jobid)) m = socket_read(s) s.close() print('{} {}'.format(jobid, m)) if __name__ == "__main__": main()