Ein Check ist erst dann gültig, wenn er gewisse Voraussetzungen erfüllt. Zum einen, muss er ein Nachkomme der Klasse Check
sein. Somit wird sichergestellt, dass er die Grundfunktionalität eines Checks hat.
Zudem muss der Check die Funktion check()
der Standardklasse so erweitern, dass er innerhalb dieser Funktion seine eigene Funktionalität implementiert, die Funktion set_value()
aufruft und schließlich seinen Wert zurückgibt.
Die o. a. Implementierung sieht in der Praxis folgendermaßen aus:
# CPU check
def check(self):
cpu = cpu_percent()
self.set_value(cpu)
return cpu
Weitere Voraussetzungen sind die Einhaltung der Struktur- und Namenskonvention. Im Allgemeinen gilt es folgenes zu beachten:
- Es muss für jeden Check eine neue Datei im Verzeichnis
checks
angelegt werden, welche zwangsweisecheck_name.py
zu heißen hat, wobeiname
mit dem Namen der entsprechenden Check-Klasse ersetzt wird. Für den CPU-Check heißt die Dateicheck_cpu.py
. - Der Klassenname muss die PEP8-Konvention (Stand 2018) entsprechen. Konkret bedeutet dies, dass die erste Buchstabe großgeschrieben wird und keine Sonderzeichen enthalten sein sollten. Dementsprechend heißt die Klasse für den CPU-Check wie folgt:
class Cpu(Check):
Zuständig für die Konfiguration des gesamten Systems ist die settings.py
-Datei. Die darin enthalteten Einstellungen sind relativ selbsterklärend.
Ein Webserver wird mittles flask
zur Verügung gestellt und läuft standardmäßig auf Port 8088.
Mit @app.route("/")
erstellen wir einen lokalen Host. Auf diesen Host haben wir unsere Website erstellt, wo wir die Ausgaben der einzelnen Checks wiedergeben.
@app.route("/")
def localhost():
data = {'checks': checks}
return render_template('website.html', **data)
Der aktuelle Status der einzelnen Checks lässt sich über eine Anfrage an /check/<name>
(wobei name
bspw. durch den Check "cpu" ersetzt wird) abfragen. Die dafür zuständige Funktion daily_post()
sieht folgendermaßen aus:
@app.route('/check/<check>', methods=['GET'])
def daily_post(check):
if check in checks:
value = client.check_by_name(check)
return "{}".format(value)
else:
return "Error: {} check not found!".format(check)
Die wiederkehrende Aktualisierung der Informationen der einzelnen Checks auf der Webseite erfolgt durch eine Javaskript-Funktion names setupChart()
, welche den Checknamen jede Sekunde abfragt und diesen auf der Webseite aktualisiert.
Die Webseite wird durch ein Jinja-Template erzeugt. Jeder Checks wird durch die Schleife innerhalb des <body>
mit dem Template verknüpft und auf der Webseite einzeln wiedergegeben.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Monitoring</title>
<link rel="stylesheet" href="/static/style.css"/>
<script src="/static/canvasjs.min.js"></script>
<script src="/static/charts.js"></script>
</head>
<body>
{% for check in checks %}
<div class="{{ check }}">
<div id="{{ check }}-chart" class="chart"></div>
<script>setupChart("{{ check }}")</script>
</div>
{% endfor %}
</body>
</html>
<script src="/static/canvasjs.min.js"></script>
<script src="/static/charts.js"></script>
<link rel="stylesheet" href="/static/style.css"/>
In der CSS-Datei haben wir ein Bild aus der Source-Datei von der Implementierung des Diagramms entfernt und haben die größe des Diagramms definiert:
div.chart{
height: 360px;
width: 90%;
padding: 20px;
}
.canvasjs-chart-credit{
display: none;
}
Zum Starten der Unit-Tests muss folgende Commandline eingegeben werden:
python3 ./unit_tests/tests.py
Die zuständige Klasse für die Unit-Tests ist ModuleTest
, welche bestimmte Abläufe überprüft.
- Im
test_supported_checks()
wird überprüft, ob es überhaupt supportete Checks gibt. test_exceptions_reflection()
hat die Aufgabe zu überprüfen, ob das Importieren eines Checks anhand eines ungültigen Namens fehlschlägt. Ist dieser Checkname ungültig, so wird einImportError
ausgegeben. Sollte der WertNone
sein, so wird auchNone
ausgegeben.- Im
test_checks_default()
wird überprüft, ob der CPU-Check vorhanden und funktionfähig ist. - Im
test_system_status()
wird überprüft, ob die Funktion zum Abrufen des Systemstatus funktionsfähig ist.
class ModuleTest(BaseTest):
def __init__(self):
self.client = Client()
def test_supported_checks(self):
self.all_checks = self.client.get_supported_checks()
self.assertTrue(self.all_checks is not None and len(self.all_checks) > 0)
def test_exceptions_reflection(self):
self.assertTrue(self.client.check_by_name(None) is None)
with self.assertRaises(ImportError):
random_name = "".join( [random.choice(string.ascii_letters) for i in xrange(15)] )
self.client.check_by_name(random_name)
def test_checks_default(self):
self.assertTrue(self.client.check_by_name("cpu") is not None)
def test_system_status(self):
self.assertTrue(self.client.system_status() is not None)
if __name__ == '__main__':
unittest.main()