3 from config import config
4 from optparse import OptionParser
6 #from HyperText.HTML import A, BR, IMG, TABLE, TR, TH, TD, EM, quote_body
7 #from HyperText.Documents import Document
21 def array_to_priority_map(array):
22 """ Create a mapping where each entry of array is given a priority equal
23 to its position in the array. This is useful for subsequent use in the
32 def cmpValMap(v1, v2, map):
33 if v1 in map and v2 in map and map[v1] < map[v2]:
35 elif v1 in map and v2 in map and map[v1] > map[v2]:
37 elif v1 in map and v2 in map:
40 raise Exception("No index %s or %s in map" % (v1, v2))
42 def cmpMap(l1, l2, index, map):
43 if index in l1 and index in l2:
44 if map[l1[index]] < map[l2[index]]:
46 elif map[l1[index]] > map[l2[index]]:
53 def cmpLoginBase(l1, l2):
54 #print "'" + l1['loginbase'] + "'" + " < " + "'" + l2['loginbase'] + "'" + "<BR>"
55 if l1['loginbase'] == l2['loginbase']:
57 elif l1['loginbase'] < l2['loginbase']:
59 elif l1['loginbase'] > l2['loginbase']:
65 map = array_to_priority_map([ 'BOOT', 'DEBUG', 'DOWN' ])
66 return cmpMap(l1,l2,'state', map)
68 def cmpCategoryVal(v1, v2):
69 map = array_to_priority_map([ None, 'ALPHA', 'PROD', 'OLDBOOTCD', 'UNKNOWN', 'FORCED', 'ERROR', ])
70 return cmpValMap(v1,v2,map)
72 def cmpCategory(l1, l2):
73 map = array_to_priority_map([ 'ALPHA', 'PROD', 'OLDBOOTCD', 'UNKNOWN', 'ERROR', ])
74 return cmpMap(l1,l2,'category', map)
77 """ Either PCU or NOPCU"""
78 map = array_to_priority_map([ 'PCU', 'NOPCU', 'UNKNOWN'])
79 return cmpMap(l1, l2, 'pcu', map)
82 """ Either SSH or NOSSH """
83 map = array_to_priority_map([ 'SSH', 'NOSSH'])
84 return cmpMap(l1, l2, 'ssh', map)
87 """ Compare DNS states """
88 map = array_to_priority_map([ 'OK', 'NOHOSTNAME', 'NOENTRY', 'MISMATCH'])
89 return cmpMap(l1, l2, 'dnsmatch', map)
92 """ Either PING or NOPING """
93 map = array_to_priority_map([ 'PING', 'NOPING'])
94 return cmpMap(l1, l2, 'ping', map)
97 # Extract the kernel version from kernel -a string
98 l_k1 = l1['kernel'].split()
104 l_k2 = l2['kernel'].split()
113 if l1['comonstats'][config.comon] == "null":
114 l1['comonstats'][config.comon] = -1
115 if l2['comonstats'][config.comon] == "null":
116 l2['comonstats'][config.comon] = -1
118 if int(l1['comonstats'][config.comon]) > int(l2['comonstats'][config.comon]):
120 elif int(l1['comonstats'][config.comon]) < int(l2['comonstats'][config.comon]):
125 def ssh_error_to_str(str):
127 if "Connection timed out" in str:
128 ssh_error = "Timeout"
129 elif "Connection closed by remote host" in str:
130 ssh_error = "Closed by remote host"
131 elif "Connection refused" in str:
132 ssh_error = "Connection refused"
133 elif "Temporary failure in name resolution" in str:
134 ssh_error = "Could not resolve name"
135 elif "Name or service not known" in str:
136 ssh_error = "Name not known"
137 elif "Too many authentication failures" in str:
138 ssh_error = "Disconnect: root auth failure"
139 elif "Network is unreachable" in str:
140 ssh_error = "Network is unreachable"
141 elif "Connection reset by peer" in str:
142 ssh_error = "Connection reset by peer"
143 elif "WARNING" in str:
144 ssh_error = "WARNING ssh key updated"
150 def pcu_state(pcu_id):
153 if 'nodes' in fb and "id_%s" % pcu_id in fb['nodes'] \
154 and 'values' in fb['nodes']["id_%s" % pcu_id]:
155 rec = fb['nodes']["id_%s" % pcu_id]['values']
158 if rb == 0 or rb == "0":
160 elif "NetDown" == rb or "Not_Run" == rb:
169 def fields_to_html(fields, vals):
172 pcu_colorMap = { -1 : 'indianred',
176 colorMap = { 'PING' : 'darkseagreen',
177 'NOPING': 'darksalmon',
178 'SSH': 'darkseagreen',
179 'NOSSH': 'indianred',
180 'PCU': 'darkseagreen',
181 'NOPCU': 'lightgrey',
182 'OLDBOOTCD': 'crimson',
186 'PROD': 'darkseagreen',
187 'DEBUG': 'darksalmon',
188 'DEBUG': 'darksalmon',
189 'BOOT': 'lightgreen'}
193 #print 'inside--------------'
198 if f in ['DOWN', 'BOOT', 'DEBUG']:
199 #key = "%s-%s-%s" % (f,f_prev,f_2prev)
200 key = "%s-%s" % (f,f_prev)
201 if key not in categories:
206 #print "<pre>%s</pre><br>" % f
209 bgcolor="bgcolor='%s'" % colorMap[f]
215 if 'ssherror' in vals:
216 str_ssh_error = ssh_error_to_str(vals['ssherror'])
218 str_ssh_error = "NO SSHERROR in VALS"
219 if str_ssh_error != "Timeout":
220 r_str += """<td nowrap %s>%s<br><b><font size="-2">%s</font></b></td>""" % \
221 (bgcolor,f,str_ssh_error)
223 r_str += "<td %s>%s</td>" % (bgcolor, f)
225 r_str += "<td %s>%s</td>" % (bgcolor, f)
227 if len(vals['plcnode']['pcu_ids']) > 0:
228 #print "pcu_id: %s<br>" % vals['plcnode']['pcu_ids'][0]
229 #print "state: %s<br>" % pcu_state(vals['plcnode']['pcu_ids'][0])
230 #print "color: %s<br>" % pcu_colorMap[pcu_state(vals['plcnode']['pcu_ids'][0])]
231 bgcolor = "bgcolor='%s'" % pcu_colorMap[pcu_state(vals['plcnode']['pcu_ids'][0])]
232 url = "<a href='/cgi-bin/printbadpcus.php#id%s'>PCU</a>" % vals['plcnode']['pcu_ids'][0]
233 r_str += "<td nowrap %s>%s</td>" % (bgcolor, url)
235 r_str += "<td nowrap %s>%s</td>" % (bgcolor, f)
243 def main(sitefilter, catfilter, statefilter, comonfilter, nodeonlyfilter):
246 db = soltesz.dbLoad(config.dbname)
247 fb = soltesz.dbLoad("findbadpcus")
249 ## Field widths used for printing
250 maxFieldLengths = { 'nodename' : -45,
260 ## create format string based on config.fields
264 for f in config.fields.split(','):
265 fields[f] = "%%(%s)s" % f
266 #if f in maxFieldLengths:
267 # fields[f] = "%%(%s)%ds" % (f, maxFieldLengths[f])
269 # fields[f] = "%%(%s)%ds" % (f, 10)
271 format_fields.append(fields[f])
273 for f in config.fields.split(','):
274 format += fields[f] + " "
282 #for nodename in l_nodes:
283 # if 'plcsite' in d_n[nodename]['values'] and \
284 # 'login_base' in d_n[nodename]['values']['plcsite']:
285 # loginbase = d_n[nodename]['values']['plcsite']['login_base']
286 # if loginbase not in bysite:
287 # bysite[loginbase] = []
288 # d_n[nodename]['values']['nodename'] = nodename
289 # bysite[loginbase].append(d_n[nodename]['values'])
291 # d2 was an array of [{node}, {}, ...]
292 # the bysite is a loginbase dict of [{node}, {node}]
295 if sitefilter != None:
296 sf = re.compile(sitefilter)
299 for nodename in l_nodes:
300 vals=d_n[nodename]['values']
303 v['nodename'] = nodename
304 if 'plcsite' in vals and \
305 'status' in vals['plcsite'] and \
306 vals['plcsite']['status'] == "SUCCESS":
308 url = "<a href='printbadnodes.py?site=%s'>%s</a>" % ( vals['plcsite']['login_base'],
309 vals['plcsite']['login_base'])
311 site_string = "%s %2s nodes :: %2s of %4s slices" % ( \
313 vals['plcsite']['num_nodes'],
314 vals['plcsite']['num_slices'],
315 vals['plcsite']['max_slices'])
316 loginbase = d_n[nodename]['values']['plcsite']['login_base']
318 #print "ERROR: ", nodename, vals, "<br>"
319 site_string = "<b>UNKNOWN</b>"
322 v['site_string'] = site_string
323 v['loginbase'] = loginbase
324 if (sitefilter != None and sf.match(loginbase) != None) or sitefilter == None:
328 if sitefilter != None:
329 config.cmpcategory = True
331 config.cmploginbase = True
334 if config.cmploginbase:
335 d2.sort(cmp=cmpLoginBase)
342 elif config.cmpcategory:
343 d2.sort(cmp=cmpCategory)
344 elif config.cmpstate:
345 d2.sort(cmp=cmpState)
348 elif config.cmpkernel:
349 d2.sort(cmp=cmpUname)
351 d2.sort(cmp=cmpCategory)
354 if catfilter != None: cf = re.compile(catfilter)
357 if statefilter != None: stf = re.compile(statefilter)
360 if comonfilter != None: cmf = re.compile(comonfilter)
363 #l_loginbase = bysite.keys()
365 if nodeonlyfilter == None:
366 print "<table width=80% border=1>"
373 if (catfilter != None and cf.match(vals['category']) == None):
376 if (statefilter != None and stf.match(vals['state']) == None):
379 if (comonfilter != None and comonfilter in vals['comonstats'] and vals['comonstats'][comonfilter] != 'null'):
382 if nodeonlyfilter != None:
383 print vals['nodename']
386 site_string = row['site_string']
387 if site_string != prev_sitestring:
388 print "<tr><td bgcolor=lightblue nowrap>"
392 print "<tr><td> </td>"
394 prev_sitestring = site_string
397 # convert uname values into a single kernel version string
399 kernel = vals['kernel'].split()
401 if kernel[0] == "Linux":
402 vals['kernel'] = kernel[2]
404 vals['ssherror'] = vals['kernel']
407 vals['ssherror'] = ""
410 if 'model' in vals or 'protocol' in vals or 'portstatus' in vals:
411 #vals['model'] = string.replace(vals['model']," ", " ")
412 #vals['protocol'] = vals['protocol'].replace(" ", " ")
413 if vals['model'] == None:
415 vals['model'] = string.replace(vals['model']," ", "_")
416 vals['protocol'] = vals['protocol'].replace(" ", "_")
418 ports = vals['portstatus']
419 lports = ports.keys()
424 ps += "%s: %s<br>" % (port, ports[port])
428 vals['portstatus'] = ps
431 vals['reboot'] = "%s" % vals['reboot']
432 vals['reboot'] = vals['reboot'].replace(" ", "_")
434 if 'nodename' in vals:
435 url = "<a href='https://www.planet-lab.org/db/nodes/index.php?nodepattern=%s'>%s</a>" % (vals['nodename'], vals['nodename'])
436 vals['nodename'] = url
441 for f in format_fields:
442 str_fields.append(f % vals)
445 print >>sys.stderr, vals
447 s = fields_to_html(str_fields, vals)
452 if nodeonlyfilter == None:
455 keys = categories.keys()
459 print "<th nowrap align=left>Total %s</th>" % cat
460 print "<td align=left>%s</td>" % categories[cat]
462 if nodeonlyfilter == None:
467 if __name__ == '__main__':
473 form = cgi.FieldStorage()
476 if form.has_key('site'):
477 myfilter = form.getvalue("site")
481 if form.has_key('category'):
482 mycategory = form.getvalue("category")
486 if form.has_key('state'):
487 mystate = form.getvalue("state")
491 if form.has_key('comon'):
492 mycomon = form.getvalue("comon")
496 if form.has_key('nodeonly'):
497 mynodeonly = form.getvalue("nodeonly")
501 parser = OptionParser()
502 parser.set_defaults(cmpdays=False,
504 fields="nodename,ping,ssh,pcu,category,state,comonstats,kernel,bootcd",
505 dbname="findbad", # -070724-1",
512 parser.add_option("", "--fields", dest="fields", help="")
513 parser.add_option("", "--dbname", dest="dbname", help="")
514 parser.add_option("", "--days", dest="cmpdays", action="store_true", help="")
515 parser.add_option("", "--ping", dest="cmpping", action="store_true", help="")
516 parser.add_option("", "--dns", dest="cmpdns", action="store_true", help="")
517 parser.add_option("", "--ssh", dest="cmpssh", action="store_true", help="")
518 parser.add_option("", "--loginbase",dest="cmploginbase",action="store_true", help="")
519 parser.add_option("", "--category", dest="cmpcategory", action="store_true", help="")
520 parser.add_option("", "--kernel", dest="cmpkernel", action="store_true", help="")
521 parser.add_option("", "--state", dest="cmpstate", action="store_true", help="")
522 parser.add_option("", "--comon", dest="comon", help="")
523 config = config(parser)
525 print "Content-Type: text/html\r\n"
526 if mynodeonly == None:
527 print "<html><body>\n"
528 if len(sys.argv) > 1:
529 if sys.argv[1] == "ssherror":
531 main(myfilter, mycategory, mystate, mycomon,mynodeonly)
532 if mynodeonly == None:
533 print "</body></html>\n"