#!/usr/bin/env python3 '''httpd component of routerstats''' import logging from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer import sys import os from functools import partial import argparse import configparser import rrdtool logging.basicConfig( format='%(asctime)s %(funcName)20s %(levelname)-8s %(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S') class RequestHandler(SimpleHTTPRequestHandler): '''Extended SimpleHTTPRequestHandler''' def serve_png(self): '''Give a client a png file''' self.send_response(200) self.send_header('Content-type', 'image/png') self.end_headers() tmp_queries = self.path.split('/') query = [] for q in tmp_queries: if q: query.append(q) logging.debug(str(query)) retries = 0 while True: try: if len(query) > 1: if query[1] == 'yearly': title = query[1] startstr = '--start=end-1Y' elif query[1] == 'monthly': title = query[1] startstr = '--start=end-1M' elif query[1] == 'weekly': title = query[1] startstr = '--start=end-1W' elif query[1] == 'daily': title = query[1] startstr = '--start=end-1d' else: title = 'monthly' startstr = '--start=end-1M' else: title = 'monthly' startstr = '--start=end-1M' data = rrdtool.graphv( "-", startstr, "--title=" + title, "DEF:in=" + self.rrdfile + ":net_dnat:AVERAGE", #pylint: disable=no-member "DEF:out=" + self.rrdfile + ":loc-net:AVERAGE", #pylint: disable=no-member "CDEF:result_in=in,UN,0,in,IF", "CDEF:tmp_out=out,UN,0,out,IF", "CDEF:result_out=tmp_out,-1,*", "AREA:result_in#00ff00:in", "AREA:result_out#0000ff:out") #, "--width", "1024", "--height", "600" self.wfile.write(data['image']) break except rrdtool.OperationalError as error: retries += 1 if retries > 10: logging.error('Could not graphv the data: %s', error) break def errorpage(self, errorcode, errormsg: str = ''): '''Give client an errorpage''' self.send_response(errorcode) self.send_header('Content-type', 'text/plain') self.end_headers() if errormsg: self.wfile.write(errormsg.encode('utf-8')) def do_GET(self): '''Reply to a GET request''' if self.path == '/': self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.print_page() elif self.path.startswith('/graph'): self.serve_png() elif self.path == '/favicon.ico': self.send_error(404) else: self.send_error(404, str(self.path)) def print_page(self): '''Print pretty html page''' self.wfile.write("".encode('utf-8')) self.wfile.write(''.encode('utf-8')) self.wfile.write(''.encode('utf-8')) self.wfile.write(''.encode('utf-8')) self.wfile.write("".encode('utf-8')) class CustomHandler(RequestHandler): '''wrapping the wrapped one, so we can wrap in an init''' def __init__(self, rrdfile, *args, **kwargs): self.rrdfile = rrdfile super().__init__(*args, **kwargs) def server(rrdfile, port): '''Start server''' server_address = ('', port) server_class = ThreadingHTTPServer handler_class = partial(CustomHandler, rrdfile) httpd = server_class(server_address, handler_class) httpd.serve_forever() def main(): '''This be main''' config_section = 'httpd' config = configparser.ConfigParser() parser = argparse.ArgumentParser(exit_on_error=False, add_help=False) parser.add_argument('-c', '--config', help='config file to load') parser.add_argument('-d', '--debug', action='store_true', help='enable debug') args, _ = parser.parse_known_args() if args.debug: logging.root.setLevel(logging.DEBUG) logging.debug('Starting as PID %s', os.getpid()) found = False config_dirs = ('/etc/routerstats/', '/usr/local/etc/routerstats/', '/opt/routerstats/', './') if args.config: if os.path.isfile(args.config): config.read(args.config) found = True else: logging.error('Specified config file does not exist: %s', args.config) else: logging.debug('Trying to find config') #Try to find in "usual" places for directory in config_dirs: trytoread = directory + 'routerstats.config' if os.path.isfile(trytoread): logging.debug('Reading config file %s', trytoread) config.read(trytoread) found = True if not found: logging.error('routerstats.config not found in %s', config_dirs) sys.exit(0) parser.add_argument( '-v', '--vardir', help='directory storing rrd file', default=config[config_section]['var_dir']) parser.add_argument( '-p', '--port', help='port to bind to', type=int, default=config[config_section]['port']) parser.add_argument( '-h', '--help', help='show this help and exit', action='store_true', default=False) args = parser.parse_args() logging.debug(args) if args.help: parser.print_help() sys.exit() if not os.path.isfile(args.vardir + 'routerstats.rrd'): logging.error('Cannot find rrd file %s', args.vardir + 'routerstats.rrd' ) sys.exit() server(rrdfile=args.vardir + 'routerstats.rrd', port=args.port) if __name__ == '__main__': logging.debug('Welcome') main()