isengard-bot/data.py

198 lines
6.0 KiB
Python

import datetime
import logging
from systemd.journal import JournalHandler
# Logging
log = logging.getLogger(__name__)
log.addHandler(JournalHandler())
PRIORITY = {
"OK":0,
"UP":0,
"WARNING":1,
"CRITICAL":2,
"UNKNOWN": 2,
"DOWN": 3,
}
class ProblemData:
"""
Data related to notifications related to a given problem
"""
def __init__(self, name):
self.name = name
self.status = "OK"
self.last_update = datetime.datetime.fromtimestamp(0)
class HostData:
"""
Data related to notifications related to a given host
"""
def __init__(self, name):
self.name = name
self.status = "OK"
self.downtime = False
self.last_update = datetime.datetime.fromtimestamp(0)
self.worst = None
self.problems = set()
class DataStore:
def __init__(self, linkedBot):
log.info("Created DataStore")
self.hosts = set()
self.linkedBot = linkedBot
def notify(self, destmuc):
msg = "```\n"
msg += "*** Isengard - Statut des services ***\n\n"
msg += "-"*80 + "\n"
msg += "| Hôte | Statut | Pire service | Dernière maj |\n"
msg += "-"*80 + "\n"
for host in [x for x in self.hosts]:
msg += "*"
msg += " " + str(host.name)[:22] + " "*(23 - len(str(host.name)[:22])) + "|"
msg += " " + str(host.status)[:8] + " "*(9 - len(str(host.status))) + "|"
msg += " " + str(host.worst)[:16] + " "*(17 - len(str(host.worst)[:16])) + "|"
msg += " " + host.last_update.strftime("%m/%d/%Y, %H:%M:%S")[:21] +\
" "*(22 - len(host.last_update.strftime("%m/%d/%Y, %H:%M:%S"))) +\
"|\n"
msg += "-"*80 + "\n"
if PRIORITY[host.status] == 0:
self.hosts.discard(host)
msg += "```"
# Send notification
log.info("Sending to %s: %s" % (destmuc, msg))
self.linkedBot.push(destmuc, msg)
def get_status(self):
msg = "```\n"
msg += "*** Isengard - Statut des services ***\n\n"
msg += "-"*80 + "\n"
msg += "| Hôte | Statut | Pire service | Dernière maj |\n"
msg += "-"*80 + "\n"
for host in [x for x in self.hosts]:
msg += "*"
msg += " " + str(host.name)[:22] + " "*(23 - len(str(host.name)[:22])) + "|"
msg += " " + str(host.status)[:8] + " "*(9 - len(str(host.status))) + "|"
msg += " " + str(host.worst)[:16] + " "*(17 - len(str(host.worst)[:16])) + "|"
msg += " " + host.last_update.strftime("%m/%d/%Y, %H:%M:%S")[:21] +\
" "*(22 - len(host.last_update.strftime("%m/%d/%Y, %H:%M:%S"))) +\
"|\n"
msg += "-"*80 + "\n"
if PRIORITY[host.status] == 0:
self.hosts.discard(host)
msg += "```"
return msg
def push(self, msg):
"""
Process messages like TYPE|HOST/SERVICE|STATE|OUTPUT|SENDER|COMMENT
"""
# Get current time
curtime = datetime.datetime.now() #.strftime("%m/%d/%Y, %H:%M:%S")
# Get all params
destmuc, mtype, location, status, text, sender, comment = msg.split("|")
mtype = mtype.replace(" ", "")
status = status.replace(" ", "")
# Check if message is about a service or host
try:
hostname, service = location.split("/")
except ValueError:
hostname = location.split("/")[0]
service = None
cur = None
# Look for host
for host in self.hosts:
if host.name == hostname:
cur = host
# Host not found
if not(cur):
cur = HostData(hostname)
self.hosts.add(cur)
log.info("CREATED : %s\n" % cur)
# Retrieve informations and update
log.info("RECEIVED : status %s; mtype %s; location %s; sender %s; comment %s; text %s\n"
% (status, mtype, location, sender, comment, text))
cur.last_update = curtime
# If that's global
if not(service):
# Host is now down
if PRIORITY[status] > PRIORITY[cur.status]:
cur.status = status
cur.worst = "DOWN"
# DOWNTIME
elif "DOWNTIME" in mtype:
pass
# Host is no more down and has no more problems
elif not len(cur.problems):
cur.status = "OK"
cur.worst = None
# Service problem
else:
cur_problem = None
# Look for existing problem
for problem in cur.problems:
if problem.name == service:
cur_problem = problem
# Problem not found, create it
if not(cur_problem):
cur_problem = ProblemData(service)
cur.problems.add(cur_problem)
log.info("CREATED PROBLEM in %s : %s\n" % (cur, cur_problem))
cur_problem.last_update = curtime
cur_problem.status = status
if PRIORITY[status] == 0 and cur.worst == cur_problem:
cur.worst = None
cur.status = "OK"
worst_problem = ProblemData(None)
# Find the worst current problem
for problem in cur.problems:
if PRIORITY[problem.status] > PRIORITY[worst_problem.status]:
if problem.last_update > worst_problem.last_update:
worst_problem = problem
if worst_problem.name != None:
cur.status = worst_problem.status
cur.worst = worst_problem.name
if PRIORITY[status] >= 2 or ("RECOVERY" in mtype and cur.worst == None):
self.notify(destmuc)
return