#!/usr/bin/env python3 import sys from pathlib import Path from configparser import ConfigParser from socket import gethostbyname, create_connection cfgdir = Path(__file__).resolve().parent / 'cfg' def check_connection(host, port=22): try: addr = gethostbyname(host) test_socket = create_connection((addr, port), timeout=0.1) except Exception as e: if isinstance(e, TimeoutError): return '', addr return '', '' else: test_socket.close() return '*', addr def print_row(row, sizes): print(' '.join(v.ljust(l) for v, l in zip(row, sizes))) def print_line(sizes): print(' '.join('-' * l for l in sizes)) legend = ['', '', '', '* running', '* online'] opt = sys.argv[-1] if opt.startswith('-'): opt = opt[1:] header = ['box name', 'box type', 'V', 'frappy'] if opt == 's': header.append('') legend = [] else: header.append('ip ') if opt == 'a': header.extend(['router', 'MAC addr']) else: header.append('') legend = legend[:5] table = [header] all_ports = {} for file in sorted(cfgdir.glob('*.cfg')): name = file.stem all_ports[name] = box_ports = {} parser = ConfigParser() parser.read(file) info = {k: dict(parser[k]) for k in parser.sections()} router = info.get('ROUTER', {}) if opt == 'a': ports = sorted(router) router = [] following = None firstport = None for p in ports: try: pnum = int(p) if 'router' not in box_ports: box_ports['router'] = pnum if pnum == following: first = router[-1].split('-')[0] router[-1] = f'{first}-{following}' following += 1 continue following = pnum + 1 except ValueError: pnum = -1 router.append(p) router = ' '.join(router) else: router = 'router' if router else '' frappy_info = info.get('FRAPPY', {}) frappy = frappy_info.get('cfg', '') if frappy: box_ports['frappy'] = int(frappy_info.get('port', 10767)) box = info.get('BOX', {}) row = [name, box.get('type', 'unknown'), box.get('version', '0'), frappy] if opt == 's': row.append(router) else: row.extend(['', router]) if opt == 'a': row.append(box.get('mac', '')) table.append(row) sizes = [max([len(row[i]) for row in table]) for i in range(len(header))] if opt != 's': # make space for '*' sizes[3] += 1 sizes[4] += 1 firstrow = True print_line(sizes) for row in table: if firstrow: firstrow = False print_row(header, sizes) print_line(sizes) continue if row[0]: name = row[0] online = '' if opt != 's': online, addr = check_connection(row[0], 22) addr += online if opt != 'a' and online != '*': continue row[4] = addr if opt != 's': port = all_ports[name].get('frappy') if port and online == '*': flag = check_connection(name, port)[0] else: flag = ' ' row[3] += flag print(' '.join(v.ljust(l) for v, l in zip(row, sizes))) print_line(sizes) if legend: print_row(legend, sizes) print('V 0: not yet migrated to gitea') print('V 1: 2025-05') USAGE = f""" Usage: listboxes o # only boxes online (default) listboxes a # all boxes, all info listboxes s # without ip and online check """ if opt not in 'sao': print(USAGE)