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
6 # Hartmut Goebel, h.goebel@goebel-consult.de
8 #This file is part of Shinken.
10 #Shinken is free software: you can redistribute it and/or modify
11 #it under the terms of the GNU Affero General Public License as published by
12 #the Free Software Foundation, either version 3 of the License, or
13 #(at your option) any later version.
15 #Shinken is distributed in the hope that it will be useful,
16 #but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 #GNU Affero General Public License for more details.
20 #You should have received a copy of the GNU Affero General Public License
21 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
24 #This class revolv Macro in commands by looking at the macros list
25 #in Class of elements. It give a propertie that call be callable or not.
26 #It not callable, it's a simple properties and remplace the macro with the value
27 #If callable, it's a method that is call for getting the value. for exemple, to
28 #get the number of service in a host, you call a method to get the
34 from shinken
.borg
import Borg
37 class MacroResolver(Borg
):
39 my_type
= 'macroresolver'
42 'TOTALHOSTSUP': 'get_total_hosts_up',
43 'TOTALHOSTSDOWN': 'get_total_hosts_down',
44 'TOTALHOSTSUNREACHABLE': 'get_total_hosts_unreacheable',
45 'TOTALHOSTSDOWNUNHANDLED': 'get_total_hosts_unhandled',
46 'TOTALHOSTSUNREACHABLEUNHANDLED': 'get_total_hosts_unreacheable_unhandled',
47 'TOTALHOSTPROBLEMS': 'get_total_host_problems',
48 'TOTALHOSTPROBLEMSUNHANDLED': 'get_total_host_problems_unhandled',
49 'TOTALSERVICESOK': 'get_total_service_ok',
50 'TOTALSERVICESWARNING': 'get_total_services_warning',
51 'TOTALSERVICESCRITICAL': 'get_total_services_critical',
52 'TOTALSERVICESUNKNOWN': 'get_total_services_unknown',
53 'TOTALSERVICESWARNINGUNHANDLED': 'get_total_services_warning_unhandled',
54 'TOTALSERVICESCRITICALUNHANDLED': 'get_total_services_critical_unhandled',
55 'TOTALSERVICESUNKNOWNUNHANDLED': 'get_total_services_unknown_unhandled',
56 'TOTALSERVICEPROBLEMS': 'get_total_service_problems',
57 'TOTALSERVICEPROBLEMSUNHANDLED': 'get_total_service_problems_unhandled',
58 'LONGDATETIME': 'get_long_date_time',
59 'SHORTDATETIME': 'get_short_date_time',
63 'PROCESSSTARTTIME': 'get_process_start_time',
64 'EVENTSTARTTIME': 'get_events_start_time',
68 #This shall be call ONE TIME. It just put links for elements
71 # For searching class and elements for ondemand
72 #we need link to types
74 self
.lists_on_demand
= []
75 self
.hosts
= conf
.hosts
76 #For special void host_name handling...
77 self
.host_class
= self
.hosts
.inner_class
78 self
.lists_on_demand
.append(self
.hosts
)
79 self
.services
= conf
.services
80 self
.contacts
= conf
.contacts
81 self
.lists_on_demand
.append(self
.contacts
)
82 self
.hostgroups
= conf
.hostgroups
83 self
.lists_on_demand
.append(self
.hostgroups
)
84 self
.commands
= conf
.commands
85 self
.servicegroups
= conf
.servicegroups
86 self
.lists_on_demand
.append(self
.servicegroups
)
87 self
.contactgroups
= conf
.contactgroups
88 self
.lists_on_demand
.append(self
.contactgroups
)
89 self
.illegal_macro_output_chars
= conf
.illegal_macro_output_chars
90 self
.output_macros
= ['HOSTOUTPUT', 'HOSTPERFDATA', 'HOSTACKAUTHOR', 'HOSTACKCOMMENT', 'SERVICEOUTPUT', 'SERVICEPERFDATA', 'SERVICEACKAUTHOR', 'SERVICEACKCOMMENT']
95 #Return all macros of a string, so cut the $
96 #And create a dict with it:
97 #val : value, not set here
98 #type : type of macro, like class one, or ARGN one
99 def get_macros(self
, s
):
101 # return self.cache[s]
103 p
= re
.compile(r
'(\$)')
109 in_macro
= not in_macro
111 macros
[elt
] = {'val' : '', 'type' : 'unknown'}
113 #self.cache[s] = macros
117 #Get a value from a propertie of a element
118 #Prop can ba a function or a propertie
120 def get_value_from_element(self
, elt
, prop
):
122 value
= getattr(elt
, prop
)
127 except AttributeError , exp
:
132 #For some macros, we need to delete unwanted caracters
133 def delete_unwanted_caracters(self
, s
):
134 for c
in self
.illegal_macro_output_chars
:
139 #return a dict with all environement variable came from
140 #the macros of the datas object
141 def get_env_macros(self
, data
):
144 clss
= [d
.__class
__ for d
in data
]
147 if o
.__class
__ == cls
:
150 # print "Macro in %s : %s" % (o.__class__, macro)
152 value
= self
.get_value_from_element(o
, prop
)
153 # print "Value: %s" % value
154 env
['NAGIOS_'+macro
] = value
159 # This function will look at elements in data (and args if it filled)
160 # to replace the macros in c_line with real value.
161 def resolve_simple_macros_in_string(self
, c_line
, data
, args
=None):
162 #Now we prepare the classes for looking at the class.macros
163 data
.append(self
) #For getting global MACROS
164 if hasattr(self
, 'conf'):
165 data
.append(self
.conf
) # For USERN macros
166 clss
= [d
.__class
__ for d
in data
]
168 #we should do some loops for nested macros
169 #like $USER1$ hiding like a ninja in a $ARG2$ Macro. And if
170 #$USER1$ is pointing to $USER34$ etc etc, we should loop
171 #until we reach the botom. So the last loop is when we do
172 #not still have macros :)
173 still_got_macros
= True
175 while still_got_macros
:
177 #Ok, we want the macros in the command line
178 macros
= self
.get_macros(c_line
)
180 #We can get out if we do not have macros this loop
181 still_got_macros
= (len(macros
)!=0)
182 #print "Still go macros:", still_got_macros
184 #Put in the macros the type of macro for all macros
185 self
.get_type_of_macro(macros
, clss
)
186 #Now we get values from elements
188 #If type ARGN, look at ARGN cutting
189 if macros
[macro
]['type'] == 'ARGN' and args
is not None:
190 macros
[macro
]['val'] = self
.resolve_argn(macro
, args
)
191 macros
[macro
]['type'] = 'resolved'
192 #If class, get value from properties
193 if macros
[macro
]['type'] == 'class':
194 cls
= macros
[macro
]['class']
196 if elt
is not None and elt
.__class
__ == cls
:
197 prop
= cls
.macros
[macro
]
198 macros
[macro
]['val'] = self
.get_value_from_element(elt
, prop
)
199 #Now check if we do not have a 'output' macro. If so, we must
200 #delete all special caracters that can be dangerous
201 if macro
in self
.output_macros
:
202 macros
[macro
]['val'] = self
.delete_unwanted_caracters(macros
[macro
]['val'])
203 if macros
[macro
]['type'] == 'CUSTOM':
204 cls_type
= macros
[macro
]['class']
205 macro_name
= re
.split('_'+cls_type
, macro
)[1].upper()
206 #Ok, we've got the macro like MAC_ADDRESS for _HOSTMAC_ADDRESS
207 #Now we get the element in data that have the type HOST
208 #and we check if it gots the custom value
210 if elt
is not None and elt
.__class
__.my_type
.upper() == cls_type
:
211 if '_'+macro_name
in elt
.customs
:
212 macros
[macro
]['val'] = elt
.customs
['_'+macro_name
]
213 if macros
[macro
]['type'] == 'ONDEMAND':
214 macros
[macro
]['val'] = self
.resolve_ondemand(macro
, data
)
216 #We resolved all we can, now replace the macro in the command call
218 c_line
= c_line
.replace('$'+macro
+'$', macros
[macro
]['val'])
220 if nb_loop
> 32: #too mouch loop, we exit
221 still_got_macros
= False
223 #print "Retuning c_line", c_line.strip()
224 return c_line
.strip()
227 #Resolve a command with macro by looking at data classes.macros
228 #And get macro from item properties.
229 def resolve_command(self
, com
, data
):
230 c_line
= com
.command
.command_line
231 return self
.resolve_simple_macros_in_string(c_line
, data
, args
=com
.args
)
234 #For all Macros in macros, set the type by looking at the
235 #MACRO name (ARGN? -> argn_type,
236 #HOSTBLABLA -> class one and set Host in class)
237 #_HOSTTOTO -> HOST CUSTOM MACRO TOTO
238 #$SERVICESTATEID:srv-1:Load$ -> MACRO SERVICESTATEID of
239 #the service Load of host srv-1
240 def get_type_of_macro(self
, macros
, clss
):
243 if re
.match('ARG\d', macro
):
244 macros
[macro
]['type'] = 'ARGN'
247 #are managed in the Config class, so no
248 #need to look that here
249 elif re
.match('_HOST\w', macro
):
250 macros
[macro
]['type'] = 'CUSTOM'
251 macros
[macro
]['class'] = 'HOST'
253 elif re
.match('_SERVICE\w', macro
):
254 macros
[macro
]['type'] = 'CUSTOM'
255 macros
[macro
]['class'] = 'SERVICE'
256 #value of macro : re.split('_HOST', '_HOSTMAC_ADDRESS')[1]
258 elif re
.match('_CONTACT\w', macro
):
259 macros
[macro
]['type'] = 'CUSTOM'
260 macros
[macro
]['class'] = 'CONTACT'
263 elif len(macro
.split(':')) > 1:
264 macros
[macro
]['type'] = 'ONDEMAND'
266 #OK, classical macro...
268 if macro
in cls
.macros
:
269 macros
[macro
]['type'] = 'class'
270 macros
[macro
]['class'] = cls
274 #Resolv MACROS for the ARGN
275 def resolve_argn(self
, macro
, args
):
276 #first, get number of arg
278 r
= re
.search('ARG(?P<id>\d+)', macro
)
280 id = int(r
.group('id')) - 1
287 #Resolved on demande macro, quite hard on fact
288 def resolve_ondemand(self
, macro
, data
):
289 #print "\nResolving macro", macro
290 elts
= macro
.split(':')
293 #Len 3 == service, 2 = all others types...
296 #print "Got a Service on demand asking...", elts
297 (host_name
, service_description
) = (elts
[1], elts
[2])
298 #host_name can be void, so it's the host in data
299 #that is important. We use our self.host_class to
300 #find the host in the data :)
303 if elt
is not None and elt
.__class
__ == self
.host_class
:
304 host_name
= elt
.host_name
305 #Okn now we get service
306 s
= self
.services
.find_srv_by_name_and_hostname(host_name
, service_description
)
309 prop
= cls
.macros
[macro_name
]
310 val
= self
.get_value_from_element(s
, prop
)
311 #print "Got val:", val
313 #Ok, service was easy, now hard part
317 #Special case : elt_name can be void
318 #so it's the host where it apply
321 if elt
is not None and elt
.__class
__ == self
.host_class
:
322 elt_name
= elt
.host_name
323 for list in self
.lists_on_demand
:
324 cls
= list.inner_class
325 #We search our type by look at the macro
326 if macro_name
in cls
.macros
:
327 prop
= cls
.macros
[macro_name
]
328 i
= list.find_by_name(elt_name
)
330 val
= self
.get_value_from_element(i
, prop
)
331 #print "Got val:", val
336 #Get Fri 15 May 11:42:39 CEST 2009
337 def get_long_date_time(self
):
338 return time
.strftime("%a %d %b %H:%M:%S %Z %Y", time
.localtime())
341 #Get 10-13-2000 00:30:28
342 def get_short_date_time(self
):
343 return time
.strftime("%d-%m-%Y %H:%M:%S", time
.localtime())
348 return time
.strftime("%d-%m-%Y", time
.localtime())
353 return time
.strftime("%H:%M:%S", time
.localtime())
358 return str(int(time
.time()))
361 def get_total_hosts_up(self
):
362 return len([h
for h
in self
.hosts
if h
.state
== 'UP'])
364 def get_total_hosts_down(self
):
365 return len([h
for h
in self
.hosts
if h
.state
== 'DOWN'])
367 def get_total_hosts_unreacheable(self
):
368 return len([h
for h
in self
.hosts
if h
.state
== 'UNREACHABLE'])
371 def get_total_hosts_unreacheable_unhandled(self
):
375 def get_total_host_problems(self
):
376 return len([h
for h
in self
.hosts
if h
.is_problem
])
378 def get_total_host_problems_unhandled(self
):
381 def get_total_service_ok(self
):
382 return len([s
for s
in self
.services
if s
.state
== 'OK'])
384 def get_total_services_warning(self
):
385 return len([s
for s
in self
.services
if s
.state
== 'WARNING'])
387 def get_total_services_critical(self
):
388 return len([s
for s
in self
.services
if s
.state
== 'CRITICAL'])
390 def get_total_services_unknown(self
):
391 return len([s
for s
in self
.services
if s
.state
== 'UNKNOWN'])
394 def get_total_services_warning_unhandled(self
):
397 def get_total_services_critical_unhandled(self
):
400 def get_total_services_unknown_unhandled(self
):
403 def get_total_service_problems(self
):
404 return len([s
for s
in self
.services
if s
.is_problem
])
406 def get_total_service_problems_unhandled(self
):
409 def get_process_start_time(self
):
412 def get_events_start_time(self
):