icinga-dynamic-statuspage/statuspage/__init__.py

140 lines
4.1 KiB
Python
Raw Normal View History

2023-09-10 07:14:33 +00:00
#!/usr/bin/env python3
import json
import logging
from datetime import datetime, timedelta
from os import environ
from re import sub
from flask import Flask, abort, jsonify, render_template, request
from psycopg2.pool import ThreadedConnectionPool
app = Flask(__name__)
app.config.from_file(environ['APP_CONFIG'], json.load)
if not app.debug:
log = logging.StreamHandler()
log.setLevel(logging.INFO)
app.logger.addHandler(log)
pg_pool = ThreadedConnectionPool(
minconn=1,
maxconn=20,
user=app.config['DB_USER'],
password=app.config['DB_PASS'],
database=app.config['DB_NAME'],
host='localhost',
)
def check_freshness(cur):
cur.execute('select status_update_time from icinga_programstatus;')
if datetime.utcnow() - cur.fetchone()[0] > timedelta(minutes=5):
abort(503)
def get_nodename(identifier):
if identifier in HOSTS:
return HOSTS[identifier]
abort(404)
@app.route('/status.json')
def services_as_json():
conn = pg_pool.getconn()
results = []
try:
cur = conn.cursor()
check_freshness(cur)
cur.execute(
'''
select
objs.name1,
objs.name2,
icinga_servicestatus.current_state,
icinga_servicestatus.scheduled_downtime_depth,
icinga_servicestatus.state_type,
icinga_servicestatus.output,
icinga_servicestatus.problem_has_been_acknowledged,
icinga_servicestatus.status_update_time,
icinga_servicestatus.last_state_change,
(
select vars.varvalue
from icinga_customvariables vars, icinga_services
where objs.object_id = icinga_services.service_object_id
and icinga_services.host_object_id = vars.object_id
and vars.varname = 'pretty_name'
)
from icinga_objects objs
left join icinga_servicestatus on objs.object_id = icinga_servicestatus.service_object_id
left join icinga_servicegroup_members sgrm on objs.object_id = sgrm.service_object_id
where
objs.objecttype_id = 2 and
objs.is_active = 1 and
sgrm.servicegroup_id = %s
;''',
(app.config['SERVICEGROUP_ID'],),
)
for (
host_name,
service_name,
state,
downtime_depth,
state_type,
output,
acked,
update_time,
last_state_change,
pretty_name,
) in cur.fetchall():
if last_state_change is None:
last_state_change = update_time
for regex, replacement in app.config.get('NAME_REPLACEMENTS', {}).items():
service_name = sub(regex, replacement, service_name)
results.append(
{
'type': 'Service',
'attrs': {
'acknowledgement': acked,
'display_name': service_name,
'downtime_depth': downtime_depth,
'host_name': pretty_name,
'last_check': update_time.timestamp(),
'last_state_change': last_state_change.timestamp(),
'state': state,
'state_type': state_type,
'last_check_result': {
'output': output,
},
'__custom': {
'last_check': update_time.strftime('%Y-%m-%d %H:%M:%S UTC'),
'last_state_change': last_state_change.strftime(
'%Y-%m-%d %H:%M:%S UTC'
),
},
},
}
)
cur.close()
finally:
pg_pool.putconn(conn)
return jsonify({'results': results})
@app.route('/')
def statuspage():
return render_template('statuspage.html')
if __name__ == '__main__':
app.run(host='::')