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