update of all changes in the last week that fine-tuned the behavior of Monitor
[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 import util.file
16
17 import time
18 import re
19
20 #fb = {}
21 fb = None
22 fbpcu = None
23
24 class NoKeyException(Exception): pass
25
26 def daysdown_print_nodeinfo(fbnode, hostname):
27         fbnode['hostname'] = hostname
28         fbnode['daysdown'] = Record.getStrDaysDown(fbnode)
29         fbnode['intdaysdown'] = Record.getDaysDown(fbnode)
30
31         print "%(intdaysdown)5s %(hostname)-44s | %(state)10.10s | %(daysdown)s" % fbnode
32
33 def fb_print_nodeinfo(fbnode, hostname, fields=None):
34         fbnode['hostname'] = hostname
35         fbnode['checked'] = diff_time(fbnode['checked'])
36         if fbnode['bootcd']:
37                 fbnode['bootcd'] = fbnode['bootcd'].split()[-1]
38         else:
39                 fbnode['bootcd'] = "unknown"
40         fbnode['pcu'] = color_pcu_state(fbnode)
41
42         if not fields:
43                 if 'ERROR' in fbnode['category']:
44                         fbnode['kernel'] = ""
45                 else:
46                         fbnode['kernel'] = fbnode['kernel'].split()[2]
47                 fbnode['boot_state'] = fbnode['plcnode']['boot_state']
48
49                 if len(fbnode['nodegroups']) > 0:
50                         fbnode['category'] = fbnode['nodegroups'][0]
51
52                 print "%(hostname)-45s | %(checked)11.11s | %(boot_state)5.5s| %(state)8.8s | %(ssh)5.5s | %(pcu)6.6s | %(bootcd)6.6s | %(category)8.8s | %(kernel)s" % fbnode
53         else:
54                 format = ""
55                 for f in fields:
56                         format += "%%(%s)s " % f
57                 print format % fbnode
58
59 def get(fb, path):
60     indexes = path.split("/")
61     values = fb
62     for index in indexes:
63         if index in values:
64             values = values[index]
65         else:
66             raise NoKeyException(index)
67     return values
68
69 def verifyType(constraints, data):
70         """
71                 constraints is a list of key, value pairs.
72                 # [ {... : ...}==AND , ... , ... , ] == OR
73         """
74         con_or_true = False
75         for con in constraints:
76                 #print "con: %s" % con
77                 if len(con.keys()) == 0:
78                         con_and_true = False
79                 else:
80                         con_and_true = True
81
82                 for key in con.keys():
83                         #print "looking at key: %s" % key
84                         if data is None:
85                                 con_and_true = False
86                                 break
87
88                         try:
89                                 get(data,key)
90                                 o = con[key]
91                                 if o.name() == "Match":
92                                         if get(data,key) is not None:
93                                                 value_re = re.compile(o.value)
94                                                 con_and_true = con_and_true & (value_re.search(get(data,key)) is not None)
95                                         else:
96                                                 con_and_true = False
97                                 elif o.name() == "ListMatch":
98                                         if get(data,key) is not None:
99                                                 match = False
100                                                 for listitem in get(data,key):
101                                                         value_re = re.compile(o.value)
102                                                         if value_re.search(listitem) is not None:
103                                                                 match = True
104                                                                 break
105                                                 con_and_true = con_and_true & match
106                                         else:
107                                                 con_and_true = False
108                                 elif o.name() == "Is":
109                                         con_and_true = con_and_true & (get(data,key) == o.value)
110                                 elif o.name() == "FilledIn":
111                                         con_and_true = con_and_true & (len(get(data,key)) > 0)
112                                 elif o.name() == "PortOpen":
113                                         if get(data,key) is not None:
114                                                 v = get(data,key)
115                                                 con_and_true = con_and_true & (v[str(o.value)] == "open")
116                                         else:
117                                                 con_and_true = False
118                                 else:
119                                         value_re = re.compile(o.value)
120                                         con_and_true = con_and_true & (value_re.search(get(data,key)) is not None)
121
122                         except NoKeyException, key:
123                                 print "missing key %s" % key,
124                                 pass
125                                 #print "missing key %s" % key
126                                 #con_and_true = False
127
128                 con_or_true = con_or_true | con_and_true
129
130         return con_or_true
131
132 def verify(constraints, data):
133         """
134                 constraints is a list of key, value pairs.
135                 # [ {... : ...}==AND , ... , ... , ] == OR
136         """
137         con_or_true = False
138         for con in constraints:
139                 #print "con: %s" % con
140                 if len(con.keys()) == 0:
141                         con_and_true = False
142                 else:
143                         con_and_true = True
144
145                 for key in con.keys():
146                         #print "looking at key: %s" % key
147                         if key in data: 
148                                 value_re = re.compile(con[key])
149                                 if type([]) == type(data[key]):
150                                         local_or_true = False
151                                         for val in data[key]:
152                                                 local_or_true = local_or_true | (value_re.search(val) is not None)
153                                         con_and_true = con_and_true & local_or_true
154                                 else:
155                                         con_and_true = con_and_true & (value_re.search(data[key]) is not None)
156                         elif key not in data:
157                                 print "missing key %s" % key,
158                                 pass
159                                 #print "missing key %s" % key
160                                 #con_and_true = False
161
162                 con_or_true = con_or_true | con_and_true
163
164         return con_or_true
165
166 def query_to_dict(query):
167         
168         ad = []
169
170         or_queries = query.split('||')
171         for or_query in or_queries:
172                 and_queries = or_query.split('&&')
173
174                 d = {}
175
176                 for and_query in and_queries:
177                         (key, value) = and_query.split('=')
178                         d[key] = value
179
180                 ad.append(d)
181         
182         return ad
183
184 def pcu_in(fbdata):
185         if 'plcnode' in fbdata:
186                 if 'pcu_ids' in fbdata['plcnode']:
187                         if len(fbdata['plcnode']['pcu_ids']) > 0:
188                                 return True
189         return False
190
191 def pcu_select(str_query, nodelist=None):
192         global fb
193         global fbpcu
194         pcunames = []
195         nodenames = []
196         if str_query is None: return (nodenames, pcunames)
197
198         if fb is None:
199                 fb = database.dbLoad("findbad")
200         if fbpcu is None:
201                 fbpcu = database.dbLoad("findbadpcus")
202
203         #print str_query
204         dict_query = query_to_dict(str_query)
205         #print dict_query
206
207         for node in fb['nodes'].keys():
208                 if nodelist is not None: 
209                         if node not in nodelist: continue
210         
211                 fb_nodeinfo  = fb['nodes'][node]['values']
212                 if pcu_in(fb_nodeinfo):
213                         pcuinfo = fbpcu['nodes']['id_%s' % fb_nodeinfo['plcnode']['pcu_ids'][0]]['values']
214                         if verify(dict_query, pcuinfo):
215                                 nodenames.append(node)
216                                 str = "cmdhttps/locfg.pl -s %s -f iloxml/License.xml -u %s -p '%s' | grep MESSAGE" % \
217                                                         (pcu_name(pcuinfo), pcuinfo['username'], pcuinfo['password'])
218                                 #pcunames.append(str)
219                                 pcunames.append(pcuinfo['pcu_id'])
220         return (nodenames, pcunames)
221
222 def node_select(str_query, nodelist=None, fbdb=None):
223         global fb
224
225         hostnames = []
226         if str_query is None: return hostnames
227
228         #print str_query
229         dict_query = query_to_dict(str_query)
230         #print dict_query
231
232         if fbdb is not None:
233                 fb = fbdb
234
235         for node in fb['nodes'].keys():
236                 if nodelist is not None: 
237                         if node not in nodelist: continue
238         
239                 fb_nodeinfo  = fb['nodes'][node]['values']
240
241                 if fb_nodeinfo == []:
242                         #print node, "has lost values"
243                         continue
244                         #sys.exit(1)
245                 fb_nodeinfo['pcu'] = color_pcu_state(fb_nodeinfo)
246                 fb_nodeinfo['hostname'] = node
247                 if 'plcnode' in fb_nodeinfo:
248                         fb_nodeinfo.update(fb_nodeinfo['plcnode'])
249
250                 if verify(dict_query, fb_nodeinfo):
251                         #print node #fb_nodeinfo
252                         hostnames.append(node)
253                 else:
254                         #print "NO MATCH", node
255                         pass
256         
257         return hostnames
258
259
260 def main():
261         global fb
262         global fbpcu
263
264         import parser as parsermodule
265         parser = parsermodule.getParser()
266
267         parser.set_defaults(node=None, fromtime=None, select=None, list=None, 
268                                                 pcuselect=None, nodelist=None, daysdown=None, fields=None)
269         parser.add_option("", "--daysdown", dest="daysdown", action="store_true",
270                                                 help="List the node state and days down...")
271         parser.add_option("", "--select", dest="select", metavar="key=value", 
272                                                 help="List all nodes with the given key=value pattern")
273         parser.add_option("", "--fields", dest="fields", metavar="key,list,...", 
274                                                 help="a list of keys to display for each entry.")
275         parser.add_option("", "--list", dest="list", action="store_true", 
276                                                 help="Write only the hostnames as output.")
277         parser.add_option("", "--pcuselect", dest="pcuselect", metavar="key=value", 
278                                                 help="List all nodes with the given key=value pattern")
279         parser.add_option("", "--nodelist", dest="nodelist", metavar="nodelist.txt", 
280                                                 help="A list of nodes to bring out of debug mode.")
281         parser.add_option("", "--fromtime", dest="fromtime", metavar="YYYY-MM-DD",
282                                         help="Specify a starting date from which to begin the query.")
283
284         parser = parsermodule.getParser(['defaults'], parser)
285         config = parsermodule.parse_args(parser)
286         
287         if config.fromtime:
288                 path = "archive-pdb"
289                 archive = database.SPickle(path)
290                 d = datetime_fromstr(config.fromtime)
291                 glob_str = "%s*.production.findbad.pkl" % d.strftime("%Y-%m-%d")
292                 os.chdir(path)
293                 #print glob_str
294                 file = glob.glob(glob_str)[0]
295                 #print "loading %s" % file
296                 os.chdir("..")
297                 fb = archive.load(file[:-4])
298         else:
299                 fb = database.dbLoad("findbad")
300
301         fbpcu = database.dbLoad("findbadpcus")
302         reboot.fb = fbpcu
303
304         if config.nodelist:
305                 nodelist = util.file.getListFromFile(config.nodelist)
306         else:
307                 nodelist = fb['nodes'].keys()
308
309         pculist = None
310         if config.select is not None and config.pcuselect is not None:
311                 nodelist = node_select(config.select, nodelist, fb)
312                 nodelist, pculist = pcu_select(config.pcuselect, nodelist)
313         elif config.select is not None:
314                 nodelist = node_select(config.select, nodelist, fb)
315         elif config.pcuselect is not None:
316                 nodelist, pculist = pcu_select(config.pcuselect, nodelist)
317
318         if pculist:
319                 for pcu in pculist:
320                         print pcu
321
322         for node in nodelist:
323                 config.node = node
324
325                 if node not in fb['nodes']:
326                         continue
327
328                 fb_nodeinfo  = fb['nodes'][node]['values']
329
330                 if config.list:
331                         print node
332                 else:
333                         if config.daysdown:
334                                 daysdown_print_nodeinfo(fb_nodeinfo, node)
335                         else:
336                                 if config.select:
337                                         if config.fields:
338                                                 fields = config.fields.split(",")
339                                         else:
340                                                 fields = None
341
342                                         fb_print_nodeinfo(fb_nodeinfo, node, fields)
343                                 elif not config.select and 'state' in fb_nodeinfo:
344                                         fb_print_nodeinfo(fb_nodeinfo, node)
345                                 else:
346                                         pass
347                 
348 if __name__ == "__main__":
349         main()