use new monitor.database for data model import
[monitor.git] / nodequery.py
1 #!/usr/bin/python
2
3 import plc
4 api = plc.getAuthAPI()
5
6 import sys
7 import database
8 from nodecommon import *
9 #from policy import Diagnose
10 from unified_model import Record
11 import glob
12 import os
13 from reboot import pcu_name
14 import reboot
15 from monitor import util
16 import traceback
17
18 import time
19 import re
20
21 import config
22
23 from monitor.database import FindbadNodeRecord, FindbadNodeRecordSync
24 #from sqlobject import connectionForURI,sqlhub
25 #connection = connectionForURI(config.sqlobjecturi)
26 #sqlhub.processConnection = connection
27 #from infovacuum.model.findbadrecord import *
28
29 #fb = {}
30 fb = None
31 fbpcu = None
32 import string
33
34 class NoKeyException(Exception): pass
35
36 def daysdown_print_nodeinfo(fbnode, hostname):
37         fbnode['hostname'] = hostname
38         fbnode['daysdown'] = Record.getStrDaysDown(fbnode)
39         fbnode['intdaysdown'] = Record.getDaysDown(fbnode)
40
41         print "%(intdaysdown)5s %(hostname)-44s | %(state)10.10s | %(daysdown)s" % fbnode
42
43 def fb_print_nodeinfo(fbnode, hostname, fields=None):
44         #fbnode['hostname'] = hostname
45         #fbnode['checked'] = diff_time(fbnode['checked'])
46         if fbnode['bootcd_version']:
47                 fbnode['bootcd_version'] = fbnode['bootcd_version'].split()[-1]
48         else:
49                 fbnode['bootcd_version'] = "unknown"
50         fbnode['pcu'] = color_pcu_state(fbnode)
51
52         if not fields:
53                 if ( fbnode['observed_status'] is not None and \
54                    'DOWN' in fbnode['observed_status'] ) or \
55                    fbnode['kernel_version'] is None:
56                         fbnode['kernel_version'] = ""
57                 else:
58                         fbnode['kernel_version'] = fbnode['kernel_version'].split()[2]
59
60                 if fbnode['plc_node_stats'] is not None:
61                         fbnode['boot_state'] = fbnode['plc_node_stats']['boot_state']
62                 else:
63                         fbnode['boot_state'] = "unknown"
64
65                 try:
66                         if len(fbnode['nodegroups']) > 0:
67                                 fbnode['category'] = fbnode['nodegroups'][0]
68                 except:
69                         #print "ERROR!!!!!!!!!!!!!!!!!!!!!"
70                         pass
71
72                 print "%(hostname)-45s | %(date_checked)11.11s | %(boot_state)5.5s| %(observed_status)8.8s | %(ssh_status)5.5s | %(pcu)6.6s | %(bootcd_version)6.6s | %(kernel_version)s" % fbnode
73         else:
74                 format = ""
75                 for f in fields:
76                         format += "%%(%s)s " % f
77                 print format % fbnode
78
79 def get(fb, path):
80     indexes = path.split("/")
81     values = fb
82     for index in indexes:
83         if index in values:
84             values = values[index]
85         else:
86             raise NoKeyException(index)
87     return values
88
89 def verifyType(constraints, data):
90         """
91                 constraints is a list of key, value pairs.
92                 # [ {... : ...}==AND , ... , ... , ] == OR
93         """
94         con_or_true = False
95         for con in constraints:
96                 #print "con: %s" % con
97                 if len(con.keys()) == 0:
98                         con_and_true = False
99                 else:
100                         con_and_true = True
101
102                 for key in con.keys():
103                         #print "looking at key: %s" % key
104                         if data is None:
105                                 con_and_true = False
106                                 break
107
108                         try:
109                                 get(data,key)
110                                 o = con[key]
111                                 if o.name() == "Match":
112                                         if get(data,key) is not None:
113                                                 value_re = re.compile(o.value)
114                                                 con_and_true = con_and_true & (value_re.search(get(data,key)) is not None)
115                                         else:
116                                                 con_and_true = False
117                                 elif o.name() == "ListMatch":
118                                         if get(data,key) is not None:
119                                                 match = False
120                                                 for listitem in get(data,key):
121                                                         value_re = re.compile(o.value)
122                                                         if value_re.search(listitem) is not None:
123                                                                 match = True
124                                                                 break
125                                                 con_and_true = con_and_true & match
126                                         else:
127                                                 con_and_true = False
128                                 elif o.name() == "Is":
129                                         con_and_true = con_and_true & (get(data,key) == o.value)
130                                 elif o.name() == "FilledIn":
131                                         con_and_true = con_and_true & (len(get(data,key)) > 0)
132                                 elif o.name() == "PortOpen":
133                                         if get(data,key) is not None:
134                                                 v = get(data,key)
135                                                 con_and_true = con_and_true & (v[str(o.value)] == "open")
136                                         else:
137                                                 con_and_true = False
138                                 else:
139                                         value_re = re.compile(o.value)
140                                         con_and_true = con_and_true & (value_re.search(get(data,key)) is not None)
141
142                         except NoKeyException, key:
143                                 print "missing key %s" % key,
144                                 pass
145                                 #print "missing key %s" % key
146                                 #con_and_true = False
147
148                 con_or_true = con_or_true | con_and_true
149
150         return con_or_true
151
152 def verifyDBrecord(constraints, record):
153         """
154                 constraints is a list of key, value pairs.
155                 # [ {... : ...}==AND , ... , ... , ] == OR
156         """
157         def has_key(obj, key):
158                 try:
159                         x = obj.__getattribute__(key)
160                         return True
161                 except:
162                         return False
163
164         def get_val(obj, key):
165                 try:
166                         return obj.__getattribute__(key)
167                 except:
168                         return None
169
170         def get(obj, path):
171                 indexes = path.split("/")
172                 value = get_val(obj,indexes[0])
173                 if value is not None and len(indexes) > 1:
174                         for key in indexes[1:]:
175                                 if key in value:
176                                         value = value[key]
177                                 else:
178                                         raise NoKeyException(key)
179                 return value
180
181         #print constraints, record
182
183         con_or_true = False
184         for con in constraints:
185                 #print "con: %s" % con
186                 if len(con.keys()) == 0:
187                         con_and_true = False
188                 else:
189                         con_and_true = True
190
191                 for key in con.keys():
192                         #print "looking at key: %s" % key
193                         if has_key(record, key):
194                                 value_re = re.compile(con[key])
195                                 if type([]) == type(get(record,key)):
196                                         local_or_true = False
197                                         for val in get(record,key):
198                                                 local_or_true = local_or_true | (value_re.search(val) is not None)
199                                         con_and_true = con_and_true & local_or_true
200                                 else:
201                                         if get(record,key) is not None:
202                                                 con_and_true = con_and_true & (value_re.search(get(record,key)) is not None)
203                         else:
204                                 print "missing key %s" % key,
205                                 pass
206
207                 con_or_true = con_or_true | con_and_true
208
209         return con_or_true
210
211 def verify(constraints, data):
212         """
213                 constraints is a list of key, value pairs.
214                 # [ {... : ...}==AND , ... , ... , ] == OR
215         """
216         con_or_true = False
217         for con in constraints:
218                 #print "con: %s" % con
219                 if len(con.keys()) == 0:
220                         con_and_true = False
221                 else:
222                         con_and_true = True
223
224                 for key in con.keys():
225                         #print "looking at key: %s" % key
226                         if key in data: 
227                                 value_re = re.compile(con[key])
228                                 if type([]) == type(data[key]):
229                                         local_or_true = False
230                                         for val in data[key]:
231                                                 local_or_true = local_or_true | (value_re.search(val) is not None)
232                                         con_and_true = con_and_true & local_or_true
233                                 else:
234                                         if data[key] is not None:
235                                                 con_and_true = con_and_true & (value_re.search(data[key]) is not None)
236                         elif key not in data:
237                                 print "missing key %s" % key,
238                                 pass
239
240                 con_or_true = con_or_true | con_and_true
241
242         return con_or_true
243
244 def query_to_dict(query):
245         
246         ad = []
247
248         or_queries = query.split('||')
249         for or_query in or_queries:
250                 and_queries = or_query.split('&&')
251
252                 d = {}
253
254                 for and_query in and_queries:
255                         (key, value) = and_query.split('=')
256                         d[key] = value
257
258                 ad.append(d)
259         
260         return ad
261
262 def pcu_in(fbdata):
263         if 'plcnode' in fbdata:
264                 if 'pcu_ids' in fbdata['plcnode']:
265                         if len(fbdata['plcnode']['pcu_ids']) > 0:
266                                 return True
267         return False
268
269 def pcu_select(str_query, nodelist=None):
270         global fb
271         global fbpcu
272         pcunames = []
273         nodenames = []
274         if str_query is None: return (nodenames, pcunames)
275
276         if fb is None:
277                 fb = database.dbLoad("findbad")
278         if fbpcu is None:
279                 fbpcu = database.dbLoad("findbadpcus")
280
281         #print str_query
282         dict_query = query_to_dict(str_query)
283         #print dict_query
284
285         for node in fb['nodes'].keys():
286                 if nodelist is not None: 
287                         if node not in nodelist: continue
288         
289                 fb_nodeinfo  = fb['nodes'][node]['values']
290                 if pcu_in(fb_nodeinfo):
291                         pcuinfo = fbpcu['nodes']['id_%s' % fb_nodeinfo['plcnode']['pcu_ids'][0]]['values']
292                         if verify(dict_query, pcuinfo):
293                                 nodenames.append(node)
294                                 str = "cmdhttps/locfg.pl -s %s -f iloxml/License.xml -u %s -p '%s' | grep MESSAGE" % \
295                                                         (pcu_name(pcuinfo), pcuinfo['username'], pcuinfo['password'])
296                                 #pcunames.append(str)
297                                 pcunames.append(pcuinfo['pcu_id'])
298         return (nodenames, pcunames)
299
300 def node_select(str_query, nodelist=None, fbdb=None):
301         global fb
302
303         hostnames = []
304         if str_query is None: return hostnames
305
306         #print str_query
307         dict_query = query_to_dict(str_query)
308         #print dict_query
309
310         if fbdb is not None:
311                 fb = fbdb
312
313         for node in fb['nodes'].keys():
314                 if nodelist is not None: 
315                         if node not in nodelist: continue
316
317                 try:
318                         fb_noderec = FindbadNodeRecord.select(FindbadNodeRecord.q.hostname==node, 
319                                                                                            orderBy='date_checked').reversed()[0]
320                 except:
321                         continue
322
323                 
324                 fb_nodeinfo = fb_noderec.toDict()
325
326                 #fb_nodeinfo['pcu'] = color_pcu_state(fb_nodeinfo)
327                 #if 'plcnode' in fb_nodeinfo:
328                 #       fb_nodeinfo.update(fb_nodeinfo['plcnode'])
329
330                 #if verifyDBrecord(dict_query, fb_nodeinfo):
331                 if verify(dict_query, fb_nodeinfo):
332                         #print node #fb_nodeinfo
333                         hostnames.append(node)
334                 else:
335                         #print "NO MATCH", node
336                         pass
337         
338         return hostnames
339
340
341 def main():
342         global fb
343         global fbpcu
344
345         import parser as parsermodule
346         parser = parsermodule.getParser()
347
348         parser.set_defaults(node=None, fromtime=None, select=None, list=None, 
349                                                 pcuselect=None, nodelist=None, daysdown=None, fields=None)
350         parser.add_option("", "--daysdown", dest="daysdown", action="store_true",
351                                                 help="List the node state and days down...")
352         parser.add_option("", "--select", dest="select", metavar="key=value", 
353                                                 help="List all nodes with the given key=value pattern")
354         parser.add_option("", "--fields", dest="fields", metavar="key,list,...", 
355                                                 help="a list of keys to display for each entry.")
356         parser.add_option("", "--list", dest="list", action="store_true", 
357                                                 help="Write only the hostnames as output.")
358         parser.add_option("", "--pcuselect", dest="pcuselect", metavar="key=value", 
359                                                 help="List all nodes with the given key=value pattern")
360         parser.add_option("", "--nodelist", dest="nodelist", metavar="nodelist.txt", 
361                                                 help="A list of nodes to bring out of debug mode.")
362         parser.add_option("", "--fromtime", dest="fromtime", metavar="YYYY-MM-DD",
363                                         help="Specify a starting date from which to begin the query.")
364
365         parser = parsermodule.getParser(['defaults'], parser)
366         config = parsermodule.parse_args(parser)
367         
368         if config.fromtime:
369                 path = "archive-pdb"
370                 archive = database.SPickle(path)
371                 d = datetime_fromstr(config.fromtime)
372                 glob_str = "%s*.production.findbad.pkl" % d.strftime("%Y-%m-%d")
373                 os.chdir(path)
374                 #print glob_str
375                 file = glob.glob(glob_str)[0]
376                 #print "loading %s" % file
377                 os.chdir("..")
378                 fb = archive.load(file[:-4])
379         else:
380                 fbnodes = FindbadNodeRecord.select(FindbadNodeRecord.q.hostname, orderBy='date_checked',distinct=True).reversed()
381                 fb = database.dbLoad("findbad")
382
383         fbpcu = database.dbLoad("findbadpcus")
384         reboot.fb = fbpcu
385
386         if config.nodelist:
387                 nodelist = util.file.getListFromFile(config.nodelist)
388         else:
389                 nodelist = fb['nodes'].keys()
390
391         pculist = None
392         if config.select is not None and config.pcuselect is not None:
393                 nodelist = node_select(config.select, nodelist, fb)
394                 nodelist, pculist = pcu_select(config.pcuselect, nodelist)
395         elif config.select is not None:
396                 nodelist = node_select(config.select, nodelist, fb)
397         elif config.pcuselect is not None:
398                 nodelist, pculist = pcu_select(config.pcuselect, nodelist)
399
400         if pculist:
401                 for pcu in pculist:
402                         print pcu
403
404         for node in nodelist:
405                 config.node = node
406
407                 if node not in fb['nodes']:
408                         continue
409
410                 try:
411                         # Find the most recent record
412                         fb_noderec = FindbadNodeRecord.select(FindbadNodeRecord.q.hostname==node, 
413                                                                                            orderBy='date_checked').reversed()[0]
414                 except:
415                         print traceback.print_exc()
416                         pass #fb_nodeinfo  = fb['nodes'][node]['values']
417
418                 if config.list:
419                         print node
420                 else:
421                         if config.daysdown:
422                                 daysdown_print_nodeinfo(fb_nodeinfo, node)
423                         else:
424                                 fb_nodeinfo = fb_noderec.toDict()
425                                 if config.select:
426                                         if config.fields:
427                                                 fields = config.fields.split(",")
428                                         else:
429                                                 fields = None
430
431                                         fb_print_nodeinfo(fb_nodeinfo, node, fields)
432                                 elif not config.select and 'state' in fb_nodeinfo:
433                                         fb_print_nodeinfo(fb_nodeinfo, node)
434                                 else:
435                                         pass
436                 
437 if __name__ == "__main__":
438         main()