From: Stephen Soltesz Date: Fri, 2 Nov 2007 15:10:25 +0000 (+0000) Subject: www interface and support libraries for some of monitor's data. Specifically: X-Git-Tag: Monitor-1.0-0~60 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=ba6cc9b30b0741e10033a769202047ddeb96f6d1;p=monitor.git www interface and support libraries for some of monitor's data. Specifically: - bad nodes - bad pcus - and actions taken. --- diff --git a/www/printbadnodes.py b/www/printbadnodes.py new file mode 100755 index 0000000..c8bbfcb --- /dev/null +++ b/www/printbadnodes.py @@ -0,0 +1,440 @@ +#!/usr/bin/python +import soltesz +from config import config +from optparse import OptionParser +import string + +import sys + +categories = {} +ssherror = False + +def sec2days(sec): + if sec == "null": + sec = -(60*60*24) + sec = int(sec) + return sec/(60*60*24) + +def array_to_priority_map(array): + """ Create a mapping where each entry of array is given a priority equal + to its position in the array. This is useful for subsequent use in the + cmpMap() function.""" + map = {} + count = 0 + for i in array: + map[i] = count + count += 1 + return map + +def cmpValMap(v1, v2, map): + if v1 in map and v2 in map and map[v1] < map[v2]: + return 1 + elif v1 in map and v2 in map and map[v1] > map[v2]: + return -1 + elif v1 in map and v2 in map: + return 0 + else: + raise Exception("No index %s or %s in map" % (v1, v2)) + +def cmpMap(l1, l2, index, map): + if index in l1 and index in l2: + if map[l1[index]] < map[l2[index]]: + return -1 + elif map[l1[index]] > map[l2[index]]: + return 1 + else: + return 0 + else: + return 0 + +def cmpLoginBase(l1, l2): + #print "'" + l1['loginbase'] + "'" + " < " + "'" + l2['loginbase'] + "'" + "
" + if l1['loginbase'] == l2['loginbase']: + return 0 + elif l1['loginbase'] < l2['loginbase']: + return -1 + elif l1['loginbase'] > l2['loginbase']: + return 1 + else: + return 0 + +def cmpState(l1, l2): + map = array_to_priority_map([ 'BOOT', 'DEBUG', 'DOWN' ]) + return cmpMap(l1,l2,'state', map) + +def cmpCategoryVal(v1, v2): + map = array_to_priority_map([ None, 'ALPHA', 'PROD', 'OLDBOOTCD', 'UNKNOWN', 'ERROR', ]) + return cmpValMap(v1,v2,map) + +def cmpCategory(l1, l2): + map = array_to_priority_map([ 'ALPHA', 'PROD', 'OLDBOOTCD', 'UNKNOWN', 'ERROR', ]) + return cmpMap(l1,l2,'category', map) + +def cmpPCU(l1, l2): + """ Either PCU or NOPCU""" + map = array_to_priority_map([ 'PCU', 'NOPCU', 'UNKNOWN']) + return cmpMap(l1, l2, 'pcu', map) + +def cmpSSH(l1, l2): + """ Either SSH or NOSSH """ + map = array_to_priority_map([ 'SSH', 'NOSSH']) + return cmpMap(l1, l2, 'ssh', map) + +def cmpDNS(l1,l2): + """ Compare DNS states """ + map = array_to_priority_map([ 'OK', 'NOHOSTNAME', 'NOENTRY', 'MISMATCH']) + return cmpMap(l1, l2, 'dnsmatch', map) + +def cmpPing(l1,l2): + """ Either PING or NOPING """ + map = array_to_priority_map([ 'PING', 'NOPING']) + return cmpMap(l1, l2, 'ping', map) + +def cmpUname(l1, l2): + # Extract the kernel version from kernel -a string + l_k1 = l1['kernel'].split() + if len(l_k1) > 2: + k1 = l_k1[2] + else: + return 1 + + l_k2 = l2['kernel'].split() + if len(l_k2) > 2: + k2 = l_k2[2] + else: + return -1 + + return cmp(k1, k2) + +def cmpDays(l1, l2): + if l1['comonstats'][config.comon] == "null": + l1['comonstats'][config.comon] = -1 + if l2['comonstats'][config.comon] == "null": + l2['comonstats'][config.comon] = -1 + + if int(l1['comonstats'][config.comon]) > int(l2['comonstats'][config.comon]): + return -1 + elif int(l1['comonstats'][config.comon]) < int(l2['comonstats'][config.comon]): + return 1 + else: + return 0 + +def ssh_error_to_str(str): + ssh_error = "" + if "Connection timed out" in str: + ssh_error = "Timeout" + elif "Connection closed by remote host" in str: + ssh_error = "Closed by remote host" + elif "Connection refused" in str: + ssh_error = "Connection refused" + elif "Temporary failure in name resolution" in str: + ssh_error = "Could not resolve name" + elif "Name or service not known" in str: + ssh_error = "Name not known" + elif "Too many authentication failures" in str: + ssh_error = "Disconnect: root auth failure" + elif "Network is unreachable" in str: + ssh_error = "Network is unreachable" + elif "Connection reset by peer" in str: + ssh_error = "Connection reset by peer" + elif "WARNING" in str: + ssh_error = "WARNING ssh key updated" + else: + ssh_error = str + + return ssh_error + +def fields_to_html(fields, vals): + global categories + global ssherror + colorMap = { 'PING' : 'darkseagreen', + 'NOPING': 'darksalmon', + 'SSH': 'darkseagreen', + 'NOSSH': 'indianred', + 'PCU': 'darkseagreen', + 'NOPCU': 'lightgrey', + 'OLDBOOTCD': 'crimson', + 'DOWN': 'indianred', + 'ALPHA': 'gold', + 'ERROR': 'crimson', + 'PROD': 'darkseagreen', + 'DEBUG': 'darksalmon', + 'DEBUG': 'darksalmon', + 'BOOT': 'lightgreen'} + r_str = "" + f_prev = "" + f_2prev = "" + #print 'inside--------------' + for f in fields: + f = f.strip() + #print f + + if f in ['DOWN', 'BOOT', 'DEBUG']: + #key = "%s-%s-%s" % (f,f_prev,f_2prev) + key = "%s-%s" % (f,f_prev) + if key not in categories: + categories[key] = 1 + else: + categories[key] += 1 + + #print "
%s

" % f + + if f in colorMap: + bgcolor="bgcolor='%s'" % colorMap[f] + else: + bgcolor="" + + if f == 'NOSSH': + if ssherror: + if 'ssherror' in vals: + str_ssh_error = ssh_error_to_str(vals['ssherror']) + else: + str_ssh_error = "NO SSHERROR in VALS" + if str_ssh_error != "Timeout": + r_str += """%s
%s""" % \ + (bgcolor,f,str_ssh_error) + else: + r_str += "%s" % (bgcolor, f) + else: + r_str += "%s" % (bgcolor, f) + elif f == 'PCU': + if len(vals['plcnode']['pcu_ids']) > 0: + url = "PCU" % vals['plcnode']['pcu_ids'][0] + r_str += "%s" % (bgcolor, url) + else: + r_str += "%s" % (bgcolor, f) + f_2prev = f_prev + f_prev = f + + return r_str + + + +def main(sitefilter): + db = soltesz.dbLoad(config.dbname) + + ## Field widths used for printing + maxFieldLengths = { 'nodename' : -45, + 'ping' : 6, + 'ssh' : 6, + 'pcu' : 7, + 'category' : 9, + 'state' : 5, + 'kernel' : 10.65, + 'comonstats' : 5, + 'plcsite' : 12, + 'bootcd' : 10.65} + ## create format string based on config.fields + fields = {} + format = "" + format_fields = [] + for f in config.fields.split(','): + fields[f] = "%%(%s)s" % f + #if f in maxFieldLengths: + # fields[f] = "%%(%s)%ds" % (f, maxFieldLengths[f]) + #else: + # fields[f] = "%%(%s)%ds" % (f, 10) + + format_fields.append(fields[f]) + #print fields + for f in config.fields.split(','): + format += fields[f] + " " + #print format + + d_n = db['nodes'] + l_nodes = d_n.keys() + + # category by site + #bysite = {} + #for nodename in l_nodes: + # if 'plcsite' in d_n[nodename]['values'] and \ + # 'login_base' in d_n[nodename]['values']['plcsite']: + # loginbase = d_n[nodename]['values']['plcsite']['login_base'] + # if loginbase not in bysite: + # bysite[loginbase] = [] + # d_n[nodename]['values']['nodename'] = nodename + # bysite[loginbase].append(d_n[nodename]['values']) + + # d2 was an array of [{node}, {}, ...] + # the bysite is a loginbase dict of [{node}, {node}] + d2 = [] + for nodename in l_nodes: + vals=d_n[nodename]['values'] + v = {} + v.update(vals) + v['nodename'] = nodename + if 'plcsite' in vals and \ + 'status' in vals['plcsite'] and \ + vals['plcsite']['status'] == "SUCCESS": + + url = "%s" % ( vals['plcsite']['login_base'], + vals['plcsite']['login_base']) + + site_string = "%s %2s nodes :: %2s of %4s slices" % ( \ + url, + vals['plcsite']['num_nodes'], + vals['plcsite']['num_slices'], + vals['plcsite']['max_slices']) + loginbase = d_n[nodename]['values']['plcsite']['login_base'] + else: + #print "ERROR: ", nodename, vals, "
" + site_string = "UNKNOWN" + loginbase = "" + + v['site_string'] = site_string + v['loginbase'] = loginbase + if (sitefilter != None and loginbase == sitefilter) or sitefilter == None: + d2.append(v) + + + if sitefilter != None: + config.cmpcategory = True + else: + config.cmploginbase = True + + + if config.cmploginbase: + d2.sort(cmp=cmpLoginBase) + elif config.cmpping: + d2.sort(cmp=cmpPing) + elif config.cmpdns: + d2.sort(cmp=cmpDNS) + elif config.cmpssh: + d2.sort(cmp=cmpSSH) + elif config.cmpcategory: + d2.sort(cmp=cmpCategory) + elif config.cmpstate: + d2.sort(cmp=cmpState) + elif config.cmpdays: + d2.sort(cmp=cmpDays) + elif config.cmpkernel: + d2.sort(cmp=cmpUname) + else: + d2.sort(cmp=cmpCategory) + + + #l_loginbase = bysite.keys() + #l_loginbase.sort() + print "" + prev_sitestring = "" + for row in d2: + + site_string = row['site_string'] + if site_string != prev_sitestring: + print "" + else: + print "" + + prev_sitestring = site_string + + vals = row + # convert uname values into a single kernel version string + if 'kernel' in vals: + kernel = vals['kernel'].split() + if len(kernel) > 0: + if kernel[0] == "Linux": + vals['kernel'] = kernel[2] + else: + vals['ssherror'] = vals['kernel'] + vals['kernel'] = "" + else: + vals['ssherror'] = "" + vals['kernel'] = "" +# continue + if 'model' in vals or 'protocol' in vals or 'portstatus' in vals: + #vals['model'] = string.replace(vals['model']," ", " ") + #vals['protocol'] = vals['protocol'].replace(" ", " ") + if vals['model'] == None: + vals['model'] = " " + vals['model'] = string.replace(vals['model']," ", "_") + vals['protocol'] = vals['protocol'].replace(" ", "_") + ps = "" + ports = vals['portstatus'] + lports = ports.keys() + lports.sort() + for port in lports: + t = ports[port] + if t != "closed": + ps += "%s: %s
" % (port, ports[port]) + if ps == "": + ps = "All_closed" + + vals['portstatus'] = ps + + if 'reboot' in vals: + vals['reboot'] = "%s" % vals['reboot'] + vals['reboot'] = vals['reboot'].replace(" ", "_") + + try: + str_fields = [] + count = 0 + for f in format_fields: + str_fields.append(f % vals) + count += 1 + except: + print >>sys.stderr, vals + + s = fields_to_html(str_fields, vals) + print s + + print "\n" + + print "
" + print site_string + print "
 
" + print "" + keys = categories.keys() + keys.sort() + for cat in keys: + print "" + print "" % cat + print "" % categories[cat] + print "" + print "
Total %s%s
" + +import cgi +import cgitb; +cgitb.enable() +import sys + +form = cgi.FieldStorage() +myfilter = None + +if form.has_key('site'): + myfilter = form.getvalue("site") +else: + myfilter = None + + +if __name__ == '__main__': + parser = OptionParser() + parser.set_defaults(cmpdays=False, + comon="sshstatus", + fields="nodename,ping,ssh,pcu,category,state,kernel,bootcd", + dbname="findbad", # -070724-1", + cmpping=False, + cmpdns=False, + cmploginbase=False, + cmpssh=False, + cmpcategory=False, + cmpstate=False) + parser.add_option("", "--fields", dest="fields", help="") + parser.add_option("", "--dbname", dest="dbname", help="") + parser.add_option("", "--days", dest="cmpdays", action="store_true", help="") + parser.add_option("", "--ping", dest="cmpping", action="store_true", help="") + parser.add_option("", "--dns", dest="cmpdns", action="store_true", help="") + parser.add_option("", "--ssh", dest="cmpssh", action="store_true", help="") + parser.add_option("", "--loginbase",dest="cmploginbase",action="store_true", help="") + parser.add_option("", "--category", dest="cmpcategory", action="store_true", help="") + parser.add_option("", "--kernel", dest="cmpkernel", action="store_true", help="") + parser.add_option("", "--state", dest="cmpstate", action="store_true", help="") + parser.add_option("", "--comon", dest="comon", help="") + config = config(parser) + config.parse_args() + print "Content-Type: text/html\r\n" + print "\n" + if len(sys.argv) > 1: + if sys.argv[1] == "ssherror": + ssherror = True + main(myfilter) + print "\n" diff --git a/www/printbadpcus.php b/www/printbadpcus.php new file mode 100644 index 0000000..fb86fa3 --- /dev/null +++ b/www/printbadpcus.php @@ -0,0 +1,234 @@ + 0 ) { + return join("
", $pcu['complete_entry']); + } else { + return " "; + } +} + +function format_ports($pcu) +{ + $str = ""; + #print print_r(is_array($pcu)) . "
"; + #print print_r(array_key_exists('portstatus', $pcu)) . "
"; + if ( is_array($pcu) && array_key_exists('portstatus', $pcu) ) + { + $portstat = $pcu['portstatus']; + + #foreach ( array('22', '23', '80', '443') $portstat as $port => $state) + foreach ( array('22', '23', '80', '443') as $port) + { + $state = $portstat[$port]; + switch ($state) + { + case "open": + $color = "lightgreen"; + break; + case "filtered": + $color = "gold"; + break; + case "closed": + $color = "indianred"; + break; + default: + $color = "white"; + break; + } + $str .= "$port "; + # . ": " . $state . "
"; + } + } else { + # print print_r(is_array($pcu)) . "
"; + # print print_r(array_key_exists('portstatus', $pcu)) . "
"; + #echo "
";
+		#print_r($pcu['portstatus']);
+		#echo "
"; + } + if ( $str == "" ) + { + $str = "Closed/Filtered"; + } + return $str; +} +function DNS_to_color($dns) +{ + switch ($dns) + { + case "DNS-OK": + return 'lightgreen'; + case "NOHOSTNAME": + return 'white'; + case "DNS-MISMATCH": + return 'gold'; + case "NO-DNS-OR-IP": + case "DNS-NOENTRY": + return 'indianred'; + } + return 'white'; +} + +function reboot_to_color($reboot) +{ + switch ($reboot) + { + case "0": + return "darkseagreen"; + break; + case "NetDown": + return "lightgrey"; + break; + case "Not_Run": + return "lightgrey"; + break; + case "Unsupported_PCU": + return "indianred"; + break; + default: + if ( strpos($reboot, "error") >= 0) + { + return "indianred"; + } else { + return 'white'; + } + break; + } + return "white"; +} + +function get_pcuid($pcu) { return $pcu['pcu_id']; } +function get_dns($pcu) { return $pcu['dnsmatch']; } +function get_dryrun($pcu) { return $pcu['reboot']; } +function get_model($pcu) { return $pcu['model']; } +function get_category_link($category,$header) +{ + return "$header"; +} + +include 'soltesz.php'; +$p = new Pickle(); +$findbad = $p->load("findbadpcus"); +$findbadpcus = array_keys($findbad['nodes']); + +$pculist = array(); +$c = 0; +foreach ( $findbadpcus as $pcu_id ) +{ + if ( is_array($findbad['nodes'][$pcu_id]) ) + { + #if ( in_array('values', $findbad['nodes'][$pcu]) ) + #{ + # echo $pcu . " true
"; + #} else{ + # echo $pcu . " false
"; + #} + if ( array_key_exists('values', $findbad['nodes'][$pcu_id]) ) + { + $pculist[] = $findbad['nodes'][$pcu_id]['values']; + } + } +} +$total = count($pculist); + + +## Sort the pculist + +#$pcu_ids = array_map('get_pcuid', $pculist); +#array_multisort($pcu_ids, SORT_ASC, SORT_NUMERIC, $pculist); + +#$dns_ids = array_map('get_dns', $pculist); +#array_multisort($dns_ids, SORT_ASC, SORT_STRING, $pculist); + +#$dry_ids = array_map('get_dryrun', $pculist); +#array_multisort($dry_ids, SORT_ASC, SORT_STRING, $pculist); +if ( $_GET['category'] ) +{ + $category = $_GET['category']; + if ( $category == "node_ids" ) + { + $newfunc = create_function('$pcu', 'return count($pcu[\'' . $category . '\']);'); + } else { + $newfunc = create_function('$pcu', 'return $pcu[\'' . $category . '\'];'); + } + if ( $newfunc != "" ) + { + $fields = array_map($newfunc, $pculist); + array_multisort($fields, SORT_ASC, SORT_STRING, $pculist); + } else { + echo "ERROR create_function == null
"; + } +} + +if ( $_GET['auth'] ) +{ + $auth = True; +} else { + $auth = False; +} + + +//array_multisort($protocols, SORT_ASC, SORT_STRING, $pculist); +?> + +PLC PCU Info + + + +Total PCUs : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CountUsernamePasswordNotes
'>'>'>
+ + + diff --git a/www/siteactions.cgi b/www/siteactions.cgi new file mode 100755 index 0000000..425e468 --- /dev/null +++ b/www/siteactions.cgi @@ -0,0 +1,145 @@ +#!/usr/bin/python + +# Read in the act_* databases and print out a human readable version + +import sys +import time +import getopt +import soltesz + + +def fields_to_html(fields): + colorMap = { 'PING' : 'darkseagreen', + 'NOPING': 'darksalmon', + 'SSH': 'darkseagreen', + 'NOSSH': 'indianred', + 'PCU': 'darkseagreen', + 'NOPCU': 'lightgrey', + 'OLDBOOTCD': 'crimson', + 'DOWN': 'indianred', + 'ALPHA': 'gold', + 'ERROR': 'crimson', + 'PROD': 'darkseagreen', + 'DEBUG': 'darksalmon', + 'DEBUG': 'darksalmon', + 'BOOT': 'lightgreen'} + r_str = "" + for f in fields: + if f in colorMap: + bgcolor="bgcolor='%s'" % colorMap[f] + else: + bgcolor="" + r_str += "%s" % (bgcolor, f) + + return r_str + +def rtTicketLink(rt_ticket): + link = """RT #%s""" % (rt_ticket, rt_ticket) + return link + +def main(): + + total_sites = 0 + total_nodes = 0 + total_restored = 0 + total_down = 0 + + act_all = soltesz.dbLoad("act_all") + plcdb_hn2lb = soltesz.dbLoad("plcdb_hn2lb") + s_nodenames = "" + sickdb = {} + + sorted_keys = act_all.keys() + sorted_keys.sort() + for nodename in sorted_keys: + diag_nodelist = act_all[nodename] + if nodename in plcdb_hn2lb: + lb = plcdb_hn2lb[nodename] + if lb not in sickdb: + sickdb[lb] = {} + sickdb[lb][nodename] = diag_nodelist + + sorted_keys = sickdb.keys() + sorted_keys.sort() + print "" + for loginbase in sorted_keys: + nodedict = sickdb[loginbase] + sort_nodekeys = nodedict.keys() + sort_nodekeys.sort() + print "", + print "" + total_sites += 1 + for nodename in sort_nodekeys: + total_nodes += 1 + if len(act_all[nodename]) == 0: + #print "" % (nodename) + #print "" + continue + else: + # print just the latest event + event = act_all[nodename][0] + fields = [] + fields += [nodename] + if 'time' in event: + s_time=time.strftime("%Y/%m/%d %H:%M:%S", + time.gmtime(event['time'])) + fields += [s_time] + if 'ticket_id' in event and event['ticket_id'] != "": + link = rtTicketLink(event['ticket_id']) + fields += [link] + else: + if 'found_rt_ticket' in event and event['found_rt_ticket'] != "": + link = rtTicketLink(event['found_rt_ticket']) + fields += [link] + else: + fields += ["No Known RT Ticket"] + + if event['action'] == "close_rt": + total_restored += 1 + else: + total_down += 1 + + for f in ['category', 'action', 'stage', 'info']: + if 'stage' in f and 'stage' in event and 'stage' in event['stage']: + # truncate the stage_ part. + event['stage'] = event['stage'][6:] + if f in event: + if type(event[f]) == type([]): + fields += event[f] + else: + fields += [event[f]] + else: + fields += [" "] + + print "", + print fields_to_html(fields), + print "" + + print "
", + print loginbase, + print " 
%shas no events
" + print "" + print "" + print "" + print "" + print "" + print "" + print "" + + print "" + print "" % total_sites + print "" % total_nodes + print "" % total_restored + print "" % total_down + + print "" + print "
SitesNodesRestoredDown
%s%s%s%s
" + + print s_nodenames + + +if __name__ == '__main__': + print "Content-Type: text/html\r\n" + print "\n" + main() + print "\n" diff --git a/www/soltesz.php b/www/soltesz.php new file mode 100644 index 0000000..bef3e03 --- /dev/null +++ b/www/soltesz.php @@ -0,0 +1,67 @@ + +exists("production." . $name) ) + { + print "Exception: No such file %s" . $name . "\n"; + return NULL; + } + $name = "production." . $name; + $fname = $this->__file($name); + $o = unserialize(file_get_contents($fname)); + + return $o; + } + public function dump($name, $obj) + { + if ( ! file_exists(PICKLE_PATH) ) + { + if ( ! mkdir(PICKLE_PATH, 0777, True) ) + { + print "Exception: Unable to create directory :" . PICKLE_PATH . "\n"; + } + } + $name = "production." . $name; + $fname = $this->__file($name); + + return file_put_contents($fname, serialize($obj)); + } + private function __file($name) + { + return sprintf("%s/%s.phpserial", PICKLE_PATH, $name); + } + + public function exists($name) + { + return file_exists($this->__file($name)); + } + + public function remove($name) + { + return unlink($this->__file($name)); + } + + public function if_cached_else($cond, $name, $function) + { + if ( $cond and $this->exists("production.%s" % $name) ) + { + $o = $this->load($name); + } else { + $o = $function(); + if ($cond) + { + $this->dump($name, $o); # cache the object using 'name' + } + } + return o; + } +} + +?>