n2n-ctl (n2n-3.0) | : | n2n-ctl (n2n-3.1.1) | ||
---|---|---|---|---|
skipping to change at line 43 | skipping to change at line 43 | |||
if self.key is not None: | if self.key is not None: | |||
options += ['1'] # Flags set for auth key field | options += ['1'] # Flags set for auth key field | |||
options += [self.key] | options += [self.key] | |||
optionsstr = ':'.join(options) | optionsstr = ':'.join(options) | |||
return tagstr, ' '.join((msgtype, optionsstr, cmdline)) | return tagstr, ' '.join((msgtype, optionsstr, cmdline)) | |||
def _rx(self, tagstr): | def _rx(self, tagstr): | |||
"""Wait for rx packets""" | """Wait for rx packets""" | |||
# TODO: there are no timeouts with any of the recv calls | seen_begin = False | |||
data, _ = self.sock.recvfrom(1024) | while not seen_begin: | |||
data = json.loads(data.decode('utf8')) | # TODO: there are no timeouts with any of the recv calls | |||
data, _ = self.sock.recvfrom(1024) | ||||
data = json.loads(data.decode('utf8')) | ||||
# TODO: We assume the first packet we get will be tagged for us | ||||
assert(data['_tag'] == tagstr) | ||||
if data['_type'] == 'error': | ||||
raise ValueError('Error: {}'.format(data['error'])) | ||||
# TODO: We assume the first packet we get will be tagged for us | if data['_type'] == 'replacing': | |||
# and be either an "error" or a "begin" | # a signal that we have evicted an earlier subscribe | |||
assert(data['_tag'] == tagstr) | continue | |||
if data['_type'] == 'error': | if data['_type'] == 'subscribe': | |||
raise ValueError('Error: {}'.format(data['error'])) | return True | |||
assert(data['_type'] == 'begin') | if data['_type'] == 'begin': | |||
seen_begin = True | ||||
# Ideally, we would confirm that this is our "begin", but that | ||||
# would need the cmd passed into this method, and that would | # Ideally, we would confirm that this is our "begin", but that | |||
# probably require parsing the cmdline passed to us :-( | # would need the cmd passed into this method, and that would | |||
# assert(data['cmd'] == cmd) | # probably require parsing the cmdline passed to us :-( | |||
# assert(data['cmd'] == cmd) | ||||
continue | ||||
raise ValueError('Unknown data type {} from ' | ||||
'edge'.format(data['_type'])) | ||||
result = list() | result = list() | |||
error = None | error = None | |||
while True: | while True: | |||
data, _ = self.sock.recvfrom(1024) | data, _ = self.sock.recvfrom(1024) | |||
data = json.loads(data.decode('utf8')) | data = json.loads(data.decode('utf8')) | |||
if data['_tag'] != tagstr: | if data['_tag'] != tagstr: | |||
# this packet is not for us, ignore it | # this packet is not for us, ignore it | |||
skipping to change at line 107 | skipping to change at line 121 | |||
tagstr, msgstr = self._cmdstr(msgtype, cmdline) | tagstr, msgstr = self._cmdstr(msgtype, cmdline) | |||
self.sock.sendto(msgstr.encode('utf8'), (self.address, self.port)) | self.sock.sendto(msgstr.encode('utf8'), (self.address, self.port)) | |||
return self._rx(tagstr) | return self._rx(tagstr) | |||
def read(self, cmdline): | def read(self, cmdline): | |||
return self._call('r', cmdline) | return self._call('r', cmdline) | |||
def write(self, cmdline): | def write(self, cmdline): | |||
return self._call('w', cmdline) | return self._call('w', cmdline) | |||
def str_table(rows, columns): | def sub(self, cmdline): | |||
return self._call('s', cmdline) | ||||
def readevent(self): | ||||
self.sock.settimeout(3600) | ||||
data, _ = self.sock.recvfrom(1024) | ||||
data = json.loads(data.decode('utf8')) | ||||
# assert(data['_tag'] == tagstr) | ||||
assert(data['_type'] == 'event') | ||||
del data['_tag'] | ||||
del data['_type'] | ||||
return data | ||||
def str_table(rows, columns, orderby): | ||||
"""Given an array of dicts, do a simple table print""" | """Given an array of dicts, do a simple table print""" | |||
result = list() | result = list() | |||
widths = collections.defaultdict(lambda: 0) | widths = collections.defaultdict(lambda: 0) | |||
if len(rows) == 0: | if len(rows) == 0: | |||
# No data to show, be sure not to truncate the column headings | # No data to show, be sure not to truncate the column headings | |||
for col in columns: | for col in columns: | |||
widths[col] = len(col) | widths[col] = len(col) | |||
else: | else: | |||
for row in rows: | for row in rows: | |||
for col in columns: | for col in columns: | |||
if col in row: | if col in row: | |||
widths[col] = max(widths[col], len(str(row[col]))) | widths[col] = max(widths[col], len(str(row[col]))) | |||
for col in columns: | for col in columns: | |||
if widths[col] == 0: | if widths[col] == 0: | |||
widths[col] = 1 | widths[col] = 1 | |||
result += "{:{}.{}} ".format(col, widths[col], widths[col]) | result += "{:{}.{}} ".format(col, widths[col], widths[col]) | |||
result += "\n" | result += "\n" | |||
if orderby is not None: | ||||
rows = sorted(rows, key=lambda row: row.get(orderby, 0)) | ||||
for row in rows: | for row in rows: | |||
for col in columns: | for col in columns: | |||
if col in row: | if col in row: | |||
data = row[col] | data = row[col] | |||
else: | else: | |||
data = '' | data = '' | |||
result += "{:{}} ".format(data, widths[col]) | result += "{:{}} ".format(data, widths[col]) | |||
result += "\n" | result += "\n" | |||
return ''.join(result) | return ''.join(result) | |||
skipping to change at line 149 | skipping to change at line 181 | |||
def subcmd_show_supernodes(rpc, args): | def subcmd_show_supernodes(rpc, args): | |||
rows = rpc.read('supernodes') | rows = rpc.read('supernodes') | |||
columns = [ | columns = [ | |||
'version', | 'version', | |||
'current', | 'current', | |||
'macaddr', | 'macaddr', | |||
'sockaddr', | 'sockaddr', | |||
'uptime', | 'uptime', | |||
] | ] | |||
return str_table(rows, columns) | return str_table(rows, columns, args.orderby) | |||
def subcmd_show_edges(rpc, args): | def subcmd_show_edges(rpc, args): | |||
rows = rpc.read('edges') | rows = rpc.read('edges') | |||
columns = [ | columns = [ | |||
'mode', | 'mode', | |||
'ip4addr', | 'ip4addr', | |||
'macaddr', | 'macaddr', | |||
'sockaddr', | 'sockaddr', | |||
'desc', | 'desc', | |||
] | ] | |||
return str_table(rows, columns) | return str_table(rows, columns, args.orderby) | |||
def subcmd_show_help(rpc, args): | def subcmd_show_help(rpc, args): | |||
result = 'Commands with pretty-printed output:\n\n' | result = 'Commands with pretty-printed output:\n\n' | |||
for name, cmd in subcmds.items(): | for name, cmd in subcmds.items(): | |||
result += "{:12} {}\n".format(name, cmd['help']) | result += "{:12} {}\n".format(name, cmd['help']) | |||
result += "\n" | result += "\n" | |||
result += "Possble remote commands:\n" | result += "Possble remote commands:\n" | |||
result += "(those without a pretty-printer will pass-through)\n\n" | result += "(those without a pretty-printer will pass-through)\n\n" | |||
rows = rpc.read('help') | rows = rpc.read('help') | |||
skipping to change at line 196 | skipping to change at line 228 | |||
'func': subcmd_show_edges, | 'func': subcmd_show_edges, | |||
'help': 'Show the list of edges/peers', | 'help': 'Show the list of edges/peers', | |||
}, | }, | |||
} | } | |||
def subcmd_default(rpc, args): | def subcmd_default(rpc, args): | |||
"""Just pass command through to edge""" | """Just pass command through to edge""" | |||
cmdline = ' '.join([args.cmd] + args.args) | cmdline = ' '.join([args.cmd] + args.args) | |||
if args.write: | if args.write: | |||
rows = rpc.write(cmdline) | rows = rpc.write(cmdline) | |||
else: | elif args.read: | |||
rows = rpc.read(cmdline) | rows = rpc.read(cmdline) | |||
elif args.sub: | ||||
if not rpc.sub(cmdline): | ||||
raise ValueError('Could not subscribe') | ||||
while True: | ||||
event = rpc.readevent() | ||||
# FIXME: violates layering.. | ||||
print(json.dumps(event, sort_keys=True, indent=4)) | ||||
else: | ||||
raise ValueError('Unknown request type') | ||||
return json.dumps(rows, sort_keys=True, indent=4) | return json.dumps(rows, sort_keys=True, indent=4) | |||
def main(): | def main(): | |||
ap = argparse.ArgumentParser( | ap = argparse.ArgumentParser( | |||
description='Query the running local n2n edge') | description='Query the running local n2n edge') | |||
ap.add_argument('-t', '--mgmtport', action='store', default=5644, | ap.add_argument('-t', '--mgmtport', action='store', default=5644, | |||
help='Management Port (default=5644)', type=int) | help='Management Port (default=5644)', type=int) | |||
ap.add_argument('-k', '--key', action='store', | ap.add_argument('-k', '--key', action='store', | |||
help='Password for mgmt commands') | help='Password for mgmt commands') | |||
ap.add_argument('-d', '--debug', action='store_true', | ap.add_argument('-d', '--debug', action='store_true', | |||
help='Also show raw internal data') | help='Also show raw internal data') | |||
ap.add_argument('--raw', action='store_true', | ap.add_argument('--raw', action='store_true', | |||
help='Force cmd to avoid any pretty printing') | help='Force cmd to avoid any pretty printing') | |||
ap.add_argument('--orderby', action='store', | ||||
help='Hint to a pretty printer on how to sort') | ||||
group = ap.add_mutually_exclusive_group() | group = ap.add_mutually_exclusive_group() | |||
group.add_argument('--read', action='store_true', | group.add_argument('--read', action='store_true', | |||
help='Make a read request (default)') | help='Make a read request (default)') | |||
group.add_argument('--write', action='store_true', | group.add_argument('--write', action='store_true', | |||
help='Make a write request (only to non pretty' | help='Make a write request (only to non pretty' | |||
'printed cmds)') | 'printed cmds)') | |||
group.add_argument('--sub', action='store_true', | ||||
help='Make a subscribe request') | ||||
ap.add_argument('cmd', action='store', | ap.add_argument('cmd', action='store', | |||
help='Command to run (try "help" for list)') | help='Command to run (try "help" for list)') | |||
ap.add_argument('args', action='store', nargs="*", | ap.add_argument('args', action='store', nargs="*", | |||
help='Optional args for the command') | help='Optional args for the command') | |||
args = ap.parse_args() | args = ap.parse_args() | |||
if not args.read and not args.write and not args.sub: | ||||
args.read = True | ||||
if args.raw or (args.cmd not in subcmds): | if args.raw or (args.cmd not in subcmds): | |||
func = subcmd_default | func = subcmd_default | |||
else: | else: | |||
func = subcmds[args.cmd]['func'] | func = subcmds[args.cmd]['func'] | |||
rpc = JsonUDP(args.mgmtport) | rpc = JsonUDP(args.mgmtport) | |||
rpc.debug = args.debug | rpc.debug = args.debug | |||
rpc.key = args.key | rpc.key = args.key | |||
try: | try: | |||
End of changes. 11 change blocks. | ||||
20 lines changed or deleted | 68 lines changed or added |