149a397c690bdfd2ea52daf4352770be295d0ea2
[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['install_date']:
345                                         agg['install_date'] = time.mktime(time.strptime(agg['install_date'], "%a %b %d %H:%M:%S %Y"))
346                                 if agg['kernel_version']:
347                                         agg['kernel_version'] = agg['kernel_version'].split()[2]
348                                 if 'traceroute' in data and agg['traceroute']:
349                                         agg['traceroute'] = "<pre>" + agg['traceroute'] + "</pre>"
350                                 if 'rpmvalue' in data and 'rpms' in data:
351                                         if agg['rpms']:
352                                                 rpm_list = agg['rpms'].split()
353                                                 rpm_list = filter(lambda x: re.match(data['rpmvalue'], x, re.I),
354                                                                   rpm_list)
355                                                 agg['rpms'] = " ".join(rpm_list)
356
357                                 query.append(agg)
358
359                 fields=data.copy()
360
361                 try: 
362                         del fields['object']
363                         del fields['rpmvalue']
364                         del fields['nodehistory_hostname']
365                 except: pass
366                 return dict(now=time.ctime(), query=query, fields=fields, data=data, queryform=getNodeQueryForm())
367
368         @expose(template="monitorweb.templates.nodefast", allow_json=True)
369         def node(self, filter=None):
370                 nhquery = HistoryNodeRecord.query.all()
371                 query = []
372                 for nh in nhquery:
373                         if filter:
374                                 if nh.status == filter:
375                                         agg = prep_nodehist(nh)
376                                         query.append(agg)
377                         else:
378                                 agg = prep_nodehist(nh)
379                                 query.append(agg)
380
381                 return dict(now=time.ctime(), query=query)
382
383         @expose(template="monitorweb.templates.nodelist")
384         def nodeslow(self, filter='boot'):
385                 print "NODE------------------"
386                 print "befor-len: ", len( [ i for i in session] )
387                 session.flush(); session.clear()
388                 print "after-len: ", len( [ i for i in session] )
389                 fbquery = FindbadNodeRecord.get_all_latest()
390                 query = []
391                 filtercount = {'down' : 0, 'boot': 0, 'debug' : 0, 'diagnose' : 0, 'disabled': 0, 
392                                                 'neverboot' : 0, 'pending' : 0, 'all' : 0, None : 0}
393                 for node in fbquery:
394                         # NOTE: reformat some fields.
395                         agg = prep_node_for_display(node)
396
397                         if not agg.history:
398                                 continue
399
400                         if agg.history.status in ['down', 'offline']:
401                                 if node.plc_node_stats and node.plc_node_stats['last_contact'] != None:
402                                         filtercount['down'] += 1
403                                 else:
404                                         filtercount['neverboot'] += 1
405                         elif agg.history.status in ['good', 'online']:
406                                 filtercount['boot'] += 1
407                         elif agg.history.status in ['debug', 'monitordebug']:
408                                 filtercount['debug'] += 1
409                         else:
410                                 if filtercount.has_key(agg.history.status):
411                                         filtercount[agg.history.status] += 1
412                                 
413
414                         # NOTE: apply filter
415                         if filter == "neverboot":
416                                 if not node.plc_node_stats or node.plc_node_stats['last_contact'] == None:
417                                         query.append(agg)
418                         elif filter == "all":
419                                 query.append(agg)
420                         elif filter == agg.history.status:
421                                 query.append(agg)
422                         elif filter == 'boot':
423                                 query.append(agg)
424
425                                 
426                 widget = NodeWidget(template='monitorweb.templates.node_template')
427                 return dict(now=time.ctime(), query=query, fc=filtercount, nodewidget=widget)
428         
429         def nodeaction_handler(self, tg_exceptions=None):
430                 """Handle any kind of error."""
431                 print "NODEACTION_HANDLER------------------"
432
433                 if 'pcuid' in request.params:
434                         pcuid = request.params['pcuid']
435                 else:
436                         refurl = request.headers.get("Referer",link("pcu"))
437                         print refurl
438
439                         # TODO: do this more intelligently...
440                         uri_fields = urllib.splitquery(refurl)
441                         if uri_fields[1] is not None:
442                                 val = query_to_dict(uri_fields[1])
443                                 if 'pcuid' in val:
444                                         pcuid = val['pcuid']
445                                 elif 'hostname' in val:
446                                         pcuid = FindbadNodeRecord.get_latest_by(hostname=val['hostname']).plc_pcuid
447                                 else:
448                                         pcuid=None
449                         else:
450                                 pcuid=None
451
452                 cherry_trail = cherrypy._cputil.get_object_trail()
453                 for i in cherry_trail:
454                         print "trail: ", i
455
456                 print pcuid
457                 return self.pcuview(None, pcuid, **dict(exceptions=tg_exceptions))
458
459         def nodeaction(self, **data):
460                 print "NODEACTION------------------"
461                 for item in data.keys():
462                         print "%s %s" % ( item, data[item] )
463
464                 if 'hostname' in data:
465                         hostname = data['hostname']
466                 else:
467                         flash("No hostname given in submitted data")
468                         return
469
470                 if 'submit' in data or 'type' in data:
471                         try:
472                                 action = data['submit']
473                         except:
474                                 action = data['type']
475                 else:
476                         flash("No submit action given in submitted data")
477                         return
478
479                 if action == "Reboot":
480                         print "REBOOT: %s" % hostname
481                         ret = reboot.reboot_str(str(hostname))
482                         print ret
483                         if ret: raise RuntimeError("Error using PCU: " + str(ret))
484                         flash("Reboot appeared to work.  Allow at most 5 minutes.  Then run ExternalScan to check current status.")
485
486                 elif action == "ExternalScan":
487                         scanapi.externalprobe(str(hostname))
488                         flash("External Scan Successful!")
489                 elif action == "InternalScan":
490                         scanapi.internalprobe(str(hostname))
491                         flash("Internal Scan Successful!")
492                 else:
493                         # unknown action
494                         raise RuntimeError("Unknown action given")
495                 return
496
497         @expose(template="monitorweb.templates.simpleview")
498         def simpleview(self, **data):
499                 return self.pre_view(**data)
500
501         @expose(template="monitorweb.templates.simpleview")
502         def pcuview(self, **data):
503                 return self.pre_view(**data)
504
505         @expose(template="monitorweb.templates.detailview")
506         def detailview(self, **data):
507                 return self.pre_view(**data)
508
509
510         def pre_view(self, **data):
511                 session.flush(); session.clear()
512
513                 loginbase=None
514                 loginbase_list=[]
515                 hostname=None
516                 pcuid=None
517                 since=20
518                 # if objtype is not None, then treat 'hostname' or 'loginbase' as a search pattern
519                 objtype=None
520
521                 exceptions = None
522                 sitequery=[]
523                 nodequery=[]
524                 pcuquery=[]
525                 actions=[]
526                 actions_list=[]
527
528                 for key in data:
529                         print key, data[key]
530
531                 if 'query' in data:
532                         obj = data['query']
533                         fields = obj.split(":")
534                         if len(fields) > 1:
535                                 objtype = fields[0]
536                                 obj = fields[1].replace("*", "%")
537                                 print "obj: %s"% obj
538
539                         if len(obj.split(".")) > 1 or objtype == "node": 
540                                 hostname = obj
541                         else: 
542                                 loginbase = obj
543
544                 if 'loginbase' in data:
545                         loginbase = data['loginbase']
546
547                 if 'hostname' in data:
548                         hostname = data['hostname']
549
550                 if 'pcuid' in data:
551                         try: pcuid = int(data['pcuid'])
552                         except: pcuid = None
553
554                 if 'since' in data:
555                         try: since = int(since)
556                         except: since = 20
557
558                 if pcuid:
559                         print "pcuid: %s" % pcuid
560                         pcu = FindbadPCURecord.get_latest_by(plc_pcuid=pcuid)
561                         loginbase_list += [ PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base'] ]
562
563                 if hostname:
564                         if not objtype:
565                                 nodes = [ FindbadNodeRecord.get_latest_by(hostname=hostname) ]
566                         else:
567                                 nodes = FindbadNodeRecord.query.filter(FindbadNodeRecord.hostname.like(hostname)) 
568
569                         for node in nodes:
570                                 lb = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
571                                 if lb not in loginbase_list:
572                                         loginbase_list += [ lb ]
573
574                 if loginbase:
575                         if not objtype:
576                                 loginbase_list = [ loginbase ]
577                         else:
578                                 loginbase_list = HistorySiteRecord.query.filter(HistorySiteRecord.loginbase.like(loginbase)) 
579                                 loginbase_list = [ l.loginbase for l in loginbase_list ]
580                         
581
582                 if loginbase_list:
583                         for loginbase in loginbase_list:
584                                 actions = ActionRecord.query.filter_by(loginbase=loginbase
585                                                                 ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since)
586                                                                 ).order_by(ActionRecord.date_created.desc())
587                                 actions_list += [ a for a in actions ]
588                                 site = HistorySiteRecord.by_loginbase(loginbase)
589                                 if site:
590                                         sitequery.append(site)
591                                 # NOTE: because a single pcu may be assigned to multiple hosts,
592                                 # track unique pcus by their plc_pcuid, then turn dict into list
593                                 pcus = {}
594                                 for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
595                                                 # NOTE: reformat some fields.
596                                                 agg = prep_node_for_display(node)
597                                                 nodequery += [agg]
598                                                 if agg.pcu: 
599                                                         pcus[agg.pcu.pcu.plc_pcuid] = agg.pcu
600
601                                 for pcuid_key in pcus:
602                                         pcuquery += [pcus[pcuid_key]]
603
604                 actionlist_widget = ActionListWidget(template='monitorweb.templates.actionlist_template')
605                 return dict(sitequery=sitequery, pcuquery=pcuquery, nodequery=nodequery, actions=actions_list, actionlist_widget=actionlist_widget, since=since, exceptions=exceptions)
606
607
608         # TODO: add form validation
609         @expose(template="monitorweb.templates.pcuview")
610         @exception_handler(nodeaction_handler,"isinstance(tg_exceptions,RuntimeError)")
611         def pcuviewold(self, loginbase=None, pcuid=None, hostname=None, since=20, **data):
612                 session.flush(); session.clear()
613                 sitequery=[]
614                 pcuquery=[]
615                 nodequery=[]
616                 actions=[]
617                 exceptions = None
618
619                 try: since = int(since)
620                 except: since = 7
621
622                 for key in data:
623                         print key, data[key]
624
625                 if 'submit' in data.keys() or 'type' in data.keys():
626                         if hostname: data['hostname'] = hostname
627                         self.nodeaction(**data)
628                 if 'exceptions' in data:
629                         exceptions = data['exceptions']
630
631                 if 'query' in data:
632                         obj = data['query']
633                         if len(obj.split(".")) > 1: hostname = obj
634                         else: loginbase=obj
635
636                 if pcuid:
637                         print "pcuid: %s" % pcuid
638                         pcu = FindbadPCURecord.get_latest_by(plc_pcuid=pcuid)
639                         loginbase = PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base']
640
641                 if hostname:
642                         node = FindbadNodeRecord.get_latest_by(hostname=hostname)
643                         loginbase = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
644
645                 if loginbase:
646                         actions = ActionRecord.query.filter_by(loginbase=loginbase
647                                                         ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since)
648                                                         ).order_by(ActionRecord.date_created.desc())
649                         actions = [ a for a in actions ]
650                         sitequery = [HistorySiteRecord.by_loginbase(loginbase)]
651                         pcus = {}
652                         for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
653                                         # NOTE: reformat some fields.
654                                         agg = prep_node_for_display(node)
655                                         nodequery += [agg]
656                                         if agg.pcu: #.pcu.plc_pcuid:    # not None
657                                                 #pcu = FindbadPCURecord.get_latest_by(plc_pcuid=agg.plc_pcuid)
658                                                 #prep_pcu_for_display(pcu)
659                                                 pcus[agg.pcu.pcu.plc_pcuid] = agg.pcu
660
661                         for pcuid_key in pcus:
662                                 pcuquery += [pcus[pcuid_key]]
663
664                 return dict(sitequery=sitequery, pcuquery=pcuquery, nodequery=nodequery, actions=actions, since=since, exceptions=exceptions)
665
666         @expose(template="monitorweb.templates.pcuhistory")
667         def pcuhistory(self, pcu_id=None):
668                 query = []
669                 if pcu_id:
670                         fbnode = HistoryPCURecord.get_by(plc_pcuid=pcu_id)
671                         l = fbnode.versions[-100:]
672                         l.reverse()
673                         for pcu in l:
674                                 #prep_node_for_display(node)
675                                 query.append(pcu)
676
677                 return dict(query=query, pcu_id=pcu_id)
678
679         @expose(template="monitorweb.templates.nodescanhistory")
680         def nodescanhistory(self, hostname=None, length=10):
681                 try: length = int(length)
682                 except: length = 21
683
684                 fbnode = FindbadNodeRecord.get_by(hostname=hostname)
685                 # TODO: add links for earlier history if desired.
686                 l = fbnode.versions[-length:]
687                 l.reverse()
688                 query=[]
689                 for node in l:
690                         agg = prep_node_for_display(node, pcuhash=None, preppcu=False, asofdate=node.timestamp)
691                         query.append(agg)
692
693                 if 'length' in request.params: 
694                         del request.params['length']
695                 return dict(query=query, hostname=hostname, params=request.params)
696
697         @expose(template="monitorweb.templates.nodehistory")
698         def nodehistory(self, hostname=None):
699                 query = []
700                 if hostname:
701                         fbnode = HistoryNodeRecord.get_by(hostname=hostname)
702                         l = fbnode.versions[-100:]
703                         l.reverse()
704                         for node in l:
705                                 #prep_node_for_display(node)
706                                 query.append(node)
707
708                 return dict(query=query, hostname=hostname)
709
710         @expose(template="monitorweb.templates.sitehistory")
711         def sitehistory(self, loginbase=None):
712                 query = []
713                 if loginbase:
714                         fbsite = HistorySiteRecord.get_by(loginbase=loginbase)
715                         # TODO: add links for earlier history if desired.
716                         l = fbsite.versions[-100:]
717                         l.reverse()
718                         for site in l:
719                                 query.append(site)
720                 return dict(query=query, loginbase=loginbase)
721
722
723         @expose(template="monitorweb.templates.pculist")
724         def pcu(self, filter='all'):
725                 print "PCUVIEW------------------"
726                 print "befor-len: ", len( [ i for i in session] )
727                 session.flush(); session.clear()
728                 print "after-len: ", len( [ i for i in session] )
729                 fbquery = FindbadPCURecord.get_all_latest()
730                 query = []
731                 filtercount = {'ok' : 0, 'NetDown': 0, 'Not_Run' : 0, 'pending' : 0, 'all' : 0}
732                 for node in fbquery:
733
734                         # NOTE: count filter
735                         if node.reboot_trial_status == str(0):
736                                 filtercount['ok'] += 1
737                         elif node.reboot_trial_status == 'NetDown' or node.reboot_trial_status == 'Not_Run':
738                                 filtercount[node.reboot_trial_status] += 1
739                         else:
740                                 filtercount['pending'] += 1
741
742                         pcuagg = prep_pcu_for_display(node)
743
744                         # NOTE: apply filter
745                         if filter == "all":
746                                 query.append(pcuagg)
747                         elif filter == "ok" and node.reboot_trial_status == str(0):
748                                 query.append(pcuagg)
749                         elif filter == node.reboot_trial_status:
750                                 query.append(pcuagg)
751                         elif filter == "pending":
752                                 # TODO: look in message logs...
753                                 if node.reboot_trial_status != str(0) and \
754                                         node.reboot_trial_status != 'NetDown' and \
755                                         node.reboot_trial_status != 'Not_Run':
756
757                                         query.append(pcuagg)
758                                 
759                 return dict(query=query, fc=filtercount)
760
761         @expose(template="monitorweb.templates.sitelist")
762         def site(self, filter='all'):
763                 print "SITE------------------"
764                 print "befor-len: ", len( [ i for i in session] )
765                 session.flush(); session.clear()
766                 print "after-len: ", len( [ i for i in session] )
767                 filtercount = {'good' : 0, 'down': 0, 'online':0, 'offline' : 0, 'new' : 0, 'pending' : 0, 'all' : 0}
768                 fbquery = HistorySiteRecord.query.all()
769                 query = []
770                 for site in fbquery:
771                         # count filter
772                         filtercount['all'] += 1
773                         if site.new and site.slices_used == 0 and not site.enabled:
774                                 filtercount['new'] += 1
775                         elif not site.enabled:
776                                 filtercount['pending'] += 1
777                         elif site.status in ['good', 'online']:
778                                 filtercount['good'] += 1
779                         elif site.status in ['down', 'offline']:
780                                 filtercount['down'] += 1
781
782                         # apply filter
783                         if filter == "all":
784                                 query.append(site)
785                         elif filter == 'new' and site.new and site.slices_used == 0 and not site.enabled:
786                                 query.append(site)
787                         elif filter == "pending" and not site.enabled:
788                                 query.append(site)
789                         elif filter == 'good' and site.status in ['good', 'online']:
790                                 query.append(site)
791                         elif filter == 'down' and site.status in ['down', 'offline']:
792                                 query.append(site)
793                                 
794                 return dict(query=query, fc=filtercount)
795         @expose(template="monitorweb.templates.sitesummary")
796         def sitesummary(self, loginbase="princeton"):
797                 nodequery = []
798                 for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
799                         agg = prep_node_for_display(node)
800                         nodequery += [agg]
801                 
802                 return dict(nodequery=nodequery, loginbase=loginbase)
803
804         @expose(template="monitorweb.templates.summary")
805         def summary(self, since=7):
806                 sumdata = {}
807                 sumdata['nodes'] = {}
808                 sumdata['sites'] = {}
809                 sumdata['pcus'] = {}
810
811                 def summarize(query, type):
812                         for o in query:
813                                 if o.status not in sumdata[type]:
814                                         sumdata[type][o.status] = 0
815                                 sumdata[type][o.status] += 1
816
817                 fbquery = HistorySiteRecord.query.all()
818                 summarize(fbquery, 'sites')
819                 fbquery = HistoryPCURecord.query.all()
820                 summarize(fbquery, 'pcus')
821                 fbquery = HistoryNodeRecord.query.all()
822                 summarize(fbquery, 'nodes')
823
824                 if 'monitordebug' in sumdata['nodes']:
825                         d = sumdata['nodes']['monitordebug']
826                         del sumdata['nodes']['monitordebug']
827                         sumdata['nodes']['failboot'] = d
828                 
829                 return dict(sumdata=sumdata, setorder=['good', 'offline', 'down', 'online']) 
830
831         @expose(template="monitorweb.templates.actionsummary")
832         def actionsummary(self, since=7):
833                 from monitor.wrapper.emailTxt import mailtxt
834
835                 types = filter(lambda x: 'notice' in x, dir(mailtxt))
836                 results = {}
837
838                 print mon_metadata.bind
839                 if session.bind is None:
840                         #TODO: figure out why this value gets cleared out...
841                         session.bind = mon_metadata.bind
842                 result = session.execute("select distinct(action_type) from actionrecord;")
843
844                 types = [r[0] for r in result]
845
846                 try: since = int(since)
847                 except: since = 7
848
849                 for  t in types:
850                         acts = ActionRecord.query.filter(ActionRecord.action_type==t
851                                         ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since))
852                         results[t] = acts.count()
853                 return dict(results=results)
854
855         @expose(template="monitorweb.templates.actionlist")
856         def actionlist(self, since=7, action_type=None, loginbase=None):
857
858                 try: since = int(since)
859                 except: since = 7
860
861                 acts_query = ActionRecord.query.filter(
862                                           ActionRecord.date_created >= datetime.now() - timedelta(since)
863                                          )
864                 if loginbase:
865                         acts_query = acts_query.filter_by(loginbase=loginbase)
866
867                 if action_type:
868                         acts_query = acts_query.filter(ActionRecord.action_type==action_type)
869
870                 acts = acts_query.order_by(ActionRecord.date_created.desc())
871
872                 query = [ a for a in acts ]
873                 
874                 return dict(actions=query, action_type=action_type, since=since)
875
876         @cherrypy.expose()
877         def upload(self, log, **keywords):
878                 hostname = None
879                 logtype = None
880                 logtype_list = ['bm.log', ]
881
882                 if 'hostname' in keywords:
883                         hostname = keywords['hostname']
884                 if 'type' in keywords and keywords['type'] in logtype_list:
885                         logtype = keywords['type']
886
887                 if not hostname: return ""
888                 if not logtype: return "unknown logtype: %s" % logtype 
889
890                 short_target_filename = bootman.bootmanager_log_name(hostname)
891                 abs_target_filename = os.path.join(config.MONITOR_BOOTMANAGER_LOG, short_target_filename)
892                 print "write data: %s" % abs_target_filename
893                 util.file.dumpFile(abs_target_filename, log.file.read())
894                 bootman.bootmanager_log_action(hostname, short_target_filename, logtype)
895                 session.flush()
896
897                 print "redirecting 3"
898
899                 return dict()