mirror of
https://github.com/FAUSheppy/icinga-webhook-gateway
synced 2025-12-06 07:21:38 +01:00
feat: entry creation % details
This commit is contained in:
67
server.py
67
server.py
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import time
|
||||
import flask
|
||||
import json
|
||||
import argparse
|
||||
@@ -7,6 +8,12 @@ import os
|
||||
import datetime
|
||||
import pytimeparse.timeparse as timeparse
|
||||
import sys
|
||||
import secrets
|
||||
|
||||
import flask_wtf
|
||||
from flask_wtf import FlaskForm, CSRFProtect
|
||||
from wtforms import StringField, SubmitField, BooleanField, DecimalField
|
||||
from wtforms.validators import DataRequired, Length
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Boolean, or_, and_
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
@@ -17,6 +24,9 @@ from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy.sql.expression import func
|
||||
|
||||
app = flask.Flask("Icinga Report In Gateway")
|
||||
CSRFProtect(app)
|
||||
|
||||
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
|
||||
app.config['JSON_CONFIG_FILE'] = 'services.json'
|
||||
app.config['JSON_CONFIG_DIR'] = 'config'
|
||||
@@ -40,6 +50,10 @@ class Status(db.Model):
|
||||
status = Column(String)
|
||||
info_text = Column(String)
|
||||
|
||||
def human_date(self):
|
||||
dt = datetime.datetime.fromtimestamp(self.timestamp)
|
||||
return dt.strftime("%d-%m%-%y %H:%M")
|
||||
|
||||
def buildReponseDict(status, service=None):
|
||||
|
||||
if not status:
|
||||
@@ -56,6 +70,8 @@ def buildReponseDict(status, service=None):
|
||||
@app.route('/overview')
|
||||
def overview():
|
||||
|
||||
user = flask.request.headers.get("X-Preferred-Username")
|
||||
|
||||
# query all services #
|
||||
services = db.session.query(Service).all()
|
||||
|
||||
@@ -83,7 +99,54 @@ def overview():
|
||||
status_unique_results.append(status)
|
||||
|
||||
return flask.render_template("overview.html", status_list=status_unique_results,
|
||||
datetime=datetime.datetime)
|
||||
datetime=datetime.datetime, user=user)
|
||||
|
||||
class EntryForm(FlaskForm):
|
||||
|
||||
service = StringField("Service Name", validators=[DataRequired()])
|
||||
timeout = DecimalField("Timeout in days", default=30)
|
||||
|
||||
def create_entry(form, user):
|
||||
|
||||
# TODO add entry to icinga
|
||||
token = secrets.token_urlsafe(16)
|
||||
print(form.timeout.data)
|
||||
service = Service(service=form.service.data, timeout=int(form.timeout.data),
|
||||
owner=user, token=token)
|
||||
db.session.merge(service)
|
||||
db.session.commit()
|
||||
|
||||
@app.route("/service-details")
|
||||
def service_details():
|
||||
|
||||
user = flask.request.headers.get("X-Preferred-Username")
|
||||
service = flask.request.args.get("service")
|
||||
|
||||
# query service #
|
||||
service = db.session.query(Service).filter(Service.service==service).first()
|
||||
|
||||
# validate #
|
||||
if not service:
|
||||
return ("{} not found".format("service"), 404)
|
||||
if service.owner and service.owner != user:
|
||||
return ("Services is not owned by {}".format(user))
|
||||
|
||||
status_list = db.session.query()
|
||||
|
||||
return flask.render_template("service_info.html", service=service, flask=flask,
|
||||
user=user)
|
||||
|
||||
|
||||
@app.route("/entry-form", methods=["GET", "POST"])
|
||||
def create_interface():
|
||||
|
||||
user = flask.request.headers.get("X-Preferred-Username")
|
||||
|
||||
form = EntryForm()
|
||||
if form.validate_on_submit():
|
||||
create_entry(form, user)
|
||||
return flask.redirect('/service-details?service={}'.format(form.service.data))
|
||||
return flask.render_template('add_modify_service.html', form=form)
|
||||
|
||||
@app.route('/alive')
|
||||
def alive():
|
||||
@@ -188,6 +251,8 @@ def create_app():
|
||||
db.create_all()
|
||||
config = {}
|
||||
|
||||
app.config["SECRET_KEY"] = secrets.token_urlsafe(64)
|
||||
|
||||
if os.path.isfile(app.config["JSON_CONFIG_FILE"]):
|
||||
with open(app.config["JSON_CONFIG_FILE"]) as f:
|
||||
config |= json.load(f)
|
||||
|
||||
79
static/site.css
Normal file
79
static/site.css
Normal file
@@ -0,0 +1,79 @@
|
||||
body{
|
||||
background: radial-gradient(ellipse at center, #47918a 0%, #0b3161 100%);
|
||||
color: aliceblue !important;
|
||||
}
|
||||
|
||||
.navbar{
|
||||
width: 100%;
|
||||
background: rgba(0,0,0,0);
|
||||
display: block;
|
||||
box-shadow: none;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.navbar-el{
|
||||
float: right;
|
||||
display: inline-block;
|
||||
background: rgba(0,0,0,0);
|
||||
color: aliceblue;
|
||||
}
|
||||
|
||||
.navbar-el:hover{
|
||||
color: darkgray;
|
||||
}
|
||||
|
||||
.overview-tile{
|
||||
color: black;
|
||||
}
|
||||
|
||||
.last-status{
|
||||
margin-top: 10px;
|
||||
box-shadow: 0px 0px 4px 3px rgba(0,0,0,0.5);
|
||||
background: linear-gradient(to top, #cfc6b054 0%, #cfcfcfc4 100%);
|
||||
padding: 8px;
|
||||
width: fit-content;
|
||||
font-family: monospace;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.last-status p{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.service-name{
|
||||
margin: auto;
|
||||
max-width: 1000px;
|
||||
width: fit-content;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.service-timeout{
|
||||
|
||||
}
|
||||
|
||||
.service-token{
|
||||
|
||||
}
|
||||
|
||||
.example{
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.example-indent{
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.example-indent-double{
|
||||
padding-left: 50px;
|
||||
}
|
||||
|
||||
.status-table{
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
24
templates/add_modify_service.html
Normal file
24
templates/add_modify_service.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{% include "head.html" %}
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<button class="mt-4 mb-4 btn btn-secondary" onclick="window.location.href='/'">
|
||||
Back
|
||||
</button>
|
||||
{% if form.service.errors %}
|
||||
<ul class="errors">
|
||||
{% for error in form.service.errors %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<form method="POST" action="/entry-form">
|
||||
|
||||
{{ form.csrf_token }}
|
||||
{{ form.service.label }} {{ form.service(size=20) }} </br>
|
||||
{{ form.timeout.label }} {{ form.timeout() }} </br>
|
||||
|
||||
<input type="submit" value="Go">
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
24
templates/head.html
Normal file
24
templates/head.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/static/site.css">
|
||||
<link rel="shortcut icon" href="/static/defaultFavicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- needed for @media-css mofiers -->
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
||||
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="https://cdn.atlantishq.de/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Material Design Bootstrap -->
|
||||
<link href="https://cdn.atlantishq.de/css/mdb.min.css" rel="stylesheet">
|
||||
|
||||
<script src="https://cdn.atlantishq.de/js/jquery.js"></script>
|
||||
<script src="https://cdn.atlantishq.de/js/popper.js"></script>
|
||||
<script src="https://cdn.atlantishq.de/js/bootstrap.js"></script>
|
||||
<script src="https://cdn.atlantishq.de/js/mdb.min.js"></script>
|
||||
<script src="https://cdn.atlantishq.de/js/addons/datatables.min.js" type="text/javascript">
|
||||
</script>
|
||||
</head>
|
||||
12
templates/navbar.html
Normal file
12
templates/navbar.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<div class="navbar">
|
||||
{% if user %}
|
||||
<div style="float: left;" class="navbar-el">{{ user }}</div>
|
||||
{% endif %}
|
||||
<a href="/overview" style="float: left;" class="navbar-el">Overview</a>
|
||||
<a href="/entry-form" style="float: left;" class="navbar-el">Create Service</a>
|
||||
{% if user %}
|
||||
<a href="/oauth2/sign_out" class="navbar-el">Logout</a>
|
||||
{% else %}
|
||||
<div class="navbar-el placeholder"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -1,33 +1,12 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/static/site.css">
|
||||
<link rel="shortcut icon" href="/static/defaultFavicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- needed for @media-css mofiers -->
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
||||
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="https://cdn.atlantishq.de/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Material Design Bootstrap -->
|
||||
<link href="https://cdn.atlantishq.de/css/mdb.min.css" rel="stylesheet">
|
||||
|
||||
<script src="https://cdn.atlantishq.de/js/jquery.js"></script>
|
||||
<script src="https://cdn.atlantishq.de/js/popper.js"></script>
|
||||
<script src="https://cdn.atlantishq.de/js/bootstrap.js"></script>
|
||||
<script src="https://cdn.atlantishq.de/js/mdb.min.js"></script>
|
||||
<script src="https://cdn.atlantishq.de/js/addons/datatables.min.js" type="text/javascript">
|
||||
</script>
|
||||
</head>
|
||||
{% include "head.html" %}
|
||||
<html>
|
||||
<body>
|
||||
{% include "navbar.html" %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{% for status in status_list %}
|
||||
<div class="col-md-5 m-3 p-2 border rounded"
|
||||
<a href="/service-details?service={{ status.service}}"
|
||||
class="col-md-5 m-3 p-2 border rounded overview-tile"
|
||||
{% if status.status == "OK" %}
|
||||
style="background-color: lightgreen;"
|
||||
{% elif status.status == "WARNING" %}
|
||||
@@ -44,7 +23,7 @@
|
||||
{% else %}
|
||||
{{ datetime.fromtimestamp(status.timestamp).strftime("%H:%M %d.%m.%y") }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
61
templates/service_info.html
Normal file
61
templates/service_info.html
Normal file
@@ -0,0 +1,61 @@
|
||||
{% include "head.html" %}
|
||||
<html>
|
||||
<body>
|
||||
{% include "navbar.html" %}
|
||||
<div class="container">
|
||||
<h2 class="service-name">Service: {{ service.service }}</h2>
|
||||
<div class="service-timeout">Timeout: {{ service.timeout }}d</div>
|
||||
<div class="service-token">Secret Token: {{ service.token }}</div>
|
||||
|
||||
<div class="last-status">
|
||||
{% if status_list | length > 0 %}
|
||||
<p>{{ status_list[0].status }} submitted on {{ status_list[0].timestamp }}</i>
|
||||
{% else %}
|
||||
<p style="color: darkred;">No status for this service submitted</i>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<h5 class="my-4">Curl</h5>
|
||||
<div class="ml-3 example">
|
||||
curl -X POST \ <br>
|
||||
<div class="example-indent">
|
||||
-H "application/json" \ <br>
|
||||
-d '{ "service_name" : "{{ service.service }}",
|
||||
"token" : "{{ service.token }}", \<br>
|
||||
"status" : "OK", "info" : "Free Text Information here" }' \<br>
|
||||
{{ flask.request.url_root }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="my-4">Python</h5>
|
||||
<div class="ml-3 example">
|
||||
import requests
|
||||
requests.post("{{ flask.request.url_root }}",<br>
|
||||
<div class="example-indent-double">
|
||||
json= { "service_name" : "{{ service.service }}", <br>
|
||||
<div class="example-indent-double">
|
||||
"token" : "{{ service.token }}", <br>
|
||||
"status" : "OK", </br>
|
||||
"info" : "additional information" })
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="mb-4 mt-5 status-table">
|
||||
<thead>
|
||||
<th>Date</th>
|
||||
<th>Status</th>
|
||||
<th>Info</th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for status in status_list %}
|
||||
<td>status.human_date()<td>
|
||||
<td>status.status</td>
|
||||
<td>status.info</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user