Merge branch 'master' of ssh://naparuba@shinken.git.sourceforge.net/gitroot/shinken...
[shinken.git] / shinken / dependencynode.py
blob862768ca9dad90907966ed96f778b8b110b91f87
1 #!/usr/bin/env python
2 # Copyright (C) 2009-2010 :
3 # Gabes Jean, naparuba@gmail.com
4 # Gerhard Lausser, Gerhard.Lausser@consol.de
6 # This file is part of Shinken.
8 # Shinken is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU Affero General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # Shinken is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU Affero General Public License for more details.
18 # You should have received a copy of the GNU Affero General Public License
19 # along with Shinken. If not, see <http://www.gnu.org/licenses/>.
22 """
23 Here is a node class for dependency_node(s) and a factory to create them
24 """
26 import re
28 #pat = "(h1;db | h2;db | h3;db) & (h4;Apache & h5;Apache & h6;Apache) & (h7;lvs | h8;lvs)"
29 #pat2 = "h1;db | h2;db"
30 #pat3 = "(h1;db | h2;db | h3;db) & (h4;Apache & h5;Apache)"
31 #pat4 = "2 of: h1;db | h2;db | h3;db"
33 class DependencyNode(object):
34 def __init__(self):
35 self.operand = None
36 self.sons = []
37 self.of_values = 0
39 def __str__(self):
40 return "Op:'%s' Val:'%s' Sons:'[%s]'" % (self.operand, self.of_values, ','.join([str(s) for s in self.sons]))
43 # We will get the state of this node, by looking at the state of
44 # our sons, and apply our operand
45 def get_state(self):
46 print "Ask state of me", self
48 # If we are a host or a service, wee just got the host/service
49 # hard state
50 if self.operand in ['host', 'service']:
51 state = self.sons[0].last_hard_state_id
52 print "Get the hard state (%s) for the object %s" % (state, self.sons[0].get_name())
53 # Make DOWN look as CRITICAL (2 instead of 1)
54 if self.operand == 'host' and state == 1:
55 state = 2
56 return state
58 # First we get teh state of all our sons
59 states = []
60 for s in self.sons:
61 st = s.get_state()
62 states.append(st)
64 # We will surely need the worse state
65 worse_state = max(states)
67 # We look for the better state but not OK/UP
68 no_ok = [s for s in states if s != 0]
69 if len(no_ok) != 0:
70 better_no_good = min(no_ok)
72 # Now look at the rule. For a or
73 if self.operand == '|':
74 if 0 in states:
75 print "We find a OK/UP match in an OR", states
76 return 0
77 # no ok/UP-> return worse state
78 else:
79 print "I send the better no good state...in an OR", better_no_good, states
80 return better_no_good
82 # With an AND, we just send the worse state
83 if self.operand == '&':
84 print "We raise worse state for a AND", worse_state,states
85 return worse_state
87 # Ok we've got a 'of:' rule
88 nb_search = self.of_values
89 # Look if we've got enouth 0
90 if len([s for s in states if s == 0]) >= nb_search:
91 print "Good, we find at least %d 0 in states for a of:" % nb_search, states
92 return 0
94 # Now maybe at least enouth WARNING, still beter than CRITICAL...
95 if len([s for s in states if s == 1]) >= nb_search:
96 print "Beter than nothing, we find at least %d 1 in states for a of:" % nb_search, states
97 return 1
99 # Sic... not good, return 2
100 print "ARG, not enough 1 or 0, return 2..."
101 return 2
104 #return a list of all host/service in our node and below
105 def list_all_elements(self):
106 r = []
108 #We are a host/service
109 if self.operand in ['host', 'service']:
110 return [self.sons[0]]
112 for s in self.sons:
113 r.extend(s.list_all_elements())
115 #and uniq the result
116 return list(set(r))
120 class DependencyNodeFactory(object):
121 def __init__(self):
122 pass
124 # the () will be eval in a recursiv way, only one level of ()
125 def eval_cor_patern(self, patern, hosts, services):
126 patern = patern.strip()
127 print "*****Loop", patern
128 complex_node = False
130 # Look if it's a complex patern (with rule) or
131 # if it's a leef ofit, like a host/service
132 for m in '()+&|':
133 if m in patern:
134 complex_node = True
136 is_of_nb = False
138 node = DependencyNode()
139 p = "^(\d+) *of: *(.+)"
140 r = re.compile(p)
141 m = r.search(patern)
142 if m != None:
143 print "Match the of: thing N=", m.groups()
144 node.operand = 'of:'
145 node.of_values = int(m.groups()[0])
146 patern = m.groups()[1]
148 print "Is so complex?", patern, complex_node
150 # if it's a single host/service
151 if not complex_node:
152 print "Try to find?", patern
153 node.operand = 'object'
154 obj = self.find_object(patern, hosts, services)
155 if obj != None:
156 # Set host or service
157 node.operand = obj.__class__.my_type
158 node.sons.append(obj)
159 return node
160 else:
161 print "Is complex"
163 in_par = False
164 tmp = ''
165 for c in patern:
166 if c == '(':
167 in_par = True
168 tmp = tmp.strip()
169 if tmp != '':
170 o = self.eval_cor_patern(tmp, hosts, services)
171 print "1( I've %s got new sons" % patern , o
172 node.sons.append(o)
173 continue
174 if c == ')':
175 in_par = False
176 tmp = tmp.strip()
177 if tmp != '':
178 print "Evaling sub pat", tmp
179 o = self.eval_cor_patern(tmp, hosts, services)
180 print "2) I've %s got new sons" % patern , o
181 node.sons.append(o)
182 else:
183 print "Fuck a node son!"
184 tmp = ''
185 continue
187 if not in_par:
188 if c in ('&', '|'):
189 current_rule = node.operand
190 print "Current rule", current_rule
191 if current_rule != None and current_rule != 'of:' and c != current_rule:
192 print "Fuck, you mix all dumbass!"
193 return None
194 if current_rule != 'of:':
195 node.operand = c
196 tmp = tmp.strip()
197 if tmp != '':
198 o = self.eval_cor_patern(tmp, hosts, services)
199 print "3&| I've %s got new sons" % patern , o
200 node.sons.append(o)
201 tmp = ''
202 continue
203 else:
204 tmp += c
205 else:
206 tmp += c
208 tmp = tmp.strip()
209 if tmp != '':
210 o = self.eval_cor_patern(tmp, hosts, services)
211 print "4end I've %s got new sons" % patern , o
212 node.sons.append(o)
214 print "End, tmp", tmp
215 print "R %s :" % patern, node
216 return node
219 # We've got an object, like h1,db1 that mean the
220 # db1 service of the host db1, or just h1, that mean
221 # the host h1.
222 def find_object(self, patern, hosts, services):
223 print "Finding object", patern
224 is_service = False
225 # h_name, service_desc are , separated
226 elts = patern.split(',')
227 host_name = elts[0]
228 # Look if we have a service
229 if len(elts) > 1:
230 is_service = True
231 service_description = elts[1]
232 if is_service:
233 obj = services.find_srv_by_name_and_hostname(host_name, service_description)
234 print "Find service", obj.get_name()
235 return obj
236 else:
237 obj = hosts.find_by_name(host_name)
238 print "Find host", obj.get_name()
239 return obj