clearer names for actions, and infer actions better
[monitor.git] / monitor / query.py
1 #!/usr/bin/python
2
3 import os
4 import re
5 import sys
6 import glob
7 import time
8 import string
9 import traceback
10
11 from monitor.common import *
12 from monitor.database.info.model import FindbadNodeRecord, FindbadPCURecord
13
14 class NoKeyException(Exception): pass
15
16 def first(path):
17         indexes = path.split(".")
18         return indexes[0]
19         
20 def get(fb, path):
21     indexes = path.split(".")
22     values = fb
23     for index in indexes:
24                 if values and index in values:
25                         values = values[index]
26                 elif values == {}:
27                         values = ""
28                 else:
29                         print values, index
30                         raise NoKeyException(index)
31     return values
32
33 def verifyType(constraints, data):
34         """
35                 constraints is a list of key, value pairs.
36                 # [ {... : ...}==AND , ... , ... , ] == OR
37         """
38         con_or_true = False
39         for con in constraints:
40                 #print "con: %s" % con
41                 if len(con.keys()) == 0:
42                         con_and_true = False
43                 else:
44                         con_and_true = True
45
46                 for key in con.keys():
47                         #print "looking at key: %s" % key
48                         if data is None:
49                                 con_and_true = False
50                                 break
51
52                         try:
53                                 get(data,key)
54                                 o = con[key]
55                                 if o.name() == "Match":
56                                         if get(data,key) is not None:
57                                                 value_re = re.compile(o.value)
58                                                 con_and_true = con_and_true & (value_re.search(get(data,key)) is not None)
59                                         else:
60                                                 con_and_true = False
61                                 elif o.name() == "ListMatch":
62                                         if get(data,key) is not None:
63                                                 match = False
64                                                 for listitem in get(data,key):
65                                                         value_re = re.compile(o.value)
66                                                         if value_re.search(listitem) is not None:
67                                                                 match = True
68                                                                 break
69                                                 con_and_true = con_and_true & match
70                                         else:
71                                                 con_and_true = False
72                                 elif o.name() == "Is":
73                                         con_and_true = con_and_true & (get(data,key) == o.value)
74                                 elif o.name() == "FilledIn":
75                                         con_and_true = con_and_true & (len(get(data,key)) > 0)
76                                 elif o.name() == "PortOpen":
77                                         if get(data,key) is not None:
78                                                 v = get(data,key)
79                                                 con_and_true = con_and_true & (v[str(o.value)] == "open")
80                                         else:
81                                                 con_and_true = False
82                                 else:
83                                         value_re = re.compile(o.value)
84                                         con_and_true = con_and_true & (value_re.search(get(data,key)) is not None)
85
86                         except NoKeyException, key:
87                                 print "missing key %s" % key,
88                                 pass
89                                 #print "missing key %s" % key
90                                 #con_and_true = False
91
92                 con_or_true = con_or_true | con_and_true
93
94         return con_or_true
95
96 def verifyDBrecord(constraints, record):
97         """
98                 constraints is a list of key, value pairs.
99                 # [ {... : ...}==AND , ... , ... , ] == OR
100         """
101         def has_key(obj, key):
102                 try:
103                         x = obj.__getattribute__(key)
104                         return True
105                 except:
106                         return False
107
108         def get_val(obj, key):
109                 try:
110                         return obj.__getattribute__(key)
111                 except:
112                         return None
113
114         def get(obj, path):
115                 indexes = path.split("/")
116                 value = get_val(obj,indexes[0])
117                 if value is not None and len(indexes) > 1:
118                         for key in indexes[1:]:
119                                 if key in value:
120                                         value = value[key]
121                                 else:
122                                         raise NoKeyException(key)
123                 return value
124
125         #print constraints, record
126
127         con_or_true = False
128         for con in constraints:
129                 #print "con: %s" % con
130                 if len(con.keys()) == 0:
131                         con_and_true = False
132                 else:
133                         con_and_true = True
134
135                 for key in con.keys():
136                         #print "looking at key: %s" % key
137                         if has_key(record, key):
138                                 value_re = re.compile(con[key])
139                                 if type([]) == type(get(record,key)):
140                                         local_or_true = False
141                                         for val in get(record,key):
142                                                 local_or_true = local_or_true | (value_re.search(val) is not None)
143                                         con_and_true = con_and_true & local_or_true
144                                 else:
145                                         if get(record,key) is not None:
146                                                 con_and_true = con_and_true & (value_re.search(get(record,key)) is not None)
147                         else:
148                                 print "missing key %s" % key,
149                                 pass
150
151                 con_or_true = con_or_true | con_and_true
152
153         return con_or_true
154
155 def verify(constraints, data):
156         """
157                 constraints is a list of key, value pairs.
158                 # [ {... : ...}==AND , ... , ... , ] == OR
159         """
160         con_or_true = False
161         for con in constraints:
162                 #print "con: %s" % con
163                 if len(con.keys()) == 0:
164                         con_and_true = False
165                 else:
166                         con_and_true = True
167
168                 for key in con.keys():
169                         #print "looking at key: %s" % key
170                         if first(key) in data: 
171                                 value_re = re.compile(con[key])
172                                 if type([]) == type(get(data,key)):
173                                         local_or_true = False
174                                         for val in get(data,key):
175                                                 local_or_true = local_or_true | (value_re.search(val) is not None)
176                                         con_and_true = con_and_true & local_or_true
177                                 else:
178                                         if get(data,key) is not None:
179                                                 con_and_true = con_and_true & (value_re.search(get(data,key)) is not None)
180                         elif first(key) not in data:
181                                 print "missing key %s" % first(key)
182
183                 con_or_true = con_or_true | con_and_true
184
185         return con_or_true
186
187 def query_to_dict(query):
188         
189         ad = []
190
191         or_queries = query.split('||')
192         for or_query in or_queries:
193                 and_queries = or_query.split('&&')
194
195                 d = {}
196
197                 for and_query in and_queries:
198                         (key, value) = and_query.split('=')
199                         d[key] = value
200
201                 ad.append(d)
202         
203         return ad
204
205 def pcu_in(fbdata):
206         #if 'plcnode' in fbdata:
207         if 'plc_node_stats' in fbdata:
208                 if fbdata['plc_node_stats'] and 'pcu_ids' in fbdata['plc_node_stats']:
209                         if len(fbdata['plc_node_stats']['pcu_ids']) > 0:
210                                 return True
211         return False
212
213 def pcu_select(str_query, nodelist=None):
214         pcunames = []
215         nodenames = []
216         if str_query is None: return (nodenames, pcunames)
217
218         if True:
219                 fbquery = FindbadNodeRecord.get_all_latest()
220                 fb_nodelist = [ n.hostname for n in fbquery ]
221         if True:
222                 # NOTE: this doesn't work when there are only a few records current.
223                 # pcu_select should apply to all pcus globally, not just the most recent records.
224                 fbpcuquery = FindbadPCURecord.get_all_latest()
225                 fbpcu_list = [ p.plc_pcuid for p in fbpcuquery ]
226
227         dict_query = query_to_dict(str_query)
228         print "dict_query", dict_query
229         print 'length %s' % len(fbpcuquery)
230
231         #for pcurec in fbpcuquery:
232         #       pcuinfo = pcurec.to_dict()
233         #       if verify(dict_query, pcuinfo):
234         #               #nodenames.append(noderec.hostname)
235         #               #print 'appending %s' % pcuinfo['plc_pcuid']
236         #               pcunames.append(pcuinfo['plc_pcuid'])
237
238         for noderec in fbquery:
239                 if nodelist is not None: 
240                         if noderec.hostname not in nodelist: continue
241         
242                 fb_nodeinfo  = noderec.to_dict()
243                 if pcu_in(fb_nodeinfo):
244                         pcu_id = get(fb_nodeinfo, 'plc_node_stats.pcu_ids')[0]
245                         pcurec = FindbadPCURecord.get_by(plc_pcuid=pcu_id)
246
247                         if pcurec:
248                                 pcuinfo = pcurec.to_dict()
249                                 if verify(dict_query, pcuinfo):
250                                         nodenames.append(noderec.hostname)
251                                         pcunames.append(pcuinfo['plc_pcuid'])
252
253         return (nodenames, pcunames)
254
255 def node_select(str_query, nodelist=None, fb=None):
256
257         hostnames = []
258         if str_query is None: return hostnames
259
260         #print str_query
261         dict_query = query_to_dict(str_query)
262         #print dict_query
263
264         for node in nodelist:
265                 #if nodelist is not None: 
266                 #       if node not in nodelist: continue
267
268                 try:
269                         fb_noderec = None
270                         #fb_noderec = FindbadNodeRecord.query.filter(FindbadNodeRecord.hostname==node).order_by(FindbadNodeRecord.date_checked.desc()).first()
271                         fb_noderec = FindbadNodeRecord.get_latest_by(hostname=node)
272                 except KeyboardInterrupt:
273                         print "Exiting at user request: Ctrl-C"
274                         sys.exit(1)
275                 except:
276                         print traceback.print_exc()
277                         continue
278
279                 if fb_noderec:
280                         fb_nodeinfo = fb_noderec.to_dict()
281
282                         #fb_nodeinfo['pcu'] = color_pcu_state(fb_nodeinfo)
283                         #if 'plcnode' in fb_nodeinfo:
284                         #       fb_nodeinfo.update(fb_nodeinfo['plcnode'])
285
286                         if verify(dict_query, fb_nodeinfo):
287                                 #print fb_nodeinfo.keys()
288                                 #print node #fb_nodeinfo
289                                 hostnames.append(node)
290                         else:
291                                 #print "NO MATCH", node
292                                 pass
293         
294         return hostnames
295
296