e5d0da25a7580c85ece1138476419307f06ec753
[monitor.git] / web / MonitorWeb / monitorweb / controllers.py
1 import turbogears as tg
2 from turbogears import controllers, expose, flash, exception_handler
3 from cherrypy import request, response
4 import cherrypy
5 # from monitorweb import model
6 # import logging
7 # log = logging.getLogger("monitorweb.controllers")
8 import re
9 from monitor.database.info.model import *
10 from monitor.database.zabbixapi.model import *
11 from monitor.database.dborm import zab_session as session
12 from monitor.database.dborm import zab_metadata as metadata
13
14 from pcucontrol import reboot
15 from monitor.wrapper.plccache import plcdb_id2lb as site_id2lb
16 from monitor.wrapper.plccache import plcdb_hn2lb as site_hn2lb
17 from monitor.wrapper.plccache import plcdb_lb2hn as site_lb2hn
18
19 from monitorweb.templates.links import *
20
21 import findbad
22
23 def format_ports(pcu):
24         retval = []
25         if pcu.port_status and len(pcu.port_status.keys()) > 0 :
26                 obj = reboot.model_to_object(pcu.plc_pcu_stats['model'])
27                 for port in obj.supported_ports:
28                         try:
29                                 state = pcu.port_status[str(port)]
30                         except:
31                                 state = "unknown"
32                                 
33                         retval.append( (port, state) )
34
35         if retval == []: 
36                 retval = [( "Closed/Filtered", "state" )]
37
38         return retval
39
40 def format_pcu_shortstatus(pcu):
41         status = "error"
42         if pcu:
43                 if pcu.reboot_trial_status == str(0):
44                         status = "ok"
45                 elif pcu.reboot_trial_status == "NetDown" or pcu.reboot_trial_status == "Not_Run":
46                         status = pcu.reboot_trial_status
47                 else:
48                         status = "error"
49
50         return status
51
52 def prep_pcu_for_display(pcu):
53                 
54         try:
55                 pcu.loginbase = site_id2lb[pcu.plc_pcu_stats['site_id']]
56         except:
57                 pcu.loginbase = "unknown"
58
59         pcu.ports = format_ports(pcu)
60         pcu.status = format_pcu_shortstatus(pcu)
61
62 def prep_node_for_display(node):
63         if node.plc_pcuid:
64                 pcu = FindbadPCURecord.get_latest_by(plc_pcuid=node.plc_pcuid).first()
65                 if pcu:
66                         node.pcu_status = pcu.reboot_trial_status
67                 else:
68                         node.pcu_status = "nodata"
69                 node.pcu_short_status = format_pcu_shortstatus(pcu)
70
71         else:
72                 node.pcu_status = "nopcu"
73                 node.pcu_short_status = "none"
74
75         if node.kernel_version:
76                 node.kernel = node.kernel_version.split()[2]
77         else:
78                 node.kernel = ""
79
80         try:
81                 node.loginbase = site_id2lb[node.plc_node_stats['site_id']]
82         except:
83                 node.loginbase = "unknown"
84         
85
86 class Root(controllers.RootController):
87         @expose(template="monitorweb.templates.welcome")
88         def index(self):
89                 import time
90                 # log.debug("Happy TurboGears Controller Responding For Duty")
91                 flash("Your application is now running")
92                 return dict(now=time.ctime())
93
94         @expose(template="monitorweb.templates.nodeview")
95         def nodeview(self, hostname=None):
96                 nodequery=[]
97                 if hostname:
98                         for node in FindbadNodeRecord.get_latest_by(hostname=hostname):
99                                 # NOTE: reformat some fields.
100                                 prep_node_for_display(node)
101                                 nodequery += [node]
102
103                 return dict(nodequery=nodequery)
104
105         @expose(template="monitorweb.templates.nodelist")
106         def node(self, filter='BOOT'):
107                 import time
108                 fbquery = FindbadNodeRecord.get_all_latest()
109                 query = []
110                 filtercount = {'DOWN' : 0, 'BOOT': 0, 'DEBUG' : 0, 'neverboot' : 0, 'pending' : 0, 'all' : 0}
111                 for node in fbquery:
112                         # NOTE: reformat some fields.
113                         prep_node_for_display(node)
114
115                         # NOTE: count filters
116                         if node.observed_status != 'DOWN':
117                                 filtercount[node.observed_status] += 1
118                         else:
119                                 if node.plc_node_stats['last_contact'] != None:
120                                         filtercount[node.observed_status] += 1
121                                 else:
122                                         filtercount['neverboot'] += 1
123
124                         # NOTE: apply filter
125                         if filter == node.observed_status:
126                                 if filter == "DOWN":
127                                         if node.plc_node_stats['last_contact'] != None:
128                                                 query.append(node)
129                                 else:
130                                         query.append(node)
131                         elif filter == "neverboot":
132                                 if node.plc_node_stats['last_contact'] == None:
133                                         query.append(node)
134                         elif filter == "pending":
135                                 # TODO: look in message logs...
136                                 pass
137                         elif filter == "all":
138                                 query.append(node)
139                                 
140                 return dict(now=time.ctime(), query=query, fc=filtercount)
141         
142         def nodeaction_handler(self, tg_exceptions=None):
143                 """Handle any kind of error."""
144                 refurl = request.headers.get("Referer",link("pcu"))
145                 print refurl
146                 # TODO: do this more intelligently...
147                 if len(urllib.splitquery(refurl)) > 1:
148                         pcuid = urllib.splitvalue(urllib.splitquery(refurl)[1])[1]
149                 else:
150                         pcuid=None
151
152                 cherry_trail = cherrypy._cputil.get_object_trail()
153                 for i in cherry_trail:
154                         print "trail: ", i
155
156                 print pcuid
157                 return self.pcuview(pcuid, **dict(exceptions=tg_exceptions))
158                 #return dict(pcuquery=[], nodequery=[], exceptions=tg_exceptions)
159
160         def nodeaction(self, **data):
161                 for item in data.keys():
162                         print "%s %s" % ( item, data[item] )
163
164                 if 'hostname' in data:
165                         hostname = data['hostname']
166                 else:
167                         flash("No hostname given in submitted data")
168                         return
169
170                 if 'submit' in data:
171                         action = data['submit']
172                 else:
173                         flash("No submit action given in submitted data")
174                         return
175
176                 if action == "Reboot":
177                         print "REBOOT: %s" % hostname
178                         ret = reboot.reboot_str(str(hostname))
179                         print ret
180                         if ret: raise RuntimeError("Error using PCU: " + ret)
181
182                 elif action == "ExternalProbe":
183                         raise RuntimeError("THIS IS A PROBLEM")
184
185                 elif action == "DeepProbe":
186                         findbad.probe(str(hostname))
187                 else:
188                         # unknown action
189                         flash("Unknown action given")
190                 return
191
192         # TODO: add form validation
193         @expose(template="monitorweb.templates.pcuview")
194         @exception_handler(nodeaction_handler,"isinstance(tg_exceptions,RuntimeError)")
195         def pcuview(self, pcuid=None, **data):
196                 pcuquery=[]
197                 nodequery=[]
198                 if 'submit' in data.keys():
199                         self.nodeaction(**data)
200                 if 'exceptions' in data:
201                         exceptions = data['exceptions']
202                 else:
203                         exceptions = None
204
205                 if pcuid:
206                         for pcu in FindbadPCURecord.get_latest_by(plc_pcuid=pcuid):
207                                 # NOTE: count filter
208                                 prep_pcu_for_display(pcu)
209                                 pcuquery += [pcu]
210                         for nodename in pcu.plc_pcu_stats['nodenames']: 
211                                 print "query for %s" % nodename
212                                 node = FindbadNodeRecord.get_latest_by(hostname=nodename).first()
213                                 print "%s" % node
214                                 if node:
215                                         prep_node_for_display(node)
216                                         nodequery += [node]
217                 return dict(pcuquery=pcuquery, nodequery=nodequery, exceptions=exceptions)
218
219         @expose(template="monitorweb.templates.pculist")
220         def pcu(self, filter='all'):
221                 import time
222                 fbquery = FindbadPCURecord.get_all_latest()
223                 query = []
224                 filtercount = {'ok' : 0, 'NetDown': 0, 'Not_Run' : 0, 'pending' : 0, 'all' : 0}
225                 for node in fbquery:
226
227                         # NOTE: count filter
228                         if node.reboot_trial_status == str(0):
229                                 filtercount['ok'] += 1
230                         elif node.reboot_trial_status == 'NetDown' or node.reboot_trial_status == 'Not_Run':
231                                 filtercount[node.reboot_trial_status] += 1
232                         else:
233                                 filtercount['pending'] += 1
234
235                         prep_pcu_for_display(node)
236
237                         # NOTE: apply filter
238                         if filter == "all":
239                                 query.append(node)
240                         elif filter == "ok" and node.reboot_trial_status == str(0):
241                                 query.append(node)
242                         elif filter == node.reboot_trial_status:
243                                 query.append(node)
244                         elif filter == "pending":
245                                 # TODO: look in message logs...
246                                 if node.reboot_trial_status != str(0) and \
247                                         node.reboot_trial_status != 'NetDown' and \
248                                         node.reboot_trial_status != 'Not_Run':
249
250                                         query.append(node)
251                                 
252                 return dict(query=query, fc=filtercount)
253
254         @expose(template="monitorweb.templates.siteview")
255         def siteview(self, loginbase='pl'):
256                 # get site query
257                 sitequery = [HistorySiteRecord.by_loginbase(loginbase)]
258                 nodequery = []
259                 for plcnode in site_lb2hn[loginbase]:
260                         for node in FindbadNodeRecord.get_latest_by(hostname=plcnode['hostname']):
261                                 # NOTE: reformat some fields.
262                                 prep_node_for_display(node)
263                                 nodequery += [node]
264                 return dict(sitequery=sitequery, nodequery=nodequery, fc={})
265
266         @expose(template="monitorweb.templates.sitelist")
267         def site(self, filter='all'):
268                 filtercount = {'good' : 0, 'down': 0, 'new' : 0, 'pending' : 0, 'all' : 0}
269                 fbquery = HistorySiteRecord.query.all()
270                 query = []
271                 for site in fbquery:
272                         # count filter
273                         filtercount['all'] += 1
274                         if site.new and site.slices_used == 0 and not site.enabled:
275                                 filtercount['new'] += 1
276                         elif not site.enabled:
277                                 filtercount['pending'] += 1
278                         else:
279                                 filtercount[site.status] += 1
280
281                         # apply filter
282                         if filter == "all":
283                                 query.append(site)
284                         elif filter == 'new' and site.new and site.slices_used == 0 and not site.enabled:
285                                 query.append(site)
286                         elif filter == "pending" and not site.enabled:
287                                 query.append(site)
288                         elif filter == site.status:
289                                 query.append(site)
290                                 
291                 return dict(query=query, fc=filtercount)
292
293         @expose(template="monitorweb.templates.actionlist")
294         def action(self, filter='all'):
295                 session.bind = metadata.bind
296                 filtercount = {'active' : 0, 'acknowledged': 0, 'all' : 0}
297                 # With Acknowledgement
298                 sql_ack = 'SELECT DISTINCT h.host,t.description,t.priority,t.lastchange,a.message '+ \
299               ' FROM triggers t,hosts h,items i,functions f, hosts_groups hg,escalations e,acknowledges a ' + \
300               ' WHERE f.itemid=i.itemid ' + \
301                   ' AND h.hostid=i.hostid ' + \
302                   ' AND hg.hostid=h.hostid ' + \
303                   ' AND t.triggerid=f.triggerid ' + \
304                   ' AND t.triggerid=e.triggerid ' + \
305                   ' AND a.eventid=e.eventid ' + \
306                   ' AND t.status=' + str(defines.TRIGGER_STATUS_ENABLED) + \
307                   ' AND i.status=' + str(defines.ITEM_STATUS_ACTIVE) + \
308                   ' AND h.status=' + str(defines.HOST_STATUS_MONITORED) + \
309                   ' AND t.value=' + str(defines.TRIGGER_VALUE_TRUE) + \
310               ' ORDER BY t.lastchange DESC';
311
312                 # WithOUT Acknowledgement
313                 sql_noack = 'SELECT DISTINCT h.host,t.description,t.priority,t.lastchange,e.eventid ' + \
314               ' FROM triggers t,hosts h,items i,functions f, hosts_groups hg,escalations e,acknowledges a ' + \
315               ' WHERE f.itemid=i.itemid ' + \
316                   ' AND h.hostid=i.hostid ' + \
317                   ' AND hg.hostid=h.hostid ' + \
318                   ' AND t.triggerid=f.triggerid ' + \
319                   ' AND t.triggerid=e.triggerid ' + \
320                   ' AND e.eventid not in (select eventid from acknowledges) ' + \
321                   ' AND t.status=' + str(defines.TRIGGER_STATUS_ENABLED) + \
322                   ' AND i.status=' + str(defines.ITEM_STATUS_ACTIVE) + \
323                   ' AND h.status=' + str(defines.HOST_STATUS_MONITORED) + \
324                   ' AND t.value=' + str(defines.TRIGGER_VALUE_TRUE) + \
325               ' ORDER BY t.lastchange DESC';
326                 # for i in session.execute(sql): print i
327
328                 query=[]
329                 replace = re.compile(' {.*}')
330                 for sql,ack in [(sql_ack,True), (sql_noack,False)]:
331                         result = session.execute(sql)
332                         for row in result:
333                                 try:
334                                         newrow = [ site_hn2lb[row[0].lower()] ] + [ r for r in row ]
335                                 except:
336                                         print site_hn2lb.keys()
337                                         newrow = [ "unknown" ] + [ r for r in row ]
338
339                                 newrow[2] = replace.sub("", newrow[2]) # strip {.*} expressions
340
341                                 # NOTE: filter count
342                                 filtercount['all'] += 1
343                                 if not ack: # for unacknowledged
344                                         filtercount['active'] += 1
345                                         if filter == 'active':
346                                                 query.append(newrow)
347                                 else:
348                                         filtercount['acknowledged'] += 1
349                                         if filter == 'acknowledged':
350                                                 query.append(newrow)
351                                         
352                                 if filter != "acknowledged" and filter != "active":
353                                         query.append(newrow)
354
355                 return dict(query=query, fc=filtercount)