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/>.
21 import time
, calendar
, re
23 from ClusterShell
.NodeSet
import NodeSet
27 from shinken
.macroresolver
import MacroResolver
28 #from memoized import memoized
31 ################################### TIME ##################################
33 def get_end_of_day(year
, month_id
, day
):
34 end_time
= (year
, month_id
, day
, 23, 59, 59, 0, 0, -1)
35 end_time_epoch
= time
.mktime(end_time
)
41 return time
.asctime(time
.localtime(t
))
46 return int(t
- get_sec_from_morning(t
))
50 def get_sec_from_morning(t
):
51 t_lt
= time
.localtime(t
)
55 return h
* 3600 + m
* 60 + s
59 def get_start_of_day(year
, month_id
, day
):
60 start_time
= (year
, month_id
, day
, 00, 00, 00, 0, 0, -1)
61 start_time_epoch
= time
.mktime(start_time
)
62 return start_time_epoch
65 #change a time in seconds like 3600 into a format : 0d 1h 0m 0s
66 def format_t_into_dhms_format(t
):
71 return '%sd %sh %sm %ss' % (d
, h
, m
, s
)
74 ################################# Pythonization ###########################
75 #first change to foat so manage for example 25.0 to 25
77 return int(float(val
))
91 #bool('0') = true, so...
98 def from_bool_to_string(b
):
104 def from_bool_to_int(b
):
110 def from_list_to_split(val
):
111 val
= ','.join(['%s' % v
for v
in val
])
114 def from_float_to_int(val
):
119 ### Functions for brok_transformations
120 ### They take 2 parameters : ref, and a value
121 ### ref is the item like a service, and value
122 ### if the value to preprocess
124 # Just a string list of all names, with ,
125 def to_list_string_of_names(ref
, tab
):
126 return ",".join([e
.get_name() for e
in tab
])
128 # take a list of hosts and return a list
130 def to_hostnames_list(ref
, tab
):
133 if hasattr(h
, 'host_name'):
134 r
.append(h
.host_name
)
137 # Will create a dict with 2 lists:
138 # *services : all services of the tab
139 # *hosts : all hosts of the tab
140 def to_svc_hst_distinct_lists(ref
, tab
):
141 r
= {'hosts' : [], 'services' : []}
144 if cls
.my_type
== 'service':
145 name
= e
.get_dbg_name()
146 r
['services'].append(name
)
148 name
= e
.get_dbg_name()
149 r
['hosts'].append(name
)
153 # Will expaand the value with macros from the
154 # host/service ref before brok it
155 def expand_with_macros(ref
, value
):
156 return MacroResolver().resolve_simple_macros_in_string(value
, ref
.get_data_for_checks())
159 # Just get the string name of the object
161 def get_obj_name(obj
):
162 return obj
.get_name()
165 ###################### Sorting ################
166 def scheduler_no_spare_first(x
, y
):
167 if x
.spare
and not y
.spare
:
169 elif x
.spare
and y
.spare
:
175 #-1 is x first, 0 equal, 1 is y first
176 def alive_then_spare_then_deads(x
, y
):
178 if x
.alive
and not y
.alive
:
180 if y
.alive
and not x
.alive
:
182 #if not alive both, I really don't care...
183 if not x
.alive
and not y
.alive
:
185 #Ok, both are alive... now spare after no spare
188 #x is a spare, so y must be before, even if
194 #-1 is x first, 0 equal, 1 is y first
195 def sort_by_ids(x
, y
):
205 ##################### Cleaning ##############
206 def strip_and_uniq(tab
):
209 new_tab
.add(elt
.strip())
214 #################### Patern change application (mainly for host) #######
216 def expand_xy_patern(pattern
):
217 ns
= NodeSet(pattern
)
220 for a
in expand_xy_patern(elem
):
228 #This function is used to generate all patern change as
230 #for example, for a [(1,3),(1,4),(1,5)] xy_couples,
231 #it will generate a 60 item list with:
232 #Rule: [1, '[1-5]', [1, '[1-4]', [1, '[1-3]', []]]]
233 #Rule: [1, '[1-5]', [1, '[1-4]', [2, '[1-3]', []]]]
235 def got_generation_rule_patern_change(xy_couples
):
241 for i
in xrange(x
, y
+1):
242 n
= got_generation_rule_patern_change(xy_cpl
[1:])
245 res
.append( [i
, '[%d-%d]'%(x
,y
), e
])
247 res
.append( [i
, '[%d-%d]'%(x
,y
), []])
251 #this fuction apply a recursive patern change
252 #generate by the got_generation_rule_patern_change
254 #It take one entry of this list, and apply
255 #recursivly the change to s like :
256 #s = "Unit [1-3] Port [1-4] Admin [1-5]"
257 #rule = [1, '[1-5]', [2, '[1-4]', [3, '[1-3]', []]]]
258 #output = Unit 3 Port 2 Admin 1
259 def apply_change_recursive_patern_change(s
, rule
):
260 #print "Try to change %s" % s, 'with', rule
263 #print "replace %s by %s" % (r'%s' % m, str(i)), 'in', s
264 s
= s
.replace(r
'%s' % m
, str(i
))
268 return apply_change_recursive_patern_change(s
, t
)
271 #For service generator, get dict from a _custom properties
272 #as _disks C$(80%!90%),D$(80%!90%)$,E$(80%!90%)$
273 #return {'C' : '80%!90%', 'D' : '80%!90%', 'E' : '80%!90%'}
274 #And if we have a key that look like [X-Y] we will expand it
276 GET_KEY_VALUE_SEQUENCE_ERROR_NOERROR
= 0
277 GET_KEY_VALUE_SEQUENCE_ERROR_SYNTAX
= 1
278 GET_KEY_VALUE_SEQUENCE_ERROR_NODEFAULT
= 2
279 GET_KEY_VALUE_SEQUENCE_ERROR_NODE
= 3
280 def get_key_value_sequence(entry
, default_value
=None):
285 # match a key$(value1..n)$
286 keyval_pattern_txt
= r
"""
287 \s*(?P<key>[^,]+?)(?P<values>(\$\(.*?\)\$)*)(?:[,]|$)
289 keyval_pattern
= re
.compile('(?x)' + keyval_pattern_txt
)
290 # match a whole sequence of key$(value1..n)$
291 all_keyval_pattern
= re
.compile('(?x)^(' + keyval_pattern_txt
+ ')+$')
292 # match a single value
293 value_pattern
= re
.compile('(?:\$\((?P<val>.*?)\)\$)')
294 # match a sequence of values
295 all_value_pattern
= re
.compile('^(?:\$\(.*?\)\$)+$')
297 if all_keyval_pattern
.match(conf_entry
):
298 for mat
in re
.finditer(keyval_pattern
, conf_entry
):
299 r
= { 'KEY' : mat
.group('key') }
300 # The key is in mat.group('key')
301 # If there are also value(s)...
302 if mat
.group('values'):
303 if all_value_pattern
.match(mat
.group('values')):
304 # If there are multiple values, loop over them
306 for val
in re
.finditer(value_pattern
, mat
.group('values')):
307 r
['VALUE' + str(valnum
)] = val
.group('val')
311 return (None, GET_KEY_VALUE_SEQUENCE_ERROR_SYNTAX
)
316 # Something is wrong with the values. (Maybe unbalanced '$(')
317 # TODO: count opening and closing brackets in the pattern
318 return (None, GET_KEY_VALUE_SEQUENCE_ERROR_SYNTAX
)
320 # now fill the empty values with the default value
322 if r
['VALUE1'] == None:
323 if default_value
== None:
324 return (None, GET_KEY_VALUE_SEQUENCE_ERROR_NODEFAULT
)
326 r
['VALUE1'] = default_value
327 r
['VALUE'] = r
['VALUE1']
329 #Now create new one but for [X-Y] matchs
330 # array1 holds the original entries. Some of the keys may contain wildcards
331 # array2 is filled with originals and inflated wildcards
336 #The patern that will say if we have a [X-Y] key.
337 pat
= re
.compile('\[(\d*)-(\d*)\]')
344 #We have no choice, we cannot use NodeSet, so we use the
349 else: # Try to look with a nodeset check directly
352 #If we have more than 1 element, we have a xy thing
353 got_xy
= (len(ns
) != 1)
354 except NodeSetParseRangeError
:
355 return (None, GET_KEY_VALUE_SEQUENCE_ERROR_NODE
)
356 pass # go in the next key
358 #Now we've got our couples of X-Y. If no void,
359 #we were with a "key generator"
362 #Ok 2 cases : we have the NodeSet lib or not.
363 #if not, we use the dumb algo (quick, but manage less
364 #cases like /N or , in paterns)
365 if NodeSet
== None: #us the old algo
367 xy_couples
= [] # will get all X-Y couples
370 if m
!= None: # we've find one X-Y
372 (x
,y
) = (int(x
), int(y
))
373 xy_couples
.append((x
,y
))
374 #We must search if we've gotother X-Y, so
375 #we delete this one, and loop
376 key
= key
.replace('[%d-%d]' % (x
,y
), 'Z'*10)
377 else:#no more X-Y in it
380 #Now we have our xy_couples, we can manage them
382 #We search all patern change rules
383 rules
= got_generation_rule_patern_change(xy_couples
)
385 #Then we apply them all to get ours final keys
387 res
= apply_change_recursive_patern_change(orig_key
, rule
)
395 #The key was just a generator, we can remove it
396 #keys_to_del.append(orig_key)
398 #We search all patern change rules
399 #rules = got_generation_rule_patern_change(xy_couples)
400 nodes_set
= expand_xy_patern(orig_key
)
401 new_keys
= list(nodes_set
)
403 #Then we apply them all to get ours final keys
404 for new_key
in new_keys
:
405 #res = apply_change_recursive_patern_change(orig_key, rule)
409 new_r
['KEY'] = new_key
412 # There were no wildcards
417 #print "***********Diff", t1 -t0
419 return (array2
, GET_KEY_VALUE_SEQUENCE_ERROR_NOERROR
)