add install_date field
[monitor.git] / web / MonitorWeb / monitorweb / controllers.py
1 import turbogears as tg
2 from turbogears import controllers, expose, flash, exception_handler, redirect
3 from turbogears import widgets
4 from cherrypy import request, response
5 import cherrypy
6 # from monitorweb import model
7 # import logging
8 # log = logging.getLogger("monitorweb.controllers")
9 import re
10 import os
11 from monitor.database.info.model import *
12 #from monitor.database.zabbixapi.model import *
13 from monitor_xmlrpc import MonitorXmlrpcServer
14
15 from monitor import util
16 from monitor import reboot
17 from monitor import bootman
18 from monitor import scanapi
19 from monitor import config
20 import time
21
22 from monitor.wrapper.plccache import plcdb_hn2lb as site_hn2lb
23
24 from monitorweb.templates.links import *
25
26 class ObjectQueryFields(widgets.WidgetsList):
27         """The WidgetsList defines the fields of the form."""
28         pass
29
30
31
32 class NodeQueryFields(widgets.WidgetsList):
33         """The WidgetsList defines the fields of the form."""
34
35         object = widgets.RadioButtonList(label="Query Type", options=[('nodes', 'All Nodes'), 
36                                                                                                                           ('nodehistory', 'Single Node History'),
37                                                                                                                           #('sites', 'All Sites'),
38                                                                                                                           #('sitehistory', 'Single Site History'),
39                                                                                                                           ], default="nodes")
40         nodehistory_hostname = widgets.TextField(label="Hostname Node History", attrs={'size':30})
41
42         hostname = widgets.CheckBox(label="Hostname")
43         firewall = widgets.CheckBox(label="Firewall?")
44         fs_status = widgets.CheckBox(label="Filesystem Status")
45         ssh_status = widgets.CheckBox(label="SSH Status")
46         ssh_error = widgets.CheckBox(label="SSH Errors")
47         dns_status = widgets.CheckBox(label="DNS Status")
48         iptables_status = widgets.CheckBox(label="IP Tables Status")
49         nm_status = widgets.CheckBox(label="NM Status")
50         princeton_comon_dir = widgets.CheckBox(label="CoMon Dir")
51         princeton_comon_running = widgets.CheckBox(label="CoMon Running")
52         princeton_comon_procs = widgets.CheckBox(label="CoMon Processes")
53         external_dns_status = widgets.CheckBox(label="Hostname Resolves?")
54         kernel_version = widgets.CheckBox(label="Kernel")
55         bootcd_version = widgets.CheckBox(label="BootCD")
56         boot_server = widgets.CheckBox(label="Boot Server")
57         install_date = widgets.CheckBox(label="Installation Date")
58         observed_status = widgets.CheckBox(label="Observed Status")
59         uptime = widgets.CheckBox(label="Uptime")
60         traceroute = widgets.CheckBox(label="Traceroute")
61         port_status = widgets.CheckBox(label="Port Status")
62         rpms = widgets.CheckBox(label="RPM")
63         rpmvalue = widgets.TextField(label="RPM Pattern")
64
65 class QueryForm(widgets.TableForm):
66     template = """
67     <form xmlns:py="http://purl.org/kid/ns#"
68         id="queryform"
69         name="${name}"
70         action="${action}"
71         method="${method}"
72         class="tableform"
73         py:attrs="form_attrs"
74     >
75         <div py:for="field in hidden_fields"
76             py:replace="field.display(value_for(field), **params_for(field))"
77         />
78         <table border="0" cellspacing="0" cellpadding="2" py:attrs="table_attrs">
79             <tr py:for="i, field in enumerate(fields)"
80                 class="${i%2 and 'odd' or 'even'}"
81             >
82                 <th>
83                     <label class="fieldlabel" for="${field.field_id}" py:content="field.label" />
84                 </th>
85                 <td>
86                     <span py:replace="field.display(value_for(field), **params_for(field))" />
87                     <span py:if="error_for(field)" class="fielderror" py:content="error_for(field)" />
88                     <span py:if="field.help_text" class="fieldhelp" py:content="field.help_text" />
89                 </td>
90             </tr>
91             <tr>
92                 <td>&#160;</td>
93                 <td py:content="submit.display(submit_text)" />
94             </tr>
95         </table>
96     </form>
97         """
98
99 def getNodeQueryForm():
100         return QueryForm(fields=NodeQueryFields(), action="query")
101
102 # make it easier group objects without invoking the elixir auto-write feature.
103 class aggregate: pass
104
105
106 def query_to_dict(query):
107         """ take a url query string and chop it up """
108         val = {}
109         query_fields = query.split('&')
110         for f in query_fields:
111                 (k,v) = urllib.splitvalue(f)
112                 val[k] = v
113
114         return val
115
116 def format_ports(data, pcumodel=None):
117         retval = []
118         filtered_length=0
119
120         if pcumodel:
121                 supported_ports=reboot.model_to_object(pcumodel).supported_ports
122         else:
123                 # ports of a production node
124                 supported_ports=[22,80,806]
125
126         if data and len(data.keys()) > 0 :
127                 for port in supported_ports:
128                         try:
129                                 state = data[str(port)]
130                         except:
131                                 state = "unknown"
132
133                         if state == "filtered":
134                                 filtered_length += 1
135                                 
136                         retval.append( (port, state) )
137
138         if retval == []: 
139                 retval = [( "Closed/Filtered", "state" )]
140
141         if filtered_length == len(supported_ports):
142                 retval = [( "All Filtered", "state" )]
143
144         return retval
145
146 def format_pcu_shortstatus(pcu):
147         status = "error"
148         if pcu:
149                 if pcu.reboot_trial_status == str(0):
150                         status = "Ok"
151                 elif pcu.reboot_trial_status == "NetDown" or pcu.reboot_trial_status == "Not_Run":
152                         status = pcu.reboot_trial_status
153                 else:
154                         status = "error"
155
156         return status
157
158 def prep_pcu_for_display(pcu):
159         agg = aggregate()
160         agg.pcu = pcu 
161                 
162         try:
163                 agg.loginbase = PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base']
164         except:
165                 agg.loginbase = "unknown"
166
167         agg.pcuhist = HistoryPCURecord.query.get(pcu.plc_pcuid)
168
169         agg.ports = format_ports(pcu.port_status, pcu.plc_pcu_stats['model'])
170         agg.status = format_pcu_shortstatus(pcu)
171
172         #print pcu.entry_complete
173         agg.entry_complete_str = pcu.entry_complete
174         #pcu.entry_complete_str += "".join([ f[0] for f in pcu.entry_complete.split() ])
175         if pcu.dns_status == "NOHOSTNAME":
176                 agg.dns_short_status = 'NoHost'
177         elif pcu.dns_status == "DNS-OK":
178                 agg.dns_short_status = 'Ok'
179         elif pcu.dns_status == "DNS-NOENTRY":
180                 agg.dns_short_status = 'NoEntry'
181         elif pcu.dns_status == "NO-DNS-OR-IP":
182                 agg.dns_short_status = 'NoHostOrIP'
183         elif pcu.dns_status == "DNS-MISMATCH":
184                 agg.dns_short_status = 'Mismatch'
185         return agg
186
187 class ActionListWidget(widgets.Widget):
188         pass
189
190 class NodeWidget(widgets.Widget):
191         pass
192
193 def prep_nodehist(node):
194         agg = aggregate()
195         agg.node = node
196         agg.loginbase = "unknown"
197         try:
198                 agg.loginbase = PlcSite.query.get(node.plc_siteid).plc_site_stats['login_base']
199         except:
200                 agg.loginbase = "exception"
201                 
202
203         return agg
204
205 def prep_node_for_display(node, pcuhash=None, preppcu=True, asofdate=None):
206         agg = aggregate()
207         agg.node = node
208
209         if node.plc_pcuid and preppcu:
210                 if pcuhash:
211                         pcu = pcuhash[node.plc_pcuid]
212                 else:
213                         pcu = FindbadPCURecord.get_latest_by(plc_pcuid=node.plc_pcuid)
214
215                 if pcu:
216                         agg.pcu_status = pcu.reboot_trial_status
217                         agg.pcu_short_status = format_pcu_shortstatus(pcu)
218                         agg.pcu = prep_pcu_for_display(pcu)
219                 else:
220                         agg.pcu_short_status = "none"
221                         agg.pcu_status = "nodata"
222                         agg.pcu = None
223
224         else:
225                 agg.pcu_status = "nopcu"
226                 agg.pcu_short_status = "none"
227                 agg.pcu = None
228
229
230         if node.kernel_version:
231                 agg.kernel = node.kernel_version.split()[2]
232         else:
233                 agg.kernel = ""
234
235         try:
236                 agg.loginbase = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
237         except:
238                 agg.loginbase = "unknown"
239
240         if agg.loginbase:
241                 agg.site = HistorySiteRecord.by_loginbase(agg.loginbase)
242
243                 if asofdate:
244                         agg.site = agg.site.get_as_of(asofdate)
245
246                 if agg.site is None:
247                         # TODO: need a cleaner fix for this...
248                         agg.site = HistorySiteRecord.by_loginbase("pl")
249                         if not agg.site:
250                                 agg.site = HistorySiteRecord.by_loginbase("ple")
251
252         agg.history = HistoryNodeRecord.by_hostname(node.hostname)
253         if asofdate:
254                 agg.history = agg.history.get_as_of(asofdate)
255
256         agg.ports = format_ports(node.port_status)
257
258         try:
259                 exists = node.plc_node_stats['last_contact']
260         except:
261                 # TODO: this should not assign to the fb object!
262                 node.plc_node_stats = {'last_contact' : None}
263         
264         return agg
265
266
267 class Root(controllers.RootController, MonitorXmlrpcServer):
268         @expose(template="monitorweb.templates.welcome")
269         def index(self):
270                 # log.debug("Happy TurboGears Controller Responding For Duty")
271                 flash("Welcome To MyOps!")
272                 return dict(now=time.ctime())
273
274         @expose(template="monitorweb.templates.nodelist", allow_json=True)
275         def node3(self, filter=None):
276                 nhquery = HistoryNodeRecord.query.all()
277                 query = []
278                 for nh in nhquery:
279                         if filter:
280                                 if nh.status == filter:
281                                         query.append(nh)
282                         else:
283                                 query.append(nh)
284
285                 rquery=[]
286                 for q in query:
287                         fb = FindbadNodeRecord.get_latest_by(hostname=q.hostname)
288                         rquery.append(fb)
289
290                 return dict(now=time.ctime(), query=rquery)
291
292         def node_query(self, filter):
293                 nhquery = HistoryNodeRecord.query.all()
294                 query = []
295                 for nh in nhquery:
296                         if filter:
297                                 if nh.status == filter:
298                                         query.append(nh)
299                         else:
300                                 query.append(nh)
301
302                 rquery=[]
303                 for q in query:
304                         fb = FindbadNodeRecord.get_latest_by(hostname=q.hostname)
305                         agg = prep_node_for_display(fb)
306                         rquery.append(agg)
307                 return rquery
308
309         @expose("cheetah:monitorweb.templates.nodelist_plain", as_format="plain", 
310                 accept_format="text/plain", content_type="text/plain")
311         @expose(template="monitorweb.templates.nodelist", allow_json=True)
312         def node2(self, filter=None):
313                 rquery=self.node_query(filter)
314                 widget = NodeWidget(template='monitorweb.templates.node_template')
315                 return dict(now=time.ctime(), query=rquery, nodewidget=widget)
316
317         @expose("cheetah:monitorweb.templates.query_plain", as_format="plain", 
318                 accept_format="text/plain", content_type="text/plain")
319         @expose(template="monitorweb.templates.query", allow_json=True)
320         def query(self, **data):
321                 query = []
322
323                 for k in data:
324                         print k, data[k]
325
326                 fbquery = None
327                 
328                 if 'object' in data and data['object'] == "nodes":
329                         fbquery = FindbadNodeRecord.get_all_latest()
330                 elif 'object' in data and data['object'] == "nodehistory": 
331                         hostname = data['nodehistory_hostname']
332                         data['date_checked'] = 'date_checked'
333                         fbrecord = FindbadNodeRecord.get_by(hostname=hostname)
334                         fbquery = fbrecord.versions[-500:]
335
336                 if fbquery:
337                         for node in fbquery:
338                                 # NOTE: reformat some fields.
339                                 if type(node) is not type(FindbadNodeRecord):
340                                         agg = node.__dict__.copy()
341                                 else:
342                                         agg = node.to_dict()
343                                 agg.update(agg['plc_node_stats'])
344                                 if agg['kernel_version']:
345                                         agg['kernel_version'] = agg['kernel_version'].split()[2]
346                                 if 'traceroute' in data and agg['traceroute']:
347                                         agg['traceroute'] = "<pre>" + agg['traceroute'] + "</pre>"
348                                 if 'rpmvalue' in data and 'rpms' in data:
349                                         if agg['rpms']:
350                                                 rpm_list = agg['rpms'].split()
351                                                 rpm_list = filter(lambda x: data['rpmvalue'] in x, rpm_list)
352                                                 agg['rpms'] = " ".join(rpm_list)
353
354                                 query.append(agg)
355
356                 fields=data.copy()
357
358                 try: 
359                         del fields['object']
360                         del fields['rpmvalue']
361                         del fields['nodehistory_hostname']
362                 except: pass
363                 return dict(now=time.ctime(), query=query, fields=fields, data=data, queryform=getNodeQueryForm())
364
365         @expose(template="monitorweb.templates.nodefast", allow_json=True)
366         def node(self, filter=None):
367                 nhquery = HistoryNodeRecord.query.all()
368                 query = []
369                 for nh in nhquery:
370                         if filter:
371                                 if nh.status == filter:
372                                         agg = prep_nodehist(nh)
373                                         query.append(agg)
374                         else:
375                                 agg = prep_nodehist(nh)
376                                 query.append(agg)
377
378                 return dict(now=time.ctime(), query=query)
379
380         @expose(template="monitorweb.templates.nodelist")
381         def nodeslow(self, filter='boot'):
382                 print "NODE------------------"
383                 print "befor-len: ", len( [ i for i in session] )
384                 session.flush(); session.clear()
385                 print "after-len: ", len( [ i for i in session] )
386                 fbquery = FindbadNodeRecord.get_all_latest()
387                 query = []
388                 filtercount = {'down' : 0, 'boot': 0, 'debug' : 0, 'diagnose' : 0, 'disabled': 0, 
389                                                 'neverboot' : 0, 'pending' : 0, 'all' : 0, None : 0}
390                 for node in fbquery:
391                         # NOTE: reformat some fields.
392                         agg = prep_node_for_display(node)
393
394                         if not agg.history:
395                                 continue
396
397                         if agg.history.status in ['down', 'offline']:
398                                 if node.plc_node_stats and node.plc_node_stats['last_contact'] != None:
399                                         filtercount['down'] += 1
400                                 else:
401                                         filtercount['neverboot'] += 1
402                         elif agg.history.status in ['good', 'online']:
403                                 filtercount['boot'] += 1
404                         elif agg.history.status in ['debug', 'monitordebug']:
405                                 filtercount['debug'] += 1
406                         else:
407                                 if filtercount.has_key(agg.history.status):
408                                         filtercount[agg.history.status] += 1
409                                 
410
411                         # NOTE: apply filter
412                         if filter == "neverboot":
413                                 if not node.plc_node_stats or node.plc_node_stats['last_contact'] == None:
414                                         query.append(agg)
415                         elif filter == "all":
416                                 query.append(agg)
417                         elif filter == agg.history.status:
418                                 query.append(agg)
419                         elif filter == 'boot':
420                                 query.append(agg)
421
422                                 
423                 widget = NodeWidget(template='monitorweb.templates.node_template')
424                 return dict(now=time.ctime(), query=query, fc=filtercount, nodewidget=widget)
425         
426         def nodeaction_handler(self, tg_exceptions=None):
427                 """Handle any kind of error."""
428                 print "NODEACTION_HANDLER------------------"
429
430                 if 'pcuid' in request.params:
431                         pcuid = request.params['pcuid']
432                 else:
433                         refurl = request.headers.get("Referer",link("pcu"))
434                         print refurl
435
436                         # TODO: do this more intelligently...
437                         uri_fields = urllib.splitquery(refurl)
438                         if uri_fields[1] is not None:
439                                 val = query_to_dict(uri_fields[1])
440                                 if 'pcuid' in val:
441                                         pcuid = val['pcuid']
442                                 elif 'hostname' in val:
443                                         pcuid = FindbadNodeRecord.get_latest_by(hostname=val['hostname']).plc_pcuid
444                                 else:
445                                         pcuid=None
446                         else:
447                                 pcuid=None
448
449                 cherry_trail = cherrypy._cputil.get_object_trail()
450                 for i in cherry_trail:
451                         print "trail: ", i
452
453                 print pcuid
454                 return self.pcuview(None, pcuid, **dict(exceptions=tg_exceptions))
455
456         def nodeaction(self, **data):
457                 print "NODEACTION------------------"
458                 for item in data.keys():
459                         print "%s %s" % ( item, data[item] )
460
461                 if 'hostname' in data:
462                         hostname = data['hostname']
463                 else:
464                         flash("No hostname given in submitted data")
465                         return
466
467                 if 'submit' in data or 'type' in data:
468                         try:
469                                 action = data['submit']
470                         except:
471                                 action = data['type']
472                 else:
473                         flash("No submit action given in submitted data")
474                         return
475
476                 if action == "Reboot":
477                         print "REBOOT: %s" % hostname
478                         ret = reboot.reboot_str(str(hostname))
479                         print ret
480                         if ret: raise RuntimeError("Error using PCU: " + str(ret))
481                         flash("Reboot appeared to work.  Allow at most 5 minutes.  Then run ExternalScan to check current status.")
482
483                 elif action == "ExternalScan":
484                         scanapi.externalprobe(str(hostname))
485                         flash("External Scan Successful!")
486                 elif action == "InternalScan":
487                         scanapi.internalprobe(str(hostname))
488                         flash("Internal Scan Successful!")
489                 else:
490                         # unknown action
491                         raise RuntimeError("Unknown action given")
492                 return
493
494         @expose(template="monitorweb.templates.simpleview")
495         def simpleview(self, **data):
496                 return self.pre_view(**data)
497
498         @expose(template="monitorweb.templates.simpleview")
499         def pcuview(self, **data):
500                 return self.pre_view(**data)
501
502         @expose(template="monitorweb.templates.detailview")
503         def detailview(self, **data):
504                 return self.pre_view(**data)
505
506
507         def pre_view(self, **data):
508                 session.flush(); session.clear()
509
510                 loginbase=None
511                 loginbase_list=[]
512                 hostname=None
513                 pcuid=None
514                 since=20
515                 # if objtype is not None, then treat 'hostname' or 'loginbase' as a search pattern
516                 objtype=None
517
518                 exceptions = None
519                 sitequery=[]
520                 nodequery=[]
521                 pcuquery=[]
522                 actions=[]
523                 actions_list=[]
524
525                 for key in data:
526                         print key, data[key]
527
528                 if 'query' in data:
529                         obj = data['query']
530                         fields = obj.split(":")
531                         if len(fields) > 1:
532                                 objtype = fields[0]
533                                 obj = fields[1].replace("*", "%")
534                                 print "obj: %s"% obj
535
536                         if len(obj.split(".")) > 1 or objtype == "node": 
537                                 hostname = obj
538                         else: 
539                                 loginbase = obj
540
541                 if 'loginbase' in data:
542                         loginbase = data['loginbase']
543
544                 if 'hostname' in data:
545                         hostname = data['hostname']
546
547                 if 'pcuid' in data:
548                         try: pcuid = int(data['pcuid'])
549                         except: pcuid = None
550
551                 if 'since' in data:
552                         try: since = int(since)
553                         except: since = 20
554
555                 if pcuid:
556                         print "pcuid: %s" % pcuid
557                         pcu = FindbadPCURecord.get_latest_by(plc_pcuid=pcuid)
558                         loginbase_list += [ PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base'] ]
559
560                 if hostname:
561                         if not objtype:
562                                 nodes = [ FindbadNodeRecord.get_latest_by(hostname=hostname) ]
563                         else:
564                                 nodes = FindbadNodeRecord.query.filter(FindbadNodeRecord.hostname.like(hostname)) 
565
566                         for node in nodes:
567                                 lb = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
568                                 if lb not in loginbase_list:
569                                         loginbase_list += [ lb ]
570
571                 if loginbase:
572                         if not objtype:
573                                 loginbase_list = [ loginbase ]
574                         else:
575                                 loginbase_list = HistorySiteRecord.query.filter(HistorySiteRecord.loginbase.like(loginbase)) 
576                                 loginbase_list = [ l.loginbase for l in loginbase_list ]
577                         
578
579                 if loginbase_list:
580                         for loginbase in loginbase_list:
581                                 actions = ActionRecord.query.filter_by(loginbase=loginbase
582                                                                 ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since)
583                                                                 ).order_by(ActionRecord.date_created.desc())
584                                 actions_list += [ a for a in actions ]
585                                 site = HistorySiteRecord.by_loginbase(loginbase)
586                                 if site:
587                                         sitequery.append(site)
588                                 # NOTE: because a single pcu may be assigned to multiple hosts,
589                                 # track unique pcus by their plc_pcuid, then turn dict into list
590                                 pcus = {}
591                                 for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
592                                                 # NOTE: reformat some fields.
593                                                 agg = prep_node_for_display(node)
594                                                 nodequery += [agg]
595                                                 if agg.pcu: 
596                                                         pcus[agg.pcu.pcu.plc_pcuid] = agg.pcu
597
598                                 for pcuid_key in pcus:
599                                         pcuquery += [pcus[pcuid_key]]
600
601                 actionlist_widget = ActionListWidget(template='monitorweb.templates.actionlist_template')
602                 return dict(sitequery=sitequery, pcuquery=pcuquery, nodequery=nodequery, actions=actions_list, actionlist_widget=actionlist_widget, since=since, exceptions=exceptions)
603
604
605         # TODO: add form validation
606         @expose(template="monitorweb.templates.pcuview")
607         @exception_handler(nodeaction_handler,"isinstance(tg_exceptions,RuntimeError)")
608         def pcuviewold(self, loginbase=None, pcuid=None, hostname=None, since=20, **data):
609                 session.flush(); session.clear()
610                 sitequery=[]
611                 pcuquery=[]
612                 nodequery=[]
613                 actions=[]
614                 exceptions = None
615
616                 try: since = int(since)
617                 except: since = 7
618
619                 for key in data:
620                         print key, data[key]
621
622                 if 'submit' in data.keys() or 'type' in data.keys():
623                         if hostname: data['hostname'] = hostname
624                         self.nodeaction(**data)
625                 if 'exceptions' in data:
626                         exceptions = data['exceptions']
627
628                 if 'query' in data:
629                         obj = data['query']
630                         if len(obj.split(".")) > 1: hostname = obj
631                         else: loginbase=obj
632
633                 if pcuid:
634                         print "pcuid: %s" % pcuid
635                         pcu = FindbadPCURecord.get_latest_by(plc_pcuid=pcuid)
636                         loginbase = PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base']
637
638                 if hostname:
639                         node = FindbadNodeRecord.get_latest_by(hostname=hostname)
640                         loginbase = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
641
642                 if loginbase:
643                         actions = ActionRecord.query.filter_by(loginbase=loginbase
644                                                         ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since)
645                                                         ).order_by(ActionRecord.date_created.desc())
646                         actions = [ a for a in actions ]
647                         sitequery = [HistorySiteRecord.by_loginbase(loginbase)]
648                         pcus = {}
649                         for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
650                                         # NOTE: reformat some fields.
651                                         agg = prep_node_for_display(node)
652                                         nodequery += [agg]
653                                         if agg.pcu: #.pcu.plc_pcuid:    # not None
654                                                 #pcu = FindbadPCURecord.get_latest_by(plc_pcuid=agg.plc_pcuid)
655                                                 #prep_pcu_for_display(pcu)
656                                                 pcus[agg.pcu.pcu.plc_pcuid] = agg.pcu
657
658                         for pcuid_key in pcus:
659                                 pcuquery += [pcus[pcuid_key]]
660
661                 return dict(sitequery=sitequery, pcuquery=pcuquery, nodequery=nodequery, actions=actions, since=since, exceptions=exceptions)
662
663         @expose(template="monitorweb.templates.pcuhistory")
664         def pcuhistory(self, pcu_id=None):
665                 query = []
666                 if pcu_id:
667                         fbnode = HistoryPCURecord.get_by(plc_pcuid=pcu_id)
668                         l = fbnode.versions[-100:]
669                         l.reverse()
670                         for pcu in l:
671                                 #prep_node_for_display(node)
672                                 query.append(pcu)
673
674                 return dict(query=query, pcu_id=pcu_id)
675
676         @expose(template="monitorweb.templates.nodescanhistory")
677         def nodescanhistory(self, hostname=None, length=10):
678                 try: length = int(length)
679                 except: length = 21
680
681                 fbnode = FindbadNodeRecord.get_by(hostname=hostname)
682                 # TODO: add links for earlier history if desired.
683                 l = fbnode.versions[-length:]
684                 l.reverse()
685                 query=[]
686                 for node in l:
687                         agg = prep_node_for_display(node, pcuhash=None, preppcu=False, asofdate=node.timestamp)
688                         query.append(agg)
689
690                 if 'length' in request.params: 
691                         del request.params['length']
692                 return dict(query=query, hostname=hostname, params=request.params)
693
694         @expose(template="monitorweb.templates.nodehistory")
695         def nodehistory(self, hostname=None):
696                 query = []
697                 if hostname:
698                         fbnode = HistoryNodeRecord.get_by(hostname=hostname)
699                         l = fbnode.versions[-100:]
700                         l.reverse()
701                         for node in l:
702                                 #prep_node_for_display(node)
703                                 query.append(node)
704
705                 return dict(query=query, hostname=hostname)
706
707         @expose(template="monitorweb.templates.sitehistory")
708         def sitehistory(self, loginbase=None):
709                 query = []
710                 if loginbase:
711                         fbsite = HistorySiteRecord.get_by(loginbase=loginbase)
712                         # TODO: add links for earlier history if desired.
713                         l = fbsite.versions[-100:]
714                         l.reverse()
715                         for site in l:
716                                 query.append(site)
717                 return dict(query=query, loginbase=loginbase)
718
719
720         @expose(template="monitorweb.templates.pculist")
721         def pcu(self, filter='all'):
722                 print "PCUVIEW------------------"
723                 print "befor-len: ", len( [ i for i in session] )
724                 session.flush(); session.clear()
725                 print "after-len: ", len( [ i for i in session] )
726                 fbquery = FindbadPCURecord.get_all_latest()
727                 query = []
728                 filtercount = {'ok' : 0, 'NetDown': 0, 'Not_Run' : 0, 'pending' : 0, 'all' : 0}
729                 for node in fbquery:
730
731                         # NOTE: count filter
732                         if node.reboot_trial_status == str(0):
733                                 filtercount['ok'] += 1
734                         elif node.reboot_trial_status == 'NetDown' or node.reboot_trial_status == 'Not_Run':
735                                 filtercount[node.reboot_trial_status] += 1
736                         else:
737                                 filtercount['pending'] += 1
738
739                         pcuagg = prep_pcu_for_display(node)
740
741                         # NOTE: apply filter
742                         if filter == "all":
743                                 query.append(pcuagg)
744                         elif filter == "ok" and node.reboot_trial_status == str(0):
745                                 query.append(pcuagg)
746                         elif filter == node.reboot_trial_status:
747                                 query.append(pcuagg)
748                         elif filter == "pending":
749                                 # TODO: look in message logs...
750                                 if node.reboot_trial_status != str(0) and \
751                                         node.reboot_trial_status != 'NetDown' and \
752                                         node.reboot_trial_status != 'Not_Run':
753
754                                         query.append(pcuagg)
755                                 
756                 return dict(query=query, fc=filtercount)
757
758         @expose(template="monitorweb.templates.sitelist")
759         def site(self, filter='all'):
760                 print "SITE------------------"
761                 print "befor-len: ", len( [ i for i in session] )
762                 session.flush(); session.clear()
763                 print "after-len: ", len( [ i for i in session] )
764                 filtercount = {'good' : 0, 'down': 0, 'online':0, 'offline' : 0, 'new' : 0, 'pending' : 0, 'all' : 0}
765                 fbquery = HistorySiteRecord.query.all()
766                 query = []
767                 for site in fbquery:
768                         # count filter
769                         filtercount['all'] += 1
770                         if site.new and site.slices_used == 0 and not site.enabled:
771                                 filtercount['new'] += 1
772                         elif not site.enabled:
773                                 filtercount['pending'] += 1
774                         elif site.status in ['good', 'online']:
775                                 filtercount['good'] += 1
776                         elif site.status in ['down', 'offline']:
777                                 filtercount['down'] += 1
778
779                         # apply filter
780                         if filter == "all":
781                                 query.append(site)
782                         elif filter == 'new' and site.new and site.slices_used == 0 and not site.enabled:
783                                 query.append(site)
784                         elif filter == "pending" and not site.enabled:
785                                 query.append(site)
786                         elif filter == 'good' and site.status in ['good', 'online']:
787                                 query.append(site)
788                         elif filter == 'down' and site.status in ['down', 'offline']:
789                                 query.append(site)
790                                 
791                 return dict(query=query, fc=filtercount)
792         @expose(template="monitorweb.templates.sitesummary")
793         def sitesummary(self, loginbase="princeton"):
794                 nodequery = []
795                 for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
796                         agg = prep_node_for_display(node)
797                         nodequery += [agg]
798                 
799                 return dict(nodequery=nodequery, loginbase=loginbase)
800
801         @expose(template="monitorweb.templates.summary")
802         def summary(self, since=7):
803                 sumdata = {}
804                 sumdata['nodes'] = {}
805                 sumdata['sites'] = {}
806                 sumdata['pcus'] = {}
807
808                 def summarize(query, type):
809                         for o in query:
810                                 if o.status not in sumdata[type]:
811                                         sumdata[type][o.status] = 0
812                                 sumdata[type][o.status] += 1
813
814                 fbquery = HistorySiteRecord.query.all()
815                 summarize(fbquery, 'sites')
816                 fbquery = HistoryPCURecord.query.all()
817                 summarize(fbquery, 'pcus')
818                 fbquery = HistoryNodeRecord.query.all()
819                 summarize(fbquery, 'nodes')
820
821                 if 'monitordebug' in sumdata['nodes']:
822                         d = sumdata['nodes']['monitordebug']
823                         del sumdata['nodes']['monitordebug']
824                         sumdata['nodes']['failboot'] = d
825                 
826                 return dict(sumdata=sumdata, setorder=['good', 'offline', 'down', 'online']) 
827
828         @expose(template="monitorweb.templates.actionsummary")
829         def actionsummary(self, since=7):
830                 from monitor.wrapper.emailTxt import mailtxt
831
832                 types = filter(lambda x: 'notice' in x, dir(mailtxt))
833                 results = {}
834
835                 print mon_metadata.bind
836                 if session.bind is None:
837                         #TODO: figure out why this value gets cleared out...
838                         session.bind = mon_metadata.bind
839                 result = session.execute("select distinct(action_type) from actionrecord;")
840
841                 types = [r[0] for r in result]
842
843                 try: since = int(since)
844                 except: since = 7
845
846                 for  t in types:
847                         acts = ActionRecord.query.filter(ActionRecord.action_type==t
848                                         ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since))
849                         results[t] = acts.count()
850                 return dict(results=results)
851
852         @expose(template="monitorweb.templates.actionlist")
853         def actionlist(self, since=7, action_type=None, loginbase=None):
854
855                 try: since = int(since)
856                 except: since = 7
857
858                 acts_query = ActionRecord.query.filter(
859                                           ActionRecord.date_created >= datetime.now() - timedelta(since)
860                                          )
861                 if loginbase:
862                         acts_query = acts_query.filter_by(loginbase=loginbase)
863
864                 if action_type:
865                         acts_query = acts_query.filter(ActionRecord.action_type==action_type)
866
867                 acts = acts_query.order_by(ActionRecord.date_created.desc())
868
869                 query = [ a for a in acts ]
870                 
871                 return dict(actions=query, action_type=action_type, since=since)
872
873         @cherrypy.expose()
874         def upload(self, log, **keywords):
875                 hostname = None
876                 logtype = None
877                 logtype_list = ['bm.log', ]
878
879                 if 'hostname' in keywords:
880                         hostname = keywords['hostname']
881                 if 'type' in keywords and keywords['type'] in logtype_list:
882                         logtype = keywords['type']
883
884                 if not hostname: return ""
885                 if not logtype: return "unknown logtype: %s" % logtype 
886
887                 short_target_filename = bootman.bootmanager_log_name(hostname)
888                 abs_target_filename = os.path.join(config.MONITOR_BOOTMANAGER_LOG, short_target_filename)
889                 print "write data: %s" % abs_target_filename
890                 util.file.dumpFile(abs_target_filename, log.file.read())
891                 bootman.bootmanager_log_action(hostname, short_target_filename, logtype)
892                 session.flush()
893
894                 print "redirecting 3"
895
896                 return dict()