#!/usr/bin/python3 """Serve diagnostics of the router's first setup on PORT, with the Python standard library alone. Run by vpn-router-bootstrap.service, which vpn-router-setup starts until a setup has succeeded and then stops. Every request on any address answers, as plain text, the output of COMMANDS run at that moment: the state of the last setup run, the state of the services, the addresses, and the end of the logs. """ import subprocess from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer PORT = 17081 #: The title of each section and its command. COMMANDS = ( ('Setup state', ['cat', '/run/vpn-router/setup.json']), ('Services', ['systemctl', 'is-active', 'vpn-router-setup', 'vpn-router-web', 'slapd', 'postgresql', 'strongswan', 'openvpn-server@vpn-router', 'wg-quick@wg0']), ('Failed units', ['systemctl', '--failed', '--no-legend', '--plain']), ('Addresses', ['ip', '-brief', 'address']), ('Routes', ['ip', 'route']), ('cloud-init', ['cloud-init', 'status', '--long']), ('vpn-router-setup log', ['journalctl', '--unit', 'vpn-router-setup', '--lines', '60', '--no-pager', '--output', 'short-iso']), ('vpn-router-web log', ['journalctl', '--unit', 'vpn-router-web', '--lines', '30', '--no-pager', '--output', 'short-iso']), ) def report(): """The output of every command of COMMANDS under its title.""" sections = [] for title, command in COMMANDS: try: result = subprocess.run(command, capture_output=True, text=True, timeout=10) text = (result.stdout + result.stderr).rstrip() except (OSError, subprocess.TimeoutExpired) as exc: text = f'cannot run {command[0]}: {exc}' sections.append(f'== {title} ==\n{text}\n') return '\n'.join(sections) class Handler(BaseHTTPRequestHandler): def do_GET(self): body = report().encode() self.send_response(200) self.send_header('Content-Type', 'text/plain; charset=utf-8') self.send_header('Content-Length', str(len(body))) self.send_header('Cache-Control', 'no-store') self.send_header('Refresh', '10') self.end_headers() self.wfile.write(body) if __name__ == '__main__': ThreadingHTTPServer(('', PORT), Handler).serve_forever()