diff --git a/requirements.txt b/requirements.txt
index 578254a..724e329 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,17 @@
-aiohttp==3.5.4
+aiohttp==3.6.3
+aiohttp-jinja2==1.5
+aiosignal==1.3.1
async-timeout==3.0.1
attrs==20.3.0
+cachetools==5.2.1
chardet==3.0.4
+charset-normalizer==2.1.1
+frozenlist==1.3.3
idna==2.10
idna-ssl==1.1.0
+Jinja2==3.1.2
+MarkupSafe==2.1.1
multidict==4.7.6
typing-extensions==3.7.4.3
-yarl==1.6.3
+yarl==1.5.1
zabbix-api==0.5.5
diff --git a/settings.py b/settings.py
new file mode 100644
index 0000000..ab08f86
--- /dev/null
+++ b/settings.py
@@ -0,0 +1,13 @@
+ZABBIX_API = 'http://127.0.0.1:8080'
+ZABBIX_URL = 'https://zabbix.internal'
+ZABBIX_LOGIN = 'Admin'
+ZABBIX_PASS = 'admin'
+LIMIT = 3000
+HOSTGROUP = "Zabbix*"
+SEVERITY = 3
+TIMEOUT = 20
+PORT = 8080
+ZABBIX_SERVERS_CHECK = ['127.0.0.1:10051']
+COLOR_TEAM = {
+"Zabbix servers": "#04B404"
+}
diff --git a/super-server-v2.py b/super-server-v2.py
deleted file mode 100644
index ce5972e..0000000
--- a/super-server-v2.py
+++ /dev/null
@@ -1,328 +0,0 @@
-import aiohttp_jinja2
-import jinja2
-import aiohttp
-import settings
-import time
-import datetime
-import logging
-import sys
-import random
-import os
-import json
-import asyncio
-import socket
-from aiohttp import web
-from zabbix_api import ZabbixAPI
-
-stdio_handler = logging.StreamHandler()
-stdio_handler.setLevel(logging.INFO)
-_logger = logging.getLogger('aiohttp.access')
-_logger.addHandler(stdio_handler)
-_logger.setLevel(logging.INFO)
-
-def convert_seconds(seconds):
- time = "a few sec"
- if seconds >= 60:
- time = str(round(seconds / 60)) + " min"
- if seconds > 3600:
- if round(seconds / 3600) == 1:
- time = "an hour"
- else:
- time = str(round(seconds / 3600)) + " hours"
- if seconds >= 86400:
- if round(seconds / 86400) == 1:
- time = "a day"
- else:
- time = str(round(seconds / 86400)) + " days"
- if seconds >= 2629746:
- if round(seconds / 2629746) == 1:
- time = "a month"
- else:
- time = str(round(seconds / 2629746)) + " months"
- if seconds >= 31536000:
- if round(seconds / 31536000) == 1:
- time = "a year"
- else:
- time = str(round(seconds / 31536000)) + " years"
- return time
-
-def zabbix_login():
- global zapi
- x = 0
-
- while x < 10:
- try:
- zapi = ZabbixAPI(server=settings.ZABBIX_API, timeout=int(settings.TIMEOUT))
- zapi.login(settings.ZABBIX_LOGIN, settings.ZABBIX_PASS)
- except Exception as e:
- x+=1
- _logger.error("[ERR] - {} Retry #{}: {}".format(datetime.datetime.now(), x, e))
- time.sleep(x)
- continue
- break
- if x >= 10:
- sys.exit("Can't connect to Zabbix API.")
-
-def zabbix_call(request, method):
- global zapi
- x = 0
-
- while x < 10:
- try:
- if method == 'hostgroup':
- resp = zapi.hostgroup.get(request)
- elif method == 'triggers':
- resp = zapi.trigger.get(request)
- except Exception as e:
- x+=1
- _logger.error("[ERR] - {} Retry #{}: {}".format(datetime.datetime.now(), x, e))
- time.sleep(x)
- continue
- break
- if x >= 10:
- sys.exit("Can't perform calls to Zabbix API.")
- else:
- return resp
-
-def read_file(file_to_update):
- if os.path.exists(file_to_update):
- with open(file_to_update, 'r') as f:
- out = json.load(f)
- f.close()
- return out
- return False
-
-def write_file(notes, file_to_update):
- with open(file_to_update, 'w+') as f:
- json.dump(notes, f)
- f.close()
-
-def display_notes(request):
- note_list = []
- notes = read_file('./data/motd.json')
- teams = request.match_info.get('teams')
- if notes:
- for ts in notes:
- for note in notes[ts]:
- if note['team'] in teams or note['team'] == 'all':
- date_note = datetime.datetime.utcfromtimestamp(int(ts)).strftime('%Y-%m-%d %H:%M:%S')
- note_list.append({"lvl": note["lvl"], "date": date_note, "msg": note['msg'], "name": note['name'], "ts": ts })
- return note_list
-
-def get_hostgroup_color(hostgroup):
- if hostgroup not in settings.COLOR_TEAM:
- color = "#%06x;" % random.randint(0, 0xFFFFFF)
- settings.COLOR_TEAM[hostgroup] = color
- else:
- color = settings.COLOR_TEAM[hostgroup]
- return color
-
-def get_hostgroups():
- groups = []
-
- for hg in settings.HOSTGROUP:
- request = dict()
- request['output'] = 'extend'
- request['search'] = dict()
- request['search']['name'] = hg
- request['searchWildcardsEnabled'] = 1
- resp = zabbix_call(request, 'hostgroup')
- for x in range(len(resp)):
- groups.append(resp[x]['name'])
- return groups
-
-def get_ttl_hash(seconds=30):
- return round(time.time() / seconds)
-
-### CACHE
-def get_problems(request, ttl_hash = None):
- del ttl_hash
- problems = []
- limit = settings.LIMIT
- groups = [group.lower() for group in get_hostgroups()]
- try:
- zapi.logged_in()
- except Exception as e:
- _logger.info('[INFO] - {}: Connection to Zabbix API'.format(datetime.datetime.now()))
- zabbix_login()
-
- team_list = settings.HOSTGROUP
-
- groupids = []
- for hg in team_list:
- request = dict()
- request['output'] = 'extend'
- request['search'] = dict()
- request['search']['name'] = hg
- request['searchWildcardsEnabled'] = 1
- resp = zabbix_call(request, 'hostgroup')
- for x in range(len(resp)):
- groupids.append(int(resp[x]['groupid']))
-
- request = dict()
- request['limit'] = limit
- request['groupids'] = groupids
- request['monitored'] = 1
- request['maintenance'] = 0
- request['active'] = 1
- request['min_severity'] = settings.SEVERITY
- request['output'] = "extend"
- request['expandData'] = 1
- request['selectHosts'] = "extend"
- request['selectGroups'] = "extend"
- request['expandDescription'] = 1
- request['only_true'] = 1
- request['skipDependent'] = 1
- request['withUnacknowledgedEvents'] = 1
- request['withLastEventUnacknowledged'] = 1
- request['selectTags'] = "extend"
- request['filter'] = dict()
- request['filter']['value'] = 1
- request['sortfield'] = ["priority","lastchange"]
- request['sortorder'] = ["DESC"]
-
- resp = zabbix_call(request, 'triggers')
- for x in range(len(resp)):
- data = resp[x]
- if len(data['hosts']) > 0:
- # Loop on problems
- for z in range(len(data['groups'])):
- if int(data['groups'][z]['groupid']) in groupids:
- hostgroup = data['groups'][z]['name']
- color = get_hostgroup_color(hostgroup)
- since = convert_seconds(int(time.time()) - int(data['lastchange']))
- problems.append({'description': data['description'], 'host': data['hosts'][0]['host'], 'priority': data['priority'], 'triggerid': data['triggerid'], 'since': since, 'hostgroup': hostgroup, 'color': color, 'lastchange': data['lastchange']})
- for y in range(len(data['tags'])):
- tag_value = data['tags'][y]['value']
- if tag_value.lower() in groups:
- color = get_hostgroup_color(tag_value)
- since = convert_seconds(int(time.time()) - int(data['lastchange']))
- problems.append({'description': data['description'], 'host': data['hosts'][0]['host'], 'priority': data['priority'], 'triggerid': data['triggerid'], 'since': since, 'hostgroup': tag_value, 'color': color, 'lastchange': data['lastchange']})
- _logger.info('[INFO] - {}: Refresh...'.format(datetime.datetime.now()))
- return problems
-
-async def post_note(request):
- data = await request.post()
- msg = data['msg']
- team = data['team']
- name = data['name']
- url = data['url']
- lvl = data['lvl']
- ts = int(time.time())
-
- j = {}
- j[ts] = []
- j[ts].append({
- 'team': team,
- 'name': name,
- 'msg': msg,
- 'lvl': lvl
- })
-
- if os.path.exists('./data/motd.json'):
- out = read_file('./data/motd.json')
- out.update(j)
- write_file(out, './data/motd.json')
- else:
- write_file(j, './data/motd.json')
- _logger.info("[ADD] - {}".format(j))
- return aiohttp.web.HTTPFound(location=url, text='{}'.format(ts), content_type='text/html')
-
-async def del_note(request):
- data = await request.post()
- note_id = data['note_id']
- url = data['url']
- out = read_file('./data/motd.json')
- _logger.info('[DEL] - {}'.format(out[note_id]))
- del out[note_id]
- write_file(out, './data/motd.json')
- return aiohttp.web.HTTPFound(location=url)
-
-async def check_servers():
- while True:
- _logger.info('[INFO] - Checking Zabbix Servers: {}'.format(settings.ZABBIX_SERVERS_CHECK))
- j = {}
- for ip in settings.ZABBIX_SERVERS_CHECK:
- port = 10051
- if ':' in ip:
- i = ip.split(':')
- ip = i[0]
- port = int(i[1].strip())
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.settimeout(5)
- result = sock.connect_ex((ip, port))
- if result == 0:
- _logger.info("[INFO] - Port {} OK: {}".format(port, ip))
- else:
- _logger.error("[ERR] - Port {} KO: {}".format(port, ip))
- j[ip] = result
- sock.close()
- if os.path.exists('./data/zabbix-servers.json'):
- out = read_file('./data/zabbix-servers.json')
- out.update(j)
- write_file(out, './data/zabbix-servers.json')
- else:
- write_file(j, './data/zabbix-servers.json')
- await asyncio.sleep(60)
-
-async def start_background_tasks(app):
- app['dispatch'] = app.loop.create_task(check_servers())
-
-async def cleanup_background_tasks(app):
- app['dispatch'].cancel()
- await app['dispatch']
-
-@aiohttp_jinja2.template('index.html')
-def display_alerts(request):
-
- url = str(request.url)
- if '/tv/' in url:
- tv_mode = True
- else:
- tv_mode = False
-
- teams = request.match_info.get('teams')
- try:
- zapi.logged_in()
- except Exception as e:
- _logger.info('[INFO] - {}: Connection to Zabbix API'.format(datetime.datetime.now()))
- zabbix_login()
-
- if teams:
- team_list = teams.lower().split('+')
-
- check_servers = read_file('./data/zabbix-servers.json')
- notes = display_notes(request)
- problems = get_problems(request, ttl_hash=get_ttl_hash())
- _logger.info(len(problems))
- problems = [problem for problem in problems if problem.get('hostgroup').lower() in team_list]
- problems = sorted(problems,
- key = lambda i: (i['priority'], i['lastchange']),
- reverse=True)
- _logger.info('[NB ALERTS] - {}'.format(len(problems)))
- context = {'alerts': problems, 'total_alerts': len(problems), 'zabbix_url': settings.ZABBIX_URL, "hostgroups": get_hostgroups(), "notes": notes, "tv_mode": tv_mode, "check_servers": check_servers}
- return aiohttp_jinja2.render_template(
- 'index.html', request, context)
-
-def main():
- app = web.Application()
- aiohttp_jinja2.setup(app,
- loader=jinja2.FileSystemLoader('templates'))
-
- app.add_routes([
- web.get('/', display_alerts),
- web.get('/{teams}', display_alerts),
- web.get('/tv/{teams}', display_alerts),
- aiohttp.web.post('/post', post_note),
- aiohttp.web.post('/del', del_note),
- aiohttp.web.static('/images', 'images'),
- aiohttp.web.static('/css', 'css'),
- aiohttp.web.static('/js', 'js')
- ])
-
- app.on_startup.append(start_background_tasks)
- app.on_cleanup.append(cleanup_background_tasks)
- aiohttp.web.run_app(app, port=settings.PORT)
-
-if __name__ == '__main__':
- main()
\ No newline at end of file
diff --git a/super-server.py b/super-server.py
index 6afdf34..73f8c02 100644
--- a/super-server.py
+++ b/super-server.py
@@ -1,65 +1,25 @@
-from zabbix_api import ZabbixAPI
-from os import path
-
-import asyncio
-import json
-import operator
+import aiohttp_jinja2
+import jinja2
import aiohttp
-import aiohttp.web
-import json
+import settings
import time
import datetime
import logging
import sys
-import os.path
import random
-import argparse
-import re
-import config
+import os
+import json
+import asyncio
import socket
-
+from aiohttp import web
+from zabbix_api import ZabbixAPI
+from functools import lru_cache
stdio_handler = logging.StreamHandler()
stdio_handler.setLevel(logging.INFO)
_logger = logging.getLogger('aiohttp.access')
_logger.addHandler(stdio_handler)
-_logger.setLevel(logging.DEBUG)
-
-parser = argparse.ArgumentParser()
-parser.add_argument("--zabbix_ip", help="Zabbix Frontend IP.", required=True)
-parser.add_argument("--zabbix_url", help="Zabbix URL. Used to build triggers URL.", required=True)
-parser.add_argument("--alert_limit", help="Number of alerts to retrieve.", required=True)
-parser.add_argument("--zabbix_hostgroup", help="Search for hostgroups which correspond to this parameter (Wildcard allowed).", required=True)
-parser.add_argument("--zabbix_min_severity", help="Minimum trigger severity to retrieve.", required=True)
-parser.add_argument("--zabbix_login", help="Login to connect to the Zabbix API.", required=True)
-parser.add_argument("--zabbix_pass", help="Password to connect to the Zabbix API.", required=True)
-parser.add_argument("--list_zabbix_servers", help="List of Zabbix Servers to check", required=True, nargs="+")
-parser.add_argument("--zabbix_timeout", help="Timeout to the API.", required=True, type=int)
-parser.add_argument("--port", help="Listen Port.", required=True)
-
-args = parser.parse_args()
-
-ZABBIX_API = 'http://'+args.zabbix_ip
-ZABBIX_FRONTEND = args.zabbix_url + '/'
-ZABBIX_LOGIN = args.zabbix_login
-ZABBIX_PASS = args.zabbix_pass
-LIMIT = args.alert_limit
-HOSTGROUP = args.zabbix_hostgroup
-SEVERITY = args.zabbix_min_severity
-TIMEOUT = args.zabbix_timeout
-PORT = args.port
-ZABBIX_SERVERS_CHECK = args.list_zabbix_servers
-
-_logger.info('\n[ENVIRONMENT VARIABLES]\n[ZABBIX API] - {}'.format(ZABBIX_API))
-_logger.info('[ZABBIX FRONTEND] - {}'.format(ZABBIX_FRONTEND))
-_logger.info('[ALERT LIMIT] - {}'.format(LIMIT))
-_logger.info('[HOSTGROUP] - {}'.format(HOSTGROUP))
-_logger.info('[MIN SEVERITY] - {}'.format(SEVERITY))
-_logger.info('[TIMEOUT] - {}'.format(TIMEOUT))
-_logger.info('[PORT] - {}'.format(PORT))
-_logger.info('[ZABBIX SERVERS TO CHECK] - {}\n'.format(ZABBIX_SERVERS_CHECK))
-
-zapi = None
+_logger.setLevel(logging.INFO)
def convert_seconds(seconds):
time = "a few sec"
@@ -87,92 +47,160 @@ def convert_seconds(seconds):
time = str(round(seconds / 31536000)) + " years"
return time
-def severity_badge(severity):
- if severity == 5:
- badge = ' '
- elif severity == 4:
- badge = '4'
- elif severity == 3:
- badge = '3'
- elif severity == 2:
- badge = '2'
- elif severity == 1:
- badge = '1'
+def zabbix_login():
+ global zapi
+ x = 0
+
+ while x < 10:
+ try:
+ zapi = ZabbixAPI(server=settings.ZABBIX_API, timeout=int(settings.TIMEOUT))
+ zapi.login(settings.ZABBIX_LOGIN, settings.ZABBIX_PASS)
+ except Exception as e:
+ x+=1
+ _logger.error("[ERR] - {} Retry #{}: {}".format(datetime.datetime.now(), x, e))
+ time.sleep(x)
+ continue
+ break
+ if x >= 10:
+ sys.exit("Can't connect to Zabbix API.")
+
+def zabbix_call(request, method):
+ global zapi
+ x = 0
+
+ while x < 10:
+ try:
+ if method == 'hostgroup':
+ resp = zapi.hostgroup.get(request)
+ elif method == 'triggers':
+ resp = zapi.trigger.get(request)
+ except Exception as e:
+ x+=1
+ _logger.error("[ERR] - {} Retry #{}: {}".format(datetime.datetime.now(), x, e))
+ time.sleep(x)
+ continue
+ break
+ if x >= 10:
+ sys.exit("Can't perform calls to Zabbix API.")
else:
- badge = '0'
- return badge
+ return resp
-def severity_css(severity):
- css = ""
- if severity == 5:
- css = 'class="disaster"'
- return css
+def read_file(file_to_update):
+ if os.path.exists(file_to_update):
+ with open(file_to_update, 'r') as f:
+ out = json.load(f)
+ f.close()
+ return out
+ return False
-def html_response(data):
- response = ""
- for x in range(len(data)):
- seconds = int(time.time()) - int(data[x]['lastchange'])
- since = convert_seconds(seconds)
- css_class = severity_css(int(data[x]['priority']))
- badge = severity_badge(int(data[x]['priority']))
- if data[x]['team'] not in config.COLOR_TEAM:
- color = "#%06x;" % random.randint(0, 0xFFFFFF)
- config.COLOR_TEAM[data[x]['team']] = color
- else:
- color = config.COLOR_TEAM[data[x]['team']]
- response += "
"+data[x]['team']+" | "+data[x]['host']+" | "+data[x]['description']+" | "+badge+" | "+since+" |
"
+def write_file(notes, file_to_update):
+ with open(file_to_update, 'w+') as f:
+ json.dump(notes, f)
+ f.close()
- return response
+def display_notes(request):
+ note_list = []
+ notes = read_file('./data/motd.json')
+ teams = request.match_info.get('teams')
+ if notes:
+ for ts in notes:
+ for note in notes[ts]:
+ if note['team'] in teams or note['team'] == 'all':
+ date_note = datetime.datetime.utcfromtimestamp(int(ts)).strftime('%Y-%m-%d %H:%M:%S')
+ note_list.append({"lvl": note["lvl"], "date": date_note, "msg": note['msg'], "name": note['name'], "ts": ts })
+ return note_list
-def capitalize_nth(s, n):
- if len(s) == 2:
- return s[:n].upper() + s[n:].capitalize()
+def get_hostgroup_color(hostgroup):
+ if hostgroup not in settings.COLOR_TEAM:
+ color = "#%06x;" % random.randint(0, 0xFFFFFF)
+ settings.COLOR_TEAM[hostgroup] = color
else:
- return s.title()
+ color = settings.COLOR_TEAM[hostgroup]
+ return color
+
+def get_hostgroups():
+ groups = []
+
+ for hg in settings.HOSTGROUP:
+ request = dict()
+ request['output'] = 'extend'
+ request['search'] = dict()
+ request['search']['name'] = hg
+ request['searchWildcardsEnabled'] = 1
+ resp = zabbix_call(request, 'hostgroup')
+ for x in range(len(resp)):
+ groups.append(resp[x]['name'])
+ return groups
-def construct_menu():
- MENU = ""
+def get_ttl_hash(seconds=45):
+ return round(time.time() / seconds)
- for key in config.CONTENT.keys():
- MENU += ""+ capitalize_nth(key.replace('Team-', ''),2) +""
- return MENU
-
-def construct_form():
- FORM = ""
- return FORM
-
-async def check_servers():
- global ZABBIX_SERVERS_CHECK
-
- while True:
- _logger.info('[INFO] - Checking Zabbix Servers: {}'.format(ZABBIX_SERVERS_CHECK))
- j = {}
- for ip in ZABBIX_SERVERS_CHECK:
- port = 10051
- if ':' in ip:
- i = ip.split(':')
- ip = i[0]
- port = int(i[1].strip())
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.settimeout(5)
- result = sock.connect_ex((ip, port))
- if result == 0:
- _logger.info("[INFO] - Port {} OK: {}".format(port, ip))
- else:
- _logger.error("[ERR] - Port {} KO: {}".format(port, ip))
- j[ip] = result
- sock.close()
- if os.path.exists('./data/zabbix-servers.json'):
- out = read_file('./data/zabbix-servers.json')
- out.update(j)
- write_file(out, './data/zabbix-servers.json')
- else:
- write_file(j, './data/zabbix-servers.json')
- await asyncio.sleep(60)
+@lru_cache()
+def get_problems(ttl_hash = None):
+ del ttl_hash
+ problems = []
+ limit = settings.LIMIT
+ groups = [group.lower() for group in get_hostgroups()]
+ try:
+ zapi.logged_in()
+ except Exception as e:
+ _logger.info('[INFO] - {}: Connection to Zabbix API'.format(datetime.datetime.now()))
+ zabbix_login()
+
+ team_list = settings.HOSTGROUP
+
+ groupids = []
+ for hg in team_list:
+ req = dict()
+ req['output'] = 'extend'
+ req['search'] = dict()
+ req['search']['name'] = hg
+ req['searchWildcardsEnabled'] = 1
+ resp = zabbix_call(req, 'hostgroup')
+ for x in range(len(resp)):
+ groupids.append(int(resp[x]['groupid']))
+
+ req = dict()
+ req['limit'] = limit
+ req['groupids'] = groupids
+ req['monitored'] = 1
+ req['maintenance'] = 0
+ req['active'] = 1
+ req['min_severity'] = settings.SEVERITY
+ req['output'] = "extend"
+ req['expandData'] = 1
+ req['selectHosts'] = "extend"
+ req['selectGroups'] = "extend"
+ req['expandDescription'] = 1
+ req['only_true'] = 1
+ req['skipDependent'] = 1
+ req['withUnacknowledgedEvents'] = 1
+ req['withLastEventUnacknowledged'] = 1
+ req['selectTags'] = "extend"
+ req['filter'] = dict()
+ req['filter']['value'] = 1
+ req['sortfield'] = ["priority","lastchange"]
+ req['sortorder'] = ["DESC"]
+
+ resp = zabbix_call(req, 'triggers')
+ for x in range(len(resp)):
+ data = resp[x]
+ if len(data['hosts']) > 0:
+ # Loop on problems
+ for z in range(len(data['groups'])):
+ if int(data['groups'][z]['groupid']) in groupids:
+ hostgroup = data['groups'][z]['name']
+ color = get_hostgroup_color(hostgroup)
+ since = convert_seconds(int(time.time()) - int(data['lastchange']))
+ problems.append({'description': data['description'], 'host': data['hosts'][0]['host'], 'priority': data['priority'], 'triggerid': data['triggerid'], 'since': since, 'hostgroup': hostgroup, 'color': color, 'lastchange': data['lastchange']})
+ for y in range(len(data['tags'])):
+ tag_value = data['tags'][y]['value']
+ if tag_value.lower() in groups:
+ color = get_hostgroup_color(tag_value)
+ since = convert_seconds(int(time.time()) - int(data['lastchange']))
+ problems.append({'description': data['description'], 'host': data['hosts'][0]['host'], 'priority': data['priority'], 'triggerid': data['triggerid'], 'since': since, 'hostgroup': tag_value, 'color': color, 'lastchange': data['lastchange']})
+ _logger.info('[INFO] - {}: Refresh...'.format(datetime.datetime.now()))
+ return problems
async def post_note(request):
data = await request.post()
@@ -201,19 +229,6 @@ async def post_note(request):
_logger.info("[ADD] - {}".format(j))
return aiohttp.web.HTTPFound(location=url, text='{}'.format(ts), content_type='text/html')
-def read_file(file_to_update):
- if os.path.exists(file_to_update):
- with open(file_to_update, 'r') as f:
- out = json.load(f)
- return out
- f.close()
- return False
-
-def write_file(notes, file_to_update):
- with open(file_to_update, 'w+') as f:
- json.dump(notes, f)
- f.close()
-
async def del_note(request):
data = await request.post()
note_id = data['note_id']
@@ -224,195 +239,90 @@ async def del_note(request):
write_file(out, './data/motd.json')
return aiohttp.web.HTTPFound(location=url)
-async def show_alerts(request):
- global CONTENT
- global NAVBAR
- global JS_CONTENT
- global TEMPLATE_FOOTER
- global TOTAL_ALERTS
-
- data_list = []
- html_content = ""
- html_notes = ""
- html_check = ""
- response = ""
-
- config.TEMPLATE_HEAD = config.TEMPLATE_HEAD.replace('FORM_TEAM', construct_form())
-
- config.NAVBAR = config.NAVBAR.replace('LIST', construct_menu())
- config.NAVBAR = re.sub('\[[0-9]+\]', '['+config.TOTAL_ALERTS+']', config.NAVBAR)
-
- url = str(request.url)
- if '/tv/' in url:
- config.TEMPLATE_FOOTER = config.TEMPLATE_FOOTER.replace('show', 'hide')
- else:
- config.TEMPLATE_FOOTER = config.TEMPLATE_FOOTER.replace('hide', 'show')
-
- teams = request.match_info.get('teams')
- if not teams:
- teams = []
- notes = read_file('./data/motd.json')
- if notes:
- for ts in notes:
- for note in notes[ts]:
- if note['team'] in teams or note['team'] == 'all':
- date_note = datetime.datetime.utcfromtimestamp(int(ts)).strftime('%Y-%m-%d %H:%M:%S')
- html_notes += " "+date_note+" | "+note['msg']+" | (by "+note['name']+") | |
"
- html_notes += '
'
- check_zbx = read_file('./data/zabbix-servers.json')
- if check_zbx:
- for ip in check_zbx:
- if check_zbx[ip] != 0:
- html_check += " Zabbix Server: "+ ip + " seems UNREACHABLE! |
"
- html_check += '
'
- IMAGE=''
- if teams:
- team_list = teams.split('+')
- for team in team_list:
- team_alerts = config.CONTENT.get(team, {})
- data_list.extend(team_alerts)
- if data_list:
- data = sorted(data_list,
- key = lambda i: (i['priority'], i['lastchange']),
- reverse=True)
- result = html_response(data)
- html_content = config.TEMPLATE_HEAD.replace('[alerts]', '['+str(len(data))+']').replace('NAVBAR', config.NAVBAR).replace('NOTES', html_notes).replace('CHECK', html_check) + result + config.TEMPLATE_FOOTER
- else:
- html_content = config.TEMPLATE_HEAD.replace('NAVBAR', config.NAVBAR).replace('NOTES', html_notes).replace('CHECK', html_check) + 'No Alerts for '+str(teams)+'!
'+IMAGE+' ' + config.TEMPLATE_FOOTER
- else:
- html_content = config.TEMPLATE_HEAD.replace('NAVBAR', config.NAVBAR) + response + config.TEMPLATE_FOOTER
- return aiohttp.web.Response(text=html_content, content_type='text/html')
-
-def zabbix_login():
- global zapi
- x = 0
-
- while x < 10:
- try:
- zapi = ZabbixAPI(server=ZABBIX_API, timeout=int(TIMEOUT))
- zapi.login(ZABBIX_LOGIN, ZABBIX_PASS)
- except Exception as e:
- x+=1
- _logger.error("[ERR] - {} Retry #{}: {}".format(datetime.datetime.now(), x, e))
- time.sleep(x)
- continue
- break
- if x >= 10:
- sys.exit("Can't connect to Zabbix API.")
-
-def call_zabbix(request, method):
- global zapi
- x = 0
-
- while x < 10:
- try:
- if method == 'hostgroup':
- resp = zapi.hostgroup.get(request)
- elif method == 'triggers':
- resp = zapi.trigger.get(request)
- except Exception as e:
- x+=1
- _logger.error("[ERR] - {} Retry #{}: {}".format(datetime.datetime.now(), x, e))
- time.sleep(x)
- continue
- break
- if x >= 10:
- sys.exit("Can't perform calls to Zabbix API.")
- else:
- return resp
-
-async def process_zabbix_queue():
- global CONTENT
- global TOTAL_ALERTS
- global HOSTGROUP
- global LIMIT
- global SEVERITY
- global zapi
-
+async def check_servers():
while True:
- try:
- zapi.logged_in()
- except Exception as e:
- _logger.info('[INFO] - {}: Connection to Zabbix API'.format(datetime.datetime.now()))
- zabbix_login()
-
- request = dict()
- request['output'] = 'extend'
- request['search'] = dict()
- request['search']['name'] = [HOSTGROUP]
- request['searchWildcardsEnabled'] = 1
- resp = call_zabbix(request, 'hostgroup')
- groupids = []
- for x in range(len(resp)):
- config.CONTENT[resp[x]['name']] = []
- groupids.append(resp[x]['groupid'])
-
- request = dict()
- request['limit'] = LIMIT
- request['groupids'] = groupids
- request['monitored'] = 1
- request['maintenance'] = 0
- request['active'] = 1
- request['min_severity'] = SEVERITY
- request['output'] = "extend"
- request['expandData'] = 1
- request['selectHosts'] = "extend"
- request['selectGroups'] = "extend"
- request['expandDescription'] = 1
- request['only_true'] = 1
- request['skipDependent'] = 1
- request['withUnacknowledgedEvents'] = 1
- request['withLastEventUnacknowledged'] = 1
- request['selectTags'] = "extend"
- request['filter'] = dict()
- request['filter']['value'] = 1
- request['sortfield'] = ["priority","lastchange"]
- request['sortorder'] = ["DESC"]
- _logger.info(request)
- resp = call_zabbix(request, 'triggers')
- config.TOTAL_ALERTS = str(len(resp))
- _logger.info('[NB ALERTS] - {}'.format(config.TOTAL_ALERTS))
- hostgroup_to_search = HOSTGROUP.replace('*','')
- for x in range(len(resp)):
- data = resp[x]
- if len(data['hosts']) > 0:
- for z in range(len(data['groups'])):
- if hostgroup_to_search in data['groups'][z]['name']:
- group = data['groups'][z]['name']
- config.CONTENT[group].append({'description': data['description'], 'host': data['hosts'][0]['host'], 'priority': data['priority'], 'triggerid': data['triggerid'], 'lastchange': data['lastchange'], 'team': group})
- for y in range(len(data['tags'])):
- if 'team' == data['tags'][y]['tag']:
- team = data['tags'][y]['value']
- config.CONTENT[team].append({'description': data['description'], 'host': data['hosts'][0]['host'], 'priority': data['priority'], 'triggerid': data['triggerid'], 'lastchange': data['lastchange'], 'team': team})
- _logger.info('[INFO] - {}: Refresh...'.format(datetime.datetime.now()))
- await asyncio.sleep(15)
+ _logger.info('[INFO] - Checking Zabbix Servers: {}'.format(settings.ZABBIX_SERVERS_CHECK))
+ j = {}
+ for ip in settings.ZABBIX_SERVERS_CHECK:
+ port = 10051
+ if ':' in ip:
+ i = ip.split(':')
+ ip = i[0]
+ port = int(i[1].strip())
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.settimeout(5)
+ result = sock.connect_ex((ip, port))
+ if result == 0:
+ _logger.info("[INFO] - Port {} OK: {}".format(port, ip))
+ else:
+ _logger.error("[ERR] - Port {} KO: {}".format(port, ip))
+ j[ip] = result
+ sock.close()
+ if os.path.exists('./data/zabbix-servers.json'):
+ out = read_file('./data/zabbix-servers.json')
+ out.update(j)
+ write_file(out, './data/zabbix-servers.json')
+ else:
+ write_file(j, './data/zabbix-servers.json')
+ await asyncio.sleep(60)
async def start_background_tasks(app):
- app['dispatch'] = app.loop.create_task(process_zabbix_queue())
app['dispatch'] = app.loop.create_task(check_servers())
-
async def cleanup_background_tasks(app):
app['dispatch'].cancel()
await app['dispatch']
+@aiohttp_jinja2.template('index.html')
+def display_alerts(request):
+ url = str(request.url)
+ if '/tv/' in url:
+ tv_mode = True
+ else:
+ tv_mode = False
+
+ teams = request.match_info.get('teams')
+ try:
+ zapi.logged_in()
+ except Exception as e:
+ _logger.info('[INFO] - {}: Connection to Zabbix API'.format(datetime.datetime.now()))
+ zabbix_login()
+
+ if teams:
+ team_list = teams.lower().split('+')
+
+ check_servers = read_file('./data/zabbix-servers.json')
+ notes = display_notes(request)
+ problems = get_problems(ttl_hash=get_ttl_hash())
+ _logger.info(len(problems))
+ problems = [problem for problem in problems if problem.get('hostgroup').lower() in team_list]
+ problems = sorted(problems,
+ key = lambda i: (i['priority'], i['lastchange']),
+ reverse=True)
+ _logger.info('[NB ALERTS] - {}'.format(len(problems)))
+ context = {'alerts': problems, 'total_alerts': len(problems), 'zabbix_url': settings.ZABBIX_URL, "hostgroups": get_hostgroups(), "notes": notes, "tv_mode": tv_mode, "check_servers": check_servers}
+ return aiohttp_jinja2.render_template(
+ 'index.html', request, context)
+
def main():
+ app = web.Application()
+ aiohttp_jinja2.setup(app,
+ loader=jinja2.FileSystemLoader('templates'))
- app = aiohttp.web.Application(logger=_logger)
-
- app.add_routes([aiohttp.web.get('/', show_alerts),
+ app.add_routes([
+ web.get('/', display_alerts),
+ web.get('/{teams}', display_alerts),
+ web.get('/tv/{teams}', display_alerts),
aiohttp.web.post('/post', post_note),
aiohttp.web.post('/del', del_note),
- aiohttp.web.get('/{teams}', show_alerts),
- aiohttp.web.get('/tv/{teams}', show_alerts),
aiohttp.web.static('/images', 'images'),
aiohttp.web.static('/css', 'css'),
- aiohttp.web.static('/js', 'js')])
-
+ aiohttp.web.static('/js', 'js')
+ ])
app.on_startup.append(start_background_tasks)
app.on_cleanup.append(cleanup_background_tasks)
- aiohttp.web.run_app(app, port=PORT)
+ aiohttp.web.run_app(app, port=settings.PORT)
if __name__ == '__main__':
- main()
+ main()
\ No newline at end of file
diff --git a/templates/form.html b/templates/form.html
new file mode 100644
index 0000000..6034e9f
--- /dev/null
+++ b/templates/form.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..c2bed2a
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,196 @@
+
+
+
+
+ [{{total_alerts}}] Super(Vision)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% if check_servers %}
+
+ {% for ip in check_servers%}
+ {% if check_servers[ip] != 0 %}
+
+
+ Zabbix Server: {{ip}} seems unreachable!
+ |
+
+ {%endif%}
+ {%endfor%}
+
+ {%endif%}
+ {% if notes %}
+
+ {% for note in notes %}
+ {{note["date"]}} | {{note["msg"]}} | (by {{note["name"]}}) | |
"
+ {% endfor %}
+
+ {% endif %}
+
+ {% if alerts|length > 0 %}
+ {% for alert in alerts %}
+ {% if alert["priority"] == '5' %}
+
+ {% else %}
+
+ {%endif%}
+
+ {{alert["hostgroup"]}}
+ |
+ {{alert["host"]}} |
+
+ {{alert["description"]}}
+ |
+ {% if alert["priority"] == '1' %}
+ 1 |
+ {% elif alert["priority"] == '2' %}
+ 2 |
+ {% elif alert["priority"] == '3' %}
+ 3 |
+ {% elif alert["priority"] == '4' %}
+ 4 |
+ {% elif alert["priority"] == '5' %}
+ |
+ {% endif %}
+
+ {{alert["since"]}}
+ |
+
+ {%endfor%}
+ {%else%}
+
+ {%endif%}
+
+
+
+
+
\ No newline at end of file