*Change the jenkins/hudson test scripts
[shinken.git] / shinken / satellitelink.py
blob4689d01914ef1cf3caa172c6dffc4a1154647060
1 #!/usr/bin/env python
2 #Copyright (C) 2009-2010 :
3 # Gabes Jean, naparuba@gmail.com
4 # Gerhard Lausser, Gerhard.Lausser@consol.de
5 # Gregory Starck, g.starck@gmail.com
7 #This file is part of Shinken.
9 #Shinken is free software: you can redistribute it and/or modify
10 #it under the terms of the GNU Affero General Public License as published by
11 #the Free Software Foundation, either version 3 of the License, or
12 #(at your option) any later version.
14 #Shinken is distributed in the hope that it will be useful,
15 #but WITHOUT ANY WARRANTY; without even the implied warranty of
16 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 #GNU Affero General Public License for more details.
19 #You should have received a copy of the GNU Affero General Public License
20 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
23 #SatelliteLink is a common Class for link to satellite for
24 #Arbiter with Conf Dispatcher.
27 import shinken.pyro_wrapper as pyro
28 Pyro = pyro.Pyro
31 from shinken.item import Item, Items
33 class SatelliteLink(Item):
34 #id = 0 each Class will have it's own id
35 #properties={'name' : {'required' : True },#, 'pythonize': None},
36 # 'address' : {'required' : True},#, 'pythonize': to_bool},
37 # 'port' : {'required': True, 'pythonize': to_int},
38 # 'spare' : {'required': False, 'default' : '0', 'pythonize': to_bool},
39 # }
41 #running_properties = {
42 # 'con' : {'default' : None}
43 # }
44 #macros = {}
47 #Clean? Really?
48 def clean(self):
49 pass
52 #Check is required prop are set:
53 #contacts OR contactgroups is need
54 def is_correct(self):
55 state = True #guilty or not? :)
56 cls = self.__class__
58 special_properties = ['realm']
59 for prop in cls.properties:
60 if prop not in special_properties:
61 if not hasattr(self, prop) and cls.properties[prop]['required']:
62 print self.get_name(), " : I do not have", prop
63 state = False #Bad boy...
64 # Ok now we manage special cases...
65 if getattr(self, 'realm', None) is None:
66 print self.get_name()," : I do not have a valid realm"
67 state = False
68 return state
71 def create_connexion(self):
72 self.uri = pyro.create_uri(self.address, self.port, "ForArbiter", self.__class__.use_ssl)
73 self.con = pyro.getProxy(self.uri)
74 pyro.set_timeout(self.con, self.timeout)
77 def put_conf(self, conf):
79 if self.con == None:
80 self.create_connexion()
81 #print "Connexion is OK, now we put conf", conf
82 #print "Try to put conf:", conf
84 try:
85 pyro.set_timeout(self.con, self.data_timeout)
86 #del conf[0].schedulerlinks
87 import cPickle
88 buf=cPickle.dumps(conf)
89 print "DBG: put conf to", self.con.__dict__
90 self.con.put_conf(conf)
91 pyro.set_timeout(self.con, self.timeout)
92 return True
93 except Pyro.errors.URIError , exp:
94 self.con = None
95 return False
96 except Pyro.errors.ProtocolError , exp:
97 self.con = None
98 return False
99 except TypeError , exp:
100 print ''.join(Pyro.util.getPyroTraceback(exp))
101 except Pyro.errors.CommunicationError , exp:
102 self.con = None
103 return False
106 #Get and clean all of our broks
107 def get_all_broks(self):
108 res = self.broks
109 self.broks = []
110 return res
113 #Set alive, reachable, and reset attemps.
114 #If we change state, raise a status brok update
115 def set_alive(self):
116 was_alive = self.alive
117 self.alive = True
118 self.attempt = 0
119 self.reachable = True
121 #We came from dead to alive
122 #so we must add a brok update
123 if not was_alive:
124 b = self.get_update_status_brok()
125 self.broks.append(b)
128 def set_dead(self):
129 print "Set dead for %s" % self.get_name()
130 was_alive = self.alive
131 self.alive = False
132 self.con = None
134 #We are dead now. Must raise
135 #a brok to say it
136 if was_alive:
137 b = self.get_update_status_brok()
138 self.broks.append(b)
141 #Go in reachable=False and add a failed attempt
142 #if we reach the max, go dead
143 def add_failed_check_attempt(self):
144 print "Add failed attempt to", self.get_name()
145 self.reachable = False
146 self.attempt += 1
147 self.attempt = min(self.attempt, self.max_check_attempts)
148 print "Attemps", self.attempt, self.max_check_attempts
149 #check when we just go HARD (dead)
150 if self.attempt == self.max_check_attempts:
151 self.set_dead()
154 def ping(self):
155 print "Pinging %s" % self.get_name()
156 try:
157 if self.con == None:
158 self.create_connexion()
159 self.con.ping()
160 self.set_alive()
161 except Pyro.errors.ProtocolError , exp:
162 self.add_failed_check_attempt()
163 except Pyro.errors.URIError , exp:
164 print exp
165 self.add_failed_check_attempt()
166 #Only pyro 4 but will be ProtocolError in 3
167 except Pyro.errors.CommunicationError , exp:
168 #print "Is not alive!", self.uri
169 self.add_failed_check_attempt()
170 except Pyro.errors.DaemonError , exp:
171 print exp
172 self.add_failed_check_attempt()
173 except Exception, exp:
174 print exp
175 self.add_failed_check_attempt()
178 def wait_new_conf(self):
179 if self.con == None:
180 self.create_connexion()
181 try:
182 self.con.wait_new_conf()
183 return True
184 except Pyro.errors.URIError , exp:
185 self.con = None
186 return False
187 except Pyro.errors.ProtocolError , exp:
188 self.con = None
189 return False
190 except Exception, exp:
191 self.con = False
192 return False
196 #To know if the satellite have a conf (magic_hash = None)
197 #OR to know if the satellite have THIS conf (magic_hash != None)
198 def have_conf(self, magic_hash=None):
199 if self.con == None:
200 self.create_connexion()
202 try:
203 if magic_hash == None:
204 return self.con.have_conf()
205 else:
206 return self.con.have_conf(magic_hash)
207 except Pyro.errors.URIError , exp:
208 self.con = None
209 return False
210 except Pyro.errors.ProtocolError , exp:
211 self.con = None
212 return False
213 except Exception, exp:
214 self.con = False
215 return False
219 def remove_from_conf(self, sched_id):
220 if self.con == None:
221 self.create_connexion()
222 try:
223 self.con.remove_from_conf(sched_id)
224 return True
225 except Pyro.errors.URIError , exp:
226 self.con = None
227 return False
228 except Pyro.errors.ProtocolError , exp:
229 self.con = None
230 return False
231 except Exception, exp:
232 self.con = False
233 return False
236 def what_i_managed(self):
237 if self.con == None:
238 self.create_connexion()
239 try:
240 tab = self.con.what_i_managed()
241 #I don't know why, but tab can be a bool. Not good here
242 if isinstance(tab, bool):
243 self.con = None
244 return []
245 return tab
246 except Pyro.errors.URIError , exp:
247 self.con = None
248 return []
249 except Pyro.errors.ProtocolError , exp:
250 self.con = None
251 return []
252 except Exception, exp:
253 self.con = False
254 return []
257 def push_broks(self, broks):
258 if self.con == None:
259 self.create_connexion()
260 try:
261 return self.con.push_broks(broks)
262 except Pyro.errors.URIError , exp:
263 self.con = None
264 return False
265 except Pyro.errors.ProtocolError , exp:
266 self.con = None
267 return False
268 except AttributeError , exp:
269 print exp
270 return False
271 except Exception, exp:
272 self.con = False
273 return False
277 def get_external_commands(self):
278 if self.con == None:
279 self.create_connexion()
280 try:
281 tab = self.con.get_external_commands()
282 if isinstance(tab, bool):
283 return []
284 return tab
285 except Pyro.errors.URIError , exp:
286 self.con = None
287 return []
288 except Pyro.errors.ProtocolError , exp:
289 self.con = None
290 return []
291 except AttributeError , exp:
292 print exp
293 return []
294 except Exception, exp:
295 self.con = False
296 return []
300 def prepare_for_conf(self):
301 self.cfg = { 'global' : {}, 'schedulers' : {}, 'arbiters' : {}}
302 #cfg_for_satellite['modules'] = satellite.modules
303 properties = self.__class__.properties
304 for prop in properties:
305 # if 'to_send' in properties[prop] and properties[prop]['to_send']:
306 if properties[prop].to_send:
307 self.cfg['global'][prop] = getattr(self, prop)
309 #Some parameters for satellites are not defined in the satellites conf
310 #but in the global configuration. We can pass them in the global
311 #property
312 def add_global_conf_parameters(self, params):
313 for prop in params:
314 print "Add global parameter", prop, params[prop]
315 self.cfg['global'][prop] = params[prop]
318 def get_my_type(self):
319 return self.__class__.my_type
322 #Here for poller and reactionner. Scheduler have it's own function
323 def give_satellite_cfg(self):
324 return {'port' : self.port, 'address' : self.address, 'name' : self.get_name(), 'instance_id' : self.id, 'active' : True}
328 #Call by picle for dataify the downtime
329 #because we DO NOT WANT REF in this pickleisation!
330 def __getstate__(self):
331 cls = self.__class__
332 # id is not in *_properties
333 res = {'id' : self.id}
334 for prop in cls.properties:
335 if prop != 'realm':
336 if hasattr(self, prop):
337 res[prop] = getattr(self, prop)
338 for prop in cls.running_properties:
339 if prop != 'con':
340 if hasattr(self, prop):
341 res[prop] = getattr(self, prop)
342 return res
345 #Inversed funtion of getstate
346 def __setstate__(self, state):
347 cls = self.__class__
349 self.id = state['id']
350 for prop in cls.properties:
351 if prop in state:
352 setattr(self, prop, state[prop])
353 for prop in cls.running_properties:
354 if prop in state:
355 setattr(self, prop, state[prop])
359 class SatelliteLinks(Items):
360 #name_property = "name"
361 #inner_class = SchedulerLink
363 #We must have a realm property, so we find our realm
364 def linkify(self, realms, modules):
365 self.linkify_s_by_p(realms)
366 self.linkify_s_by_plug(modules)
369 def linkify_s_by_p(self, realms):
370 for s in self:
371 p_name = s.realm.strip()
372 # If no realm name, take the default one
373 if p_name == '':
374 p = realms.get_default()
375 s.realm = p
376 else: # find the realm one
377 p = realms.find_by_name(p_name)
378 s.realm = p
379 # Check if what we get is OK or not
380 if p is not None:
381 print "Me", s.get_name(), "is linked with realm", s.realm.get_name()
382 s.register_to_my_realm()
383 else:
384 err = "The %s %s got a unknown realm '%s'" % (s.__class__.my_type, s.get_name(), p_name)
385 s.configuration_errors.append(err)
386 print err
389 def linkify_s_by_plug(self, modules):
390 for s in self:
391 new_modules = []
392 for plug_name in s.modules:
393 plug = modules.find_by_name(plug_name.strip())
394 if plug != None:
395 new_modules.append(plug)
396 else:
397 print "Error : the module %s is unknow for %s" % (plug_name, s.get_name())
398 s.modules = new_modules