summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bwLpStatus.py212
-rw-r--r--bwlpMonitor_template.html39
-rw-r--r--img/favicon.icobin0 -> 452 bytes
-rw-r--r--img/logo_bwlehrpool.pngbin0 -> 14298 bytes
-rw-r--r--img/wiki_bwlehrpool.pngbin0 -> 741 bytes
-rw-r--r--style.css196
6 files changed, 447 insertions, 0 deletions
diff --git a/bwLpStatus.py b/bwLpStatus.py
new file mode 100644
index 0000000..a0642a8
--- /dev/null
+++ b/bwLpStatus.py
@@ -0,0 +1,212 @@
+import subprocess
+import urllib.request
+import urllib.error
+#import mysql.connector
+import thriftpy
+from thriftpy.rpc import make_client
+from thriftpy.transport import TFramedTransportFactory
+import shutil
+import datetime
+import os
+
+# Global variables
+statusList = []
+logEntries = []
+newLogIndex = 0
+
+# Class of the status objects
+class Status:
+ def __init__(self, name, host, state, status, service, msg = '', data = []):
+ # Name of the service.
+ self.name = name
+
+ # Hostname (Domain, ip, ...)
+ self.host = host
+
+ # State of the response. (success, warning, error) <-- This class is responsible for the coloring (green, orange, red)
+ self.state = state
+
+ # Status of the check. (Online, Offline, Temporaily not available, Some services unavailable, ...) <-- This text is shown on the website
+ self.status = status
+
+ # Type of the service. (ping, https, http, mysql, ...)
+ self.service = service
+
+ # Message e.g. error message
+ self.msg = msg
+
+ # Data the request return e.g. organisation list from the thrift client.
+ self.data = data
+
+class LogEntry:
+ def __init__(self, date, host, service, state, msg = '', data = []):
+ self.date = date
+ self.host = host
+ self.service = service
+ self.state = state
+ self.msg = msg
+ self.data = data
+
+class Organisation:
+ def __init__(self, id, name):
+ self.id = id
+ self.name = name
+
+ def __repr__(self):
+ return str(self.__dict__)
+
+# Check connection functions.
+def ping(name, hostname):
+ # Ping a hostname and tell if the server is up or down.
+ print('Ping request ... ', end='')
+ response = subprocess.Popen(
+ ['ping', '-c', '1', hostname],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE
+ )
+ response = response.communicate()
+ output = response[0].decode('utf-8')
+ error = response[1].decode('utf-8')
+
+ # Error happend
+ if error != '':
+ print('error: ', end='')
+ print(error)
+ statusList.append(Status(name, hostname, 'error', 'Offline', 'ping', error.rstrip()))
+ else:
+ print('success')
+ statusList.append(Status(name, hostname, 'success', 'Online', 'ping'))
+
+ logStatus(statusList[-1])
+
+def https(name, url):
+ print('HTTPS request')
+ try:
+ r = urllib.request.urlopen(url)
+ if r.getcode() == 200:
+ statusList.append(Status(name, url, 'success', 'Online', 'https'))
+ else:
+ statusList.append(Status(name, url, 'error', 'Offline', 'https'))
+
+ except urllib.error.URLError as e:
+ statusList.append(Status(name, url, 'error', 'Offline', 'https'))
+
+ logStatus(statusList[-1])
+
+def mysql(self, host, user, passwd, db):
+ print('MYSQL request start ...')
+ #db = mysql.connector.connect(
+ # host='localhost',
+ # user='openslx',
+ # passwd='geheim',
+ # database='openslx'
+ #)
+ #cursor = db.cursor()
+ #cursor.execute('SELECT * FROM user')
+ #result = cursor.fetchall()
+ #for user in result:
+ # print(user[1])
+
+def thrift(name, ip, port):
+ print('THRIFT request start ...')
+ bwlp_thrift = thriftpy.load('bwlp.thrift', module_name='bwlp_thrift')
+ # masterserver = make_client(bwlp_thrift.MasterServer, '132.230.4.16', 9090, trans_factory=TFramedTransportFactory())
+ # TODO: TRY CATCH
+ satserver = make_client(bwlp_thrift.SatelliteServer, ip, port, trans_factory=TFramedTransportFactory())
+ organisations = satserver.getAllOrganizations()
+ organisationList = []
+ for org in organisations:
+ organisationList.append(Organisation(org.organizationId, org.displayName))
+
+ host = ip + ':' + str(port)
+ statusList.append(Status(name, host, 'success', 'Online (' + str(len(organisationList)) + ')', 'thrift', data=organisationList))
+ logStatus(statusList[-1])
+
+# Parses the log from the logfile. Fills the logEntries array.
+def parseLog():
+ if not (os.path.exists('bwLpStatusLog.txt')):
+ return
+ with open('bwLpStatusLog.txt', 'r') as log:
+ for line in log:
+ line = line.strip()
+ entry = line.split('\t')
+ if len(entry) < 4: continue
+ logEntries.append(LogEntry(entry[0], entry[1], entry[2], entry[3], '' if len(entry) < 5 else entry[4], [] if len(entry) < 6 else entry[5]))
+ global newLogIndex
+ newLogIndex = len(logEntries)
+
+# Writes updated log in the logfile.
+def writeLog():
+ with open('bwLpStatusLog.txt', 'a') as log:
+ for entry in logEntries[newLogIndex:]:
+ log_string = entry.date + '\t' + entry.service + '\t' + entry.state + '\t' + entry.host
+ if entry.msg != '': log_string += '\t' + entry.msg
+ if entry.data != []: log_string += '\t' + str(entry.data)
+ log.write(log_string + '\n')
+
+# Returns the most recent log object to a given status. None if there is none.
+def getLogEntry(status):
+ # for entry in reversed(logEntries):
+ # if status.host == entry.host and status.service == entry.service: return entry
+ return next((x for x in reversed(logEntries) if (x.host == status.host) and (x.service == status.service)), None)
+
+# Checks weather the status has to be logged or not. (Does the status has changes from the last time?)
+def logStatus(status):
+ obj = getLogEntry(status)
+ if (obj is None) or (status.state != obj.state):
+ date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ logEntries.append(LogEntry(date, status.host, status.service, status.state, status.msg, status.data))
+
+# Parse the logfile.
+parseLog()
+
+# Call the checks.
+https('Masterserver HTTPS Service', 'https://bwlp-masterserver.ruf.uni-freiburg.de')
+ping('Masterserver IP Ping', '132.230.4.16')
+ping('Fileserver Ping', 'files.bwlp.ks.uni-freiburg.de')
+ping('Backup fileserver Ping', 'bwlp-backup.ruf.uni-freiburg.de')
+thrift('Thrift SAT', '132.230.8.192', 9090)
+ping('BAS Ping', 'bas.intra.uni-freiburg.de')
+ping('yc', '127.0.0.2')
+ping('yx', '127.0.0.3')
+
+# Write the new logfile.
+writeLog()
+
+# HTML Processing to generate the website.
+code = '\r\n'
+for status in statusList:
+ # Prepare and calculate the time since the server is online / offline
+ obj = getLogEntry(status)
+ now = datetime.datetime.now()
+ date = datetime.datetime.strptime(obj.date, '%Y-%m-%d %H:%M:%S')
+ time = now - date
+ days = time.days
+ hours = time.seconds // 3600
+ minutes = (time.seconds // 60) % 60
+ timeString = ''
+ if days > 0:
+ timeString += str(days) + ' days '
+ if hours > 0:
+ timeString += str(hours) + ' hours '
+ if minutes > 0:
+ timeString += str(minutes) + ' minutes'
+
+ code += '<div class="content_item"><div class="content_item_part"><div class="content_item_part_title">' + status.name + '</div><div class="content_item_part_subtitle">' + status.host + '</div></div><div class="content_item_part ' + status.state + '"><div class="content_item_part_title">' + status.status + '</div><div class="content_item_part_subtitle">' + timeString + '</div></div></div>\r\n'
+
+# Generate the html code for the log.
+log = '\r\n'
+for entry in reversed(logEntries):
+ log += '<div class="log_item"><div class="log_item_part time"><div class="content_item_part_title">[' + entry.date + ']</div></div><div class="log_item_part service"><div class="content_item_part_title">[' + entry.service + ']</div></div><div class="log_item_part ' + entry.state + '"><div class="content_item_part_title">[' + entry.state + ']</div></div><div class="log_item_part"><div class="content_item_part_title">[' + entry.host +']</div></div><div class="log_item_part"><div class="content_item_part_title">' + entry.msg + '</div></div></div>'
+
+# Copy the .html file and replace the %CONTENT% to generate the final html file.
+shutil.copyfile('bwlpMonitor_template.html', 'bwlpMonitor.html')
+
+# Replace the %CONTENT% in the template with the actual html code.
+html = open('bwlpMonitor_template.html')
+html2 = open('bwlpMonitor.html', 'w')
+for line in html:
+ html2.write(line.replace('%CONTENT%', code).replace('%LOG%', log))
+
+html.close()
+html2.close()
diff --git a/bwlpMonitor_template.html b/bwlpMonitor_template.html
new file mode 100644
index 0000000..e90b251
--- /dev/null
+++ b/bwlpMonitor_template.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="stylesheet" type="text/css" href="style.css">
+ <link rel="icon" type="image/x-icon" href="img/favicon.ico">
+ <title>bwLp Status Monitor</title>
+ </head>
+ <body>
+ <div id="header">
+ <div id="header_left">
+ <a href="">
+ <img id="header_image" src="img/logo_bwlehrpool.png" alt="bwLehrpool">
+ </a>
+ </div>
+ <div id="header_center">
+ <label id="header_label">Status Monitor</label>
+ </div>
+ <div id="header_right">
+ <div>
+ <a href="https://www.bwlehrpool.de/doku.php/start">
+ <img id="header_wiki" src="img/wiki_bwlehrpool.png" alt="bwLehrpool">
+ </a>
+ </div>
+ <a id="header_wiki_label" href="https://www.bwlehrpool.de/doku.php/start">bwlp Wiki</a>
+ </div>
+ </div>
+ <div id="body">
+ <div id="content">
+%CONTENT%
+ </div>
+
+ <div id="log">
+%LOG%
+ </div>
+ </div>
+
+ </body>
+
+</html>
diff --git a/img/favicon.ico b/img/favicon.ico
new file mode 100644
index 0000000..f9a714e
--- /dev/null
+++ b/img/favicon.ico
Binary files differ
diff --git a/img/logo_bwlehrpool.png b/img/logo_bwlehrpool.png
new file mode 100644
index 0000000..b8661a7
--- /dev/null
+++ b/img/logo_bwlehrpool.png
Binary files differ
diff --git a/img/wiki_bwlehrpool.png b/img/wiki_bwlehrpool.png
new file mode 100644
index 0000000..2a00915
--- /dev/null
+++ b/img/wiki_bwlehrpool.png
Binary files differ
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..eaba8a2
--- /dev/null
+++ b/style.css
@@ -0,0 +1,196 @@
+html {
+ background: #ffffff;
+ font: normal 100%/1.4 sans-serif;
+ margin: unset;
+ height: 100%;
+}
+
+body {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: flex-start;
+ margin: unset;
+}
+
+a {
+ color: #137ba9;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #014c8c;
+ !text-decoration: underline;
+}
+
+#header {
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+ justify-content: space-between;
+ white-space: nowrap;
+ background-color: white;
+ height: 60px;
+ position: fixed;
+ box-shadow: 0 2px 4px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) !important;
+}
+
+#header_left {
+ display: flex;
+ flex-direction: row;
+ justify-content: left;
+ align-items: center;
+ width: 228px;
+}
+
+#header_center {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ margin-right: 16px;
+ margin-left: 16px;
+}
+
+#header_right {
+ display: flex;
+ flex-direction: row;
+ justify-content: right;
+ align-items: center;
+ margin-right: 8px;
+ width: 228px;
+}
+
+#header_label {
+ color: #949494;
+ font-size: 50px;
+}
+
+#header_image {
+ width: auto;
+ height: 60px;
+ margin-top: 8px;
+ margin-left: 8px;
+}
+
+#header_wiki_label {
+ display: flex;
+ align-items: center;
+ font-size: 24px;
+ margin-left: 8px;
+ height: 100%;
+}
+
+#body {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ margin-top: 90px;
+ min-height: 300px;
+}
+
+#content {
+ display: flex;
+ flex-direction: column;
+ width: 800px;
+ box-shadow: 0 2px 4px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) !important;
+ background-color: #f5f5f5;
+ overflow: auto;
+ margin-top: 30px;
+ min-height: 150px;
+ flex-shrink: 1;
+}
+
+.content_item {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ justify-items: stretch;
+ align-items: center;
+ min-height: 50px;
+ height: 80px;
+ border-bottom: 1px solid #e2e2e2;
+}
+
+.content_item:hover {
+ background-color: #efeeee;
+}
+
+.content_item_part {
+ height: 100%;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ border-left: 1px solid #e2e2e2;
+ border-right: 1px solid #e2e2e2;
+}
+
+.content_item_part_title {
+}
+
+.content_item_part_subtitle {
+ color: #000;
+ font-size: 10px;
+}
+
+.success {
+ color: #58dc42; !#15e005;
+}
+
+.warning {
+ color: #f6cc5e;
+}
+
+.error {
+ color: #ce2323;
+}
+
+#log {
+ display: flex;
+ flex-direction: column;
+ box-shadow: 0 2px 4px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) !important;
+ background-color: #f5f5f5;
+ min-height: 150px;
+ max-height: 600px;
+ white-space: nowrap;
+ overflow: auto;
+ margin-top: 60px;
+ flex-shrink: 5;
+ margin-bottom: 90px;
+}
+
+.log_item {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ justify-items: stretch;
+ align-items: center;
+ border-bottom: 1px solid #e2e2e2;
+ min-height: 34px;
+ width: 100%;
+}
+
+.log_item_part {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ margin-right: 5px;
+}
+
+.time {
+ color: #40bac8;
+ padding-left: 10px;
+}
+
+.service {
+ color: #2196f3;
+}
+
+.log_item:hover {
+ background-color: #efeeee;
+}