sean@4: """ sean@4: This software is part of "Bottledash" sean@4: author: sean engelhardt > sean.engelhardt@intevation.de sean@4: license: GNU >= V2. See LICENSE for details sean@4: """ sean@4: sean@3: from bottle import get, post, request, view, response, route sean@3: from bottle import template, run, static_file, error sean@19: import os.path, sys, configparser, functools, bottle sean@19: import logging sean@0: sean@3: CONFIG_FILE = "dash.conf" sean@8: PATH = os.path.abspath(os.path.dirname(sys.argv[0])) sean@8: CONFIG_PATH = PATH + "/" + CONFIG_FILE sean@8: sean@9: # Create a new list with absolute paths sean@9: MY_TEMPLATE_PATH = [ sean@10: os.path.abspath(os.path.join(os.path.dirname(__file__), './views')), sean@9: ] sean@9: sean@9: # Patch @view() so it uses the customized path list instead of the global one sean@9: view = functools.partial(bottle.view, template_lookup=MY_TEMPLATE_PATH) sean@9: sean@3: tiles = [] sean@7: settings = {} sean@3: sean@7: default_settings = configparser.ConfigParser() sean@19: default_settings['settings'] = {'show_top_bar': False, 'rows': 2} sean@19: sean@19: #logging: sean@19: sean@19: logger = logging.getLogger('myapp') sean@19: hdlr = logging.FileHandler(PATH + '/bottledash.log') sean@19: formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') sean@19: hdlr.setFormatter(formatter) sean@19: logger.addHandler(hdlr) sean@19: logger.setLevel(logging.INFO) sean@7: sean@20: ### debug function: prints the current status of the "tiles" in sean@20: ### the log-file sean@20: def log_tile_status(): sean@20: global tiles sean@20: sean@20: try: sean@20: for tile in tiles: sean@20: logger.info("found tile : " + str(tile)) sean@20: for option in tiles[0]: sean@20: logger.info(str(option) + ' : ' + str(tile[option])) sean@20: except KeyError: sean@20: pass sean@20: sean@20: ###read the config file. usually "dash.conf" sean@3: def read_config(): sean@20: global settings sean@8: # print(PATH) sean@3: sean@8: if os.path.isfile(CONFIG_PATH) == False: sean@3: write_default_config() sean@3: sean@20: # print("read existing config file...") sean@3: config = configparser.ConfigParser() sean@8: config.read(CONFIG_PATH) sean@3: sean@3: for section in config.items(): sean@3: if "tile" in section[0]: sean@3: tiles.append(section[1]) sean@3: sean@20: ###log read tiles sean@20: logger.info("------- read tiles --------") sean@20: log_tile_status() sean@20: sean@7: try: sean@7: if config["settings"]: sean@7: settings = config["settings"] sean@7: else: sean@7: settings = default_settings["settings"] sean@7: except KeyError: sean@7: settings = default_settings["settings"] sean@7: sean@7: ###write the default condfig file if there is none sean@3: def write_default_config(): sean@8: print("there is no Config file! Creating one...") sean@8: file = open(CONFIG_PATH, "w") sean@3: file.write(""" sean@3: ### bottledash default configuration sean@3: ### created by sean engelhardt >sean.engelhardt@intevation.de sean@7: ### license: GNU GPL >= v2. See LICENSE for details sean@3: ### sean@3: ### Usage: sean@3: ### define the tiles for the dashboard in sections sean@7: sean@7: # Settings: sean@7: # example: sean@7: # -------------------- sean@7: # [settings] sean@7: # show_top_bar=True sean@7: # -------------------- sean@7: # options: sean@7: # show_top_bar (True / False) [optional] sean@7: # If True, the dashboard will show the current date and the time on the top sean@7: # if False, the dashboard will not show a top-bar sean@7: # default: True sean@7: # hint: the top-bar has got a height of 5%! sean@7: sean@7: [settings] sean@14: show_top_bar=False sean@7: sean@7: # Tiles: sean@7: # example: sean@7: # -------------------- sean@7: # [tile1] sean@7: # type=mon sean@7: # source=192.168.0.2 sean@7: # status=up sean@7: # -------------------- sean@7: # options: sean@7: # type (mon / d3js) [required] sean@7: # tells the program what kind of tile you need. sean@7: # a "mon" tile can be used for IT infrastructure monitoring purposes sean@7: # a d3js tile can be used to display a chart sean@7: # default: - sean@7: # sean@7: # source ( or ) [required for mon-types] sean@7: # ONLY FOR MON-Type tiles! sean@7: # tells the tile which resource to watch sean@7: # default: none sean@7: # sean@7: # status: (up / down) [required] sean@7: # ONLY FOR DEBUGGING PURPOSE - WILL BE REMOVED LATER sean@7: # simulates up and down events for mon-type-tiles sean@14: # sean@14: # div_name: (identifier) [required for d3js-types] sean@14: # sean@14: # script: (name of a script without extension) [required for d3js-types0] sean@14: # sean@3: [tile1] sean@3: type=mon sean@3: source=192.168.0.2 sean@14: status=down sean@3: sean@3: [tile2] sean@3: type=mon sean@7: source=192.168.2.3 sean@14: status=up sean@7: sean@7: [tile3] sean@7: type=mon sean@7: source=192.168.4.3 sean@3: status=up sean@7: sean@7: [tile4] sean@14: type=d3js sean@14: div_name=techintern sean@14: script=display_issues_techintern sean@3: """) sean@3: file.close() sean@3: sean@3: ##Bottle sean@0: @route('/') sean@15: @view('bottledash_view') sean@0: def call_dashboard(): sean@7: return dict(tiles=tiles, settings=settings) sean@0: sean@20: #wait for post-request which shall inform the system about running services sean@19: @post('/updown') sean@19: def updown(): sean@20: global tiles sean@20: sean@19: service = request.forms.get('service') sean@19: status = request.forms.get('status') sean@20: try: sean@20: for tile in tiles: sean@20: if tile["source"] == str(service): sean@20: tile["status"] = str(status) sean@20: except KeyError: sean@21: logger.info("this tile got no source : " + str(tile)) sean@20: sean@19: sean@19: logger.info('------- new alert --------') sean@19: logger.info('Service : ' + str(service)) sean@19: logger.info('Status : ' + str(status)) sean@24: # log_tile_status() sean@19: sean@20: return "thanks for informing bottledash! :: " + str(service) + " is " + str(status) + " !" sean@0: sean@21: sean@21: @post('/ask-systemstate') sean@21: def get_systemstate(): sean@21: global tiles sean@21: service = request.forms.get('service') sean@21: sean@21: print("service: " + service) sean@21: sean@21: try: sean@21: for tile in tiles: sean@21: if tile["source"] == str(service): sean@21: # return "service : " + str(service) + " is " + str(tile["status"]) sean@21: return tile["status"] sean@21: except KeyError: sean@21: return "cannot find the service: " + str(service) sean@21: sean@21: return "did not found anything in my list for : " + service sean@21: sean@21: sean@21: @route('/static/') sean@21: def server_static(filename): sean@21: return static_file(filename, root=PATH + '/static/') sean@21: sean@0: @error(404) sean@0: def error404(error): sean@0: return 'Nothing here, sorry
404' sean@0: sean@3: read_config() sean@7: # print(tiles) sean@9: run(host='localhost', port=8080, debug=True)