#!/usr/bin/python3 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, service, state, host, 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 ' + hostname + ' ... ', 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('\033[91m' + 'error' + '\033[0m') statusList.append(Status(name, hostname, 'error', 'Offline', 'ping', error.rstrip())) else: print('\033[92m' + 'success' + '\033[0m') statusList.append(Status(name, hostname, 'success', 'Online', 'ping')) logStatus(statusList[-1]) def https(name, url): print('HTTPS request ' + url + ' ... ', end='') try: r = urllib.request.urlopen(url) if r.getcode() == 200: statusList.append(Status(name, url, 'success', 'Online', 'https')) print('\033[92m' + 'success' + '\033[0m') else: statusList.append(Status(name, url, 'error', 'Offline', 'https')) print('\033[91m' + 'error' + '\033[0m') except urllib.error.URLError as e: statusList.append(Status(name, url, 'error', 'Offline', 'https', msg=str(e))) print('\033[91m' + 'error' + '\033[0m') except ValueError: statusList.append(Status(name, url, 'error', 'Offline', 'https', msg="Unknown url type")) print('\033[91m' + 'error' + '\033[0m') finally: logStatus(statusList[-1]) def mysql(self, host, user, passwd, db): pass # TODO: Backend to check the mysql status needs to be implemented. # 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]) # Creates the thrift client and proceeds the get Organisations call. Server can either be SAT or MASTER def thrift(name, ip, port, server): host = ip + ':' + str(port) print('THRIFT request ' + host + ' ...', end='') bwlp_thrift = thriftpy.load('bwlp.thrift', module_name='bwlp_thrift') organisations = [] # Different clients for SAT / Master is needed. # TODO: TRY CATCH try: if server is 'SAT': satserver = make_client(bwlp_thrift.SatelliteServer, ip, port, trans_factory=TFramedTransportFactory()) organisations = satserver.getAllOrganizations() elif server is 'MASTER': masterserver = make_client(bwlp_thrift.MasterServer, ip, port, trans_factory=TFramedTransportFactory()) organisations = masterserver.getOrganizations() organisationList = [] for org in organisations: organisationList.append(Organisation(org.organizationId, org.displayName)) statusList.append(Status(name, host, 'success', 'Online (' + str(len(organisationList)) + ')', 'thrift', msg=str(len(organisationList)) + " organizations",data=organisationList)) print('\033[92m' + 'success' + '\033[0m') #logStatus(statusList[-1]) except ConnectionResetError: statusList.append(Status(name, host, 'error', 'Offline', 'thrift', msg="ConnectionResetError: [Errno 104] Connection reset by peer")) print('\033[91m' + 'error' + '\033[0m') # statusList.append(Status(name, host, 'error', 'Offline', 'thrift', msg=str(e))) finally: 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 log_string += '\t' + str(entry.msg) 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) # print(status.host + " " + status.service + " " + status.state) 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.service, status.state, status.host, status.msg, status.data)) # Parse the logfile. parseLog() # Call the checks. https('Masterserver HTTPS Service', 'https://bwlp-masterserver.ruf.uni-freiburg.de') https('Fail Test', '5121236') https('Fail Test', 'https://www.amazony.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') ping('Ping Fail', '0.0.0.1') thrift('Thrift SAT', '132.230.8.192', 9090, 'SAT') thrift('Thrift MASTER', '132.230.4.16', 9090, 'MASTER') thrift('Thrift MASTER', '132.230.4.16', 9091, 'MASTER') 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 += ('
' + status.name + '
' + status.host + '
' + status.status + '
' + timeString + '
\r\n') # Generate the html code for the log. log = '\r\n' for entry in reversed(logEntries): log += ('
[' + entry.date + ']
[' + entry.service + ']
[' + entry.state + ']
[' + entry.host +']
' + entry.msg + '
') # 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()