Compare commits

..

7 commits

4 changed files with 110 additions and 22 deletions

41
error.html Normal file
View file

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>${title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🔥</text></svg>">
</head>
<body>
<div class="container">
<div class="page-header my-5" id="banner">
<div class="row">
<div class="col-lg-8">
<h1>Status: 🔥</h1>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="card text-white border-primary mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h4>Something went wrong</h4>
</div>
<div class="card-body">
<p>
There was an error rendering the status page.
Admins have been notified.
</p>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
window.setTimeout(function() {
window.location.reload();
}, 10000);
</script>
</body>
</html>

View file

@ -1,2 +1,3 @@
Mako Mako
tomlkit tomlkit
requests

View file

@ -1,29 +1,39 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import requests import logging
import urllib3 import shutil
import sys
from datetime import datetime
from os import environ from os import environ
import requests
import tomlkit import tomlkit
import urllib3
from mako.template import Template from mako.template import Template
urllib3.disable_warnings() urllib3.disable_warnings()
CONFIGFILE = environ.get('STATUSPAGE_CONFIG', 'config.toml') CONFIGFILE = environ.get('STATUSPAGE_CONFIG', 'config.toml')
class StatusPage: class StatusPage:
def get_api_result(self): def get_api_result(self):
if self.services: if self.services:
log.debug('services already exist, returning early')
return self.services return self.services
headers = { headers = {'Accept': 'application/json', 'X-HTTP-Method-Override': 'GET'}
'Accept': 'application/json',
'X-HTTP-Method-Override': 'GET'
}
requestbody = { requestbody = {
"attrs": [ "name", "state", "last_check_result", "host_name", "display_name" ], "attrs": [
"joins": [ "host.name", "host.state", "host.last_check_result", "host.vars" ], "name",
"state",
"last_check_result",
"host_name",
"display_name",
],
"joins": ["host", "host.state", "host.last_check_result", "host.vars"],
"filter": self.config['filters']['services'], "filter": self.config['filters']['services'],
} }
@ -31,17 +41,24 @@ class StatusPage:
'{}/v1/objects/services'.format(self.config['icinga2_api']['baseurl']), '{}/v1/objects/services'.format(self.config['icinga2_api']['baseurl']),
headers=headers, headers=headers,
json=requestbody, json=requestbody,
auth=(self.config['icinga2_api']['username'], self.config['icinga2_api']['password']), auth=(
verify=False self.config['icinga2_api']['username'],
self.config['icinga2_api']['password'],
),
verify=False,
) )
if (r.status_code == 200): self.logger.info(f'got http status code {r.status_code}')
self.logger.debug(r.text)
if r.status_code == 200:
self.services = r.json()['results'] self.services = r.json()['results']
else: else:
r.raise_for_status() r.raise_for_status()
return self.services self.logger.info(f'got {len(self.services)} services from api')
return self.services
def prettify(self, text): def prettify(self, text):
for search, replace in self.config.get('prettify', {}).items(): for search, replace in self.config.get('prettify', {}).items():
@ -49,7 +66,6 @@ class StatusPage:
return text return text
def get_services_per_host(self): def get_services_per_host(self):
state_to_design_mapping = [ state_to_design_mapping = [
('success', 'OK'), ('success', 'OK'),
@ -60,6 +76,11 @@ class StatusPage:
result = {} result = {}
for service in self.get_api_result(): for service in self.get_api_result():
self.logger.info(
f'now processing {service["attrs"]["host_name"]} "{service["attrs"]["display_name"]}"'
)
self.logger.debug(service)
host = service['joins']['host']['vars']['pretty_name'] host = service['joins']['host']['vars']['pretty_name']
if host not in result: if host not in result:
@ -80,14 +101,16 @@ class StatusPage:
if state in (1, 2): if state in (1, 2):
self.ragecounter += state self.ragecounter += state
result[host]['services'][self.prettify(service['attrs']['display_name'])] = { result[host]['services'][
self.prettify(service['attrs']['display_name'])
] = {
'badge': state_to_design_mapping[state][0], 'badge': state_to_design_mapping[state][0],
'state': state_to_design_mapping[state][1], 'state': state_to_design_mapping[state][1],
} }
self.logger.info(f'ragecounter is now {self.ragecounter}')
return result return result
def render_html(self, service_details): def render_html(self, service_details):
if self.ragecounter == 0: if self.ragecounter == 0:
mood = '🆗' mood = '🆗'
@ -96,27 +119,45 @@ class StatusPage:
else: else:
mood = '🔥' mood = '🔥'
template = Template(filename=self.config['output'].get('template', 'template.html')) self.logger.info('rendering output html')
start = datetime.now()
template = Template(
filename=self.config['output'].get('template', 'template.html')
)
output = template.render( output = template.render(
title=self.config['output'].get('page_title', 'Status Page'), title=self.config['output'].get('page_title', 'Status Page'),
mood=mood, mood=mood,
hosts=service_details, hosts=service_details,
) )
end = datetime.now()
self.logger.info(f'rendered in {(end-start).total_seconds():.09f}s')
with open(self.config['output']['filename'], 'w') as f: with open(self.config['output']['filename'], 'w') as f:
f.write(output) f.write(output)
def __init__(self): def __init__(self):
self.config = tomlkit.loads(open(CONFIGFILE).read()) self.config = tomlkit.loads(open(CONFIGFILE).read())
self.services = {} self.services = {}
self.ragecounter = 0 self.ragecounter = 0
self.logger = logging.getLogger('StatusPage')
handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter(
'%(levelname)s {%(filename)s:%(lineno)d} %(message)s'
)
handler.setFormatter(formatter)
self.logger.addHandler(handler)
self.logger.setLevel(self.config.get('loglevel', 'INFO'))
if __name__ == "__main__": if __name__ == "__main__":
page = StatusPage() page = StatusPage()
service_details = page.get_services_per_host()
from pprint import pprint try:
pprint(service_details) service_details = page.get_services_per_host()
page.render_html(service_details)
page.render_html(service_details) except Exception as e:
shutil.copyfile('error.html', page.config['output']['filename'])
raise e

View file

@ -39,5 +39,10 @@
</div> </div>
% endfor % endfor
</div> </div>
<script type="text/javascript">
window.setTimeout(function() {
window.location.reload();
}, 30000);
</script>
</body> </body>
</html> </html>