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 #SatelliteLink is a common Class for link to satellite for
23 #Arbiter with Conf Dispatcher.
26 import shinken
.pyro_wrapper
27 Pyro
= shinken
.pyro_wrapper
.Pyro
30 from shinken
.item
import Item
, Items
32 class SatelliteLink(Item
):
33 #id = 0 each Class will have it's own id
34 #properties={'name' : {'required' : True },#, 'pythonize': None},
35 # 'address' : {'required' : True},#, 'pythonize': to_bool},
36 # 'port' : {'required': True, 'pythonize': to_int},
37 # 'spare' : {'required': False, 'default' : '0', 'pythonize': to_bool},
40 #running_properties = {
41 # 'con' : {'default' : None}
51 #Check is required prop are set:
52 #contacts OR contactgroups is need
54 state
= True #guilty or not? :)
57 special_properties
= ['realm']
58 for prop
in cls
.properties
:
59 if prop
not in special_properties
:
60 if not hasattr(self
, prop
) and cls
.properties
[prop
]['required']:
61 print self
.get_name(), " : I do not have", prop
62 state
= False #Bad boy...
63 #Ok now we manage special cases...
64 if not hasattr(self
, 'realm') or hasattr(self
, 'realm') and self
.realm
== None:
65 print self
.get_name()," : I do not have a valid realm"
70 def create_connexion(self
):
71 #URI are differents between 3 and 4
72 if shinken
.pyro_wrapper
.pyro_version
== 3:
73 self
.uri
= 'PYROLOC://'+self
.address
+":"+str(self
.port
)+"/ForArbiter"
74 self
.con
= Pyro
.core
.getProxyForURI(self
.uri
)
75 #Ok, set timeout to 3 sec (ping timeout)
76 self
.con
._setTimeout
(self
.timeout
)
78 self
.uri
= 'PYRO:ForArbiter@'+self
.address
+":"+str(self
.port
)
79 self
.con
= Pyro
.core
.Proxy(self
.uri
)
80 self
.con
._pyroTimeout
= self
.timeout
83 def put_conf(self
, conf
):
85 self
.create_connexion()
86 #print "Connexion is OK, now we put conf", conf
87 #print "Try to put conf:", conf
89 #Still fun with pyro 3 and 4...
90 if shinken
.pyro_wrapper
.pyro_version
== 3:
91 #Data timeout is far longer than timeout (ping one)
92 self
.con
._setTimeout
(self
.data_timeout
)
93 self
.con
.put_conf(conf
)
94 self
.con
._setTimeout
(self
.timeout
)
97 self
.con
._pyroTimeout
= self
.data_timeout
98 self
.con
.put_conf(conf
)
99 self
.con
._pyroTimeout
= self
.timeout
101 except Pyro
.errors
.URIError
, exp
:
104 except Pyro
.errors
.ProtocolError
, exp
:
107 except TypeError , exp
:
108 print ''.join(Pyro
.util
.getPyroTraceback(exp
))
109 except Pyro
.errors
.CommunicationError
, exp
:
114 #Get and clean all of our broks
115 def get_all_broks(self
):
121 #Set alive, reachable, and reset attemps.
122 #If we change state, raise a status brok update
124 was_alive
= self
.alive
127 self
.reachable
= True
129 #We came from dead to alive
130 #so we must add a brok update
132 b
= self
.get_update_status_brok()
137 print "Set dead for %s" % self
.get_name()
138 was_alive
= self
.alive
142 #We are dead now. Must raise
145 b
= self
.get_update_status_brok()
149 #Go in reachable=False and add a failed attempt
150 #if we reach the max, go dead
151 def add_failed_check_attempt(self
):
152 print "Add failed attempt to", self
.get_name()
153 self
.reachable
= False
155 self
.attempt
= min(self
.attempt
, self
.max_check_attempts
)
156 print "Attemps", self
.attempt
, self
.max_check_attempts
157 #check when we just go HARD (dead)
158 if self
.attempt
== self
.max_check_attempts
:
163 print "Pinging %s" % self
.get_name()
166 self
.create_connexion()
169 except Pyro
.errors
.ProtocolError
, exp
:
170 self
.add_failed_check_attempt()
171 except Pyro
.errors
.URIError
, exp
:
173 self
.add_failed_check_attempt()
174 #Only pyro 4 but will be ProtocolError in 3
175 except Pyro
.errors
.CommunicationError
, exp
:
176 #print "Is not alive!", self.uri
177 self
.add_failed_check_attempt()
178 except Pyro
.errors
.DaemonError
, exp
:
180 self
.add_failed_check_attempt()
183 def wait_new_conf(self
):
185 self
.create_connexion()
187 self
.con
.wait_new_conf()
189 except Pyro
.errors
.URIError
, exp
:
192 except Pyro
.errors
.ProtocolError
, exp
:
197 #To know if the satellite have a conf (magic_hash = None)
198 #OR to know if the satellite have THIS conf (magic_hash != None)
199 def have_conf(self
, magic_hash
=None):
201 self
.create_connexion()
204 if magic_hash
== None:
205 return self
.con
.have_conf()
207 return self
.con
.have_conf(magic_hash
)
208 except Pyro
.errors
.URIError
, exp
:
211 except Pyro
.errors
.ProtocolError
, exp
:
216 def remove_from_conf(self
, sched_id
):
218 self
.create_connexion()
220 self
.con
.remove_from_conf(sched_id
)
222 except Pyro
.errors
.URIError
, exp
:
225 except Pyro
.errors
.ProtocolError
, exp
:
230 def what_i_managed(self
):
232 self
.create_connexion()
234 tab
= self
.con
.what_i_managed()
235 #I don't know why, but tab can be a bool. Not good here
236 if isinstance(tab
, bool):
240 except Pyro
.errors
.URIError
, exp
:
243 except Pyro
.errors
.ProtocolError
, exp
:
248 def push_broks(self
, broks
):
250 self
.create_connexion()
252 return self
.con
.push_broks(broks
)
253 except Pyro
.errors
.URIError
, exp
:
256 except Pyro
.errors
.ProtocolError
, exp
:
259 except AttributeError , exp
:
264 def get_external_commands(self
):
266 self
.create_connexion()
268 tab
= self
.con
.get_external_commands()
269 if isinstance(tab
, bool):
272 except Pyro
.errors
.URIError
, exp
:
275 except Pyro
.errors
.ProtocolError
, exp
:
278 except AttributeError , exp
:
284 def prepare_for_conf(self
):
285 self
.cfg
= { 'global' : {}, 'schedulers' : {}, 'arbiters' : {}}
286 #cfg_for_satellite['modules'] = satellite.modules
287 properties
= self
.__class
__.properties
288 for prop
in properties
:
289 # if 'to_send' in properties[prop] and properties[prop]['to_send']:
290 if properties
[prop
].to_send
:
291 self
.cfg
['global'][prop
] = getattr(self
, prop
)
293 #Some parameters for satellites are not defined in the satellites conf
294 #but in the global configuration. We can pass them in the global
296 def add_global_conf_parameters(self
, params
):
298 print "Add global parameter", prop
, params
[prop
]
299 self
.cfg
['global'][prop
] = params
[prop
]
302 def get_my_type(self
):
303 return self
.__class
__.my_type
306 #Here for poller and reactionner. Scheduler have it's own function
307 def give_satellite_cfg(self
):
308 return {'port' : self
.port
, 'address' : self
.address
, 'name' : self
.get_name(), 'instance_id' : self
.id, 'active' : True}
312 class SatelliteLinks(Items
):
313 #name_property = "name"
314 #inner_class = SchedulerLink
316 #We must have a realm property, so we find our realm
317 def linkify(self
, realms
, modules
):
318 self
.linkify_s_by_p(realms
)
319 self
.linkify_s_by_plug(modules
)
322 def linkify_s_by_p(self
, realms
):
324 p_name
= s
.realm
.strip()
325 # If no realm name, take the default one
327 p
= realms
.get_default()
329 else: # find the realm one
330 p
= realms
.find_by_name(p_name
)
332 # Check if what we get is OK or not
334 print "Me", s
.get_name(), "is linked with realm", s
.realm
.get_name()
335 s
.register_to_my_realm()
337 err
= "The %s %s got a unknown realm '%s'" % (s
.__class
__.my_type
, s
.get_name(), p_name
)
338 s
.configuration_errors
.append(err
)
342 def linkify_s_by_plug(self
, modules
):
345 for plug_name
in s
.modules
:
346 plug
= modules
.find_by_name(plug_name
.strip())
348 new_modules
.append(plug
)
350 print "Error : the module %s is unknow for %s" % (plug_name
, s
.get_name())
351 s
.modules
= new_modules