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