X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=systems%2Fmonitoring-1%2Fstatus%2Fapp.py;h=ff928914c6d681f15769ea81dd2cfbd95b59b662;hb=1a64deeb894dc95e2645a75771732c6cc53a79ad;hpb=fa25ffd4583cc362075cd5e1b4130f33306103f0;p=perso%2FImmae%2FConfig%2FNix.git diff --git a/systems/monitoring-1/status/app.py b/systems/monitoring-1/status/app.py new file mode 100755 index 0000000..ff92891 --- /dev/null +++ b/systems/monitoring-1/status/app.py @@ -0,0 +1,414 @@ +from flask import Flask, request, render_template_string, jsonify, make_response +from flask_login import LoginManager, UserMixin, login_required +import socket +import json +import time +import os + +login_manager = LoginManager() +app = Flask(__name__) +login_manager.init_app(app) + +STATUS = [ + "ok", + "warning", + "error", + "unknown" + ] + +HOST_STATUS = [ + "up", + "down", + "unreachable", + ] + +#### Push +AUTHORIZED_KEYS = os.environ.get("TOKENS", "").split() +COMMAND_FILE = "/var/run/naemon/naemon.cmd" + +ERROR_NO_REQUEST_HANDLER="NO REQUEST HANDLER" +ERROR_NO_TOKEN_SUPPLIED="NO TOKEN" +ERROR_BAD_TOKEN_SUPPLIED="BAD TOKEN" + +ERROR_BAD_COMMAND_FILE="BAD COMMAND FILE" +ERROR_COMMAND_FILE_OPEN_WRITE="COMMAND FILE UNWRITEABLE" +ERROR_COMMAND_FILE_OPEN="CANNOT OPEN COMMAND FILE" +ERROR_BAD_WRITE="WRITE ERROR" + +ERROR_BAD_DATA="BAD DATA" +ERROR_BAD_JSON="BAD JSON" + +ERROR_NO_CORRECT_STATUS="NO STATUS WAS CORRECT" +#### /Push + +def get_lq(request): + # https://mathias-kettner.de/checkmk_livestatus.html + socket_path="/var/run/naemon/live" + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.connect(socket_path) + s.send(request.encode()) + s.shutdown(socket.SHUT_WR) + chunks = [] + while len(chunks) == 0 or len(chunks[-1]) > 0: + chunks.append(s.recv(4096)) + s.close() + return b"".join(chunks).decode() + +class Host: + def __init__(self, name, alias, status, webname, vhost): + self.name = name + self.alias = alias + self.webname = webname or alias + self.vhost = vhost + self.status = status + self.services = [] + + @classmethod + def parse_hosts(cls, payload, vhost): + parsed = filter(lambda x: x.vhost == vhost, [cls.parse(p) for p in json.loads(payload)]) + return {p.name: p for p in parsed} + + @classmethod + def parse(cls, payload): + return cls(payload[0], payload[1], HOST_STATUS[payload[2]], payload[3].get("WEBSTATUS_NAME"), payload[3].get("WEBSTATUS_VHOST")) + + def __repr__(self): + return "Host {}: {} ({})".format(self.name, self.alias, self.webname) + + @classmethod + def query(cls, vhost): + answer = get_lq("""GET hosts +Filter: groups >= webstatus-hosts +Columns: name alias state custom_variables +OutputFormat: json +""") + return cls.parse_hosts(answer, vhost) + + def fill_services(self, services): + self.services = [service for service in services if service.host == self.name] + +class ServiceGroup: + def __init__(self, name, alias): + self.name = name + self.alias = alias + self.services = [] + + @classmethod + def parse_groups(cls, payload): + parsed = [cls.parse(p) for p in json.loads(payload)] + return {p.name: p for p in parsed} + + @classmethod + def parse(cls, payload): + return cls(payload[0], payload[1]) + + @classmethod + def query(cls): + answer = get_lq("""GET servicegroups +Filter: name ~ ^webstatus- +Columns: name alias custom_variables +OutputFormat: json +""") + return cls.parse_groups(answer) + + def fill_services(self, services, hosts): + self.services = [service for service in services if any([group == self.name for group in service.groups]) and service.host in hosts] + + def __repr__(self): + return "ServiceGroup {}: {}".format(self.name, self.alias) + +class Service: + def __init__(self, name, host, groups, status, webname, url, description, infos): + self.name = name + self.host = host + self.groups = groups + self.status = status + self.webname = webname + self.url = url + self.description = description + self.infos = infos + + @classmethod + def parse_services(cls, payload): + parsed = json.loads(payload) + return [cls.parse(p) for p in parsed if cls.valid(p[2])] + + @staticmethod + def valid(groups): + return any([b.startswith("webstatus-") for b in groups]) + + @classmethod + def parse(cls, payload): + return cls(payload[0], + payload[1], + payload[2], + STATUS[payload[3]], + payload[4].get("WEBSTATUS_NAME"), + payload[4].get("WEBSTATUS_URL"), + payload[5], + payload[6]) + + @classmethod + def query(cls): + answer = get_lq("""GET services +Columns: display_name host_name groups state custom_variables description plugin_output +OutputFormat: json +""") + return cls.parse_services(answer) + + def __repr__(self): + return "Service {}: {}".format(self.name, self.webname) + +def get_infos(vhost): + hosts = Host.query(vhost) + servicegroups = ServiceGroup.query() + services = Service.query() + + for host in hosts: + hosts[host].fill_services(services) + for group in servicegroups: + servicegroups[group].fill_services(services, hosts) + return (hosts, servicegroups, services) + +TEMPLATE=''' + + +
+ + +