194 lines
5.2 KiB
Python
Executable File
194 lines
5.2 KiB
Python
Executable File
#!/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("<html><body>".encode('utf-8'))
|
|
self.wfile.write('<img src="/graph/monthly">'.encode('utf-8'))
|
|
self.wfile.write('<img src="/graph/weekly">'.encode('utf-8'))
|
|
self.wfile.write('<img src="/graph/daily">'.encode('utf-8'))
|
|
self.wfile.write("</body></html>".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()
|