140 lines
4.1 KiB
Python
140 lines
4.1 KiB
Python
|
#!/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='::')
|