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 is a base class for nearly all configuration
25 elements like service, hosts or contacts.
28 #from command import CommandCall
29 #from util import to_int, to_char, to_split, to_bool
32 from shinken
.objects
.command
import CommandCall
33 from shinken
.brok
import Brok
34 from shinken
.util
import strip_and_uniq
35 from shinken
.acknowledge
import Acknowledge
36 from shinken
.comment
import Comment
39 def __init__(self
, params
={}):
40 # We have our own id of My Class type :)
41 # use set attr for going into the slots
42 # instead of __dict__ :)
43 setattr(self
, 'id', self
.__class
__.id)
44 self
.__class
__.id += 1
47 self
.customs
= {} # for custom variables
48 self
.plus
= {} # for value with a +
51 # adding running properties like latency, dependency list, etc
52 for prop
, entry
in cls
.running_properties
.items():
53 # Copy is slow, so we check type
54 # Type with __iter__ are list or dict, or tuple.
55 # Item need it's own list, so qe copy
57 if hasattr(val
, '__iter__'):
58 setattr(self
, prop
, copy(val
))
60 setattr(self
, prop
, val
)
61 #eatch istance to have his own running prop!
63 # [0] = + -> new key-plus
64 # [0] = _ -> new custom entry in UPPER case
66 if len(params
[key
]) >= 1 and params
[key
][0] == '+':
67 # Special case : a _MACRO can be a plus. so add to plus
68 # but upper the key for the macro name
70 self
.plus
[key
.upper()] = params
[key
][1:] # we remove the +
72 self
.plus
[key
] = params
[key
][1:] # we remove the +
74 custom_name
= key
.upper()
75 self
.customs
[custom_name
] = params
[key
]
77 setattr(self
, key
, params
[key
])
80 #return a copy of the item, but give him a new id
82 """ Copy a copy of the item, but give him a new id """
84 i
= cls({})#Dummy item but with it's own running properties
85 for prop
in cls
.properties
:
86 if hasattr(self
, prop
):
87 val
= getattr(self
, prop
)
89 # Also copy the customs tab
90 i
.customs
= copy(self
.customs
)
99 return str(self
.__dict
__)+'\n'
103 """ Return if the elements is a template """
105 return self
.register
== '0'
110 #If a prop is absent and is not required, put the default value
111 def fill_default(self
):
112 """ Fill missing properties if they are missing """
115 for prop
, entry
in cls
.properties
.items():
116 if not hasattr(self
, prop
) and entry
.has_default
:
117 setattr(self
, prop
, entry
.default
)
120 #We load every usefull parameter so no need to access global conf later
121 #Must be called after a change in a gloabl conf parameter
122 def load_global_conf(cls
, conf
):
123 """ Used to put global values in the sub Class like
124 hosts ro services """
125 #conf have properties, if 'enable_notifications' :
126 #{ [...] 'class_inherit' : [(Host, None), (Service, None),
128 #get the name and put the value if None, put the Name
129 #(not None) if not (not clear ?)
130 for prop
, entry
in conf
.properties
.items():
131 #If we have a class_inherit, and the arbtier really send us it
132 # if 'class_inherit' in entry and hasattr(conf, prop):
133 if hasattr(conf
, prop
):
134 for (cls_dest
, change_name
) in entry
.class_inherit
:
135 if cls_dest
== cls
:#ok, we've got something to get
136 value
= getattr(conf
, prop
)
137 if change_name
is None:
138 setattr(cls
, prop
, value
)
140 setattr(cls
, change_name
, value
)
142 #Make this method a classmethod
143 load_global_conf
= classmethod(load_global_conf
)
146 #Use to make python properties
149 for prop
, tab
in cls
.properties
.items():
151 # if isinstance(tab, dict):
152 # if 'pythonize' in tab:
153 # f = tab['pythonize']
154 # old_val = getattr(self, prop)
155 # new_val = f(old_val)
156 # #print "Changing ", old_val, "by", new_val
157 # setattr(self, prop, new_val)
158 # else: #new style for service
159 new_val
= tab
.pythonize(getattr(self
, prop
))
160 setattr(self
, prop
, new_val
)
161 except AttributeError , exp
:
162 #print self.get_name(), ' : ', exp
163 pass # Will be catch at the is_correct moment
166 def get_templates(self
):
167 if hasattr(self
, 'use'):
168 return self
.use
.split(',')
173 #We fillfull properties with template ones if need
174 def get_property_by_inheritance(self
, items
, prop
):
175 #If I have the prop, I take mine but I check if I must
177 if hasattr(self
, prop
):
178 value
= getattr(self
, prop
)
179 # Maybe this value is 'null'. If so, we should NOT inherit
180 # and just delete this entry, and hope of course.
184 # Manage the additive inheritance for the property,
185 # if property is in plus, add or replace it
186 if self
.has_plus(prop
):
187 value
+= ',' + self
.get_plus_and_delete(prop
)
189 #Ok, I do not have prop, Maybe my templates do?
191 for i
in self
.templates
:
192 value
= i
.get_property_by_inheritance(items
, prop
)
193 if value
is not None:
194 if self
.has_plus(prop
):
195 value
+= ','+self
.get_plus_and_delete(prop
)
196 setattr(self
, prop
, value
)
198 #I do not have prop, my templates too... Maybe a plus?
199 if self
.has_plus(prop
):
200 value
= self
.get_plus_and_delete(prop
)
201 setattr(self
, prop
, value
)
203 #Not event a plus... so None :)
207 #We fillfull properties with template ones if need
208 def get_customs_properties_by_inheritance(self
, items
):
209 for i
in self
.templates
:
210 tpl_cv
= i
.get_customs_properties_by_inheritance(items
)
213 if prop
not in self
.customs
:
216 value
= self
.customs
[prop
]
217 if self
.has_plus(prop
):
218 value
= value
+self
.get_plus_and_delete(prop
)
219 self
.customs
[prop
] = value
220 for prop
in self
.customs
:
221 value
= self
.customs
[prop
]
222 if self
.has_plus(prop
):
223 value
= value
= value
+','+self
.get_plus_and_delete(prop
)
224 self
.customs
[prop
] = value
225 #We can get custom properties in plus, we need to get all
228 cust_in_plus
= self
.get_all_plus_and_delete()
229 for prop
in cust_in_plus
:
230 self
.customs
[prop
] = cust_in_plus
[prop
]
234 def has_plus(self
, prop
):
242 def get_all_plus_and_delete(self
):
244 props
= self
.plus
.keys() #we delete entries, so no for ... in ...
246 res
[prop
] = self
.get_plus_and_delete(prop
)
250 def get_plus_and_delete(self
, prop
):
251 val
= self
.plus
[prop
]
256 #Check is required prop are set:
257 #template are always correct
258 def is_correct(self
):
260 properties
= self
.__class
__.properties
261 for prop
, entry
in properties
.items():
262 if not hasattr(self
, prop
) and entry
.required
:
263 print self
.get_name(), "missing property :", prop
268 #This function is used by service and hosts
269 #to transform Nagios2 parameters to Nagios3
270 #ones, like normal_check_interval to
271 #check_interval. There is a old_parameters tab
272 #in Classes taht give such modifications to do.
273 def old_properties_names_to_new(self
):
274 old_properties
= self
.__class
__.old_properties
275 for old_name
, new_name
in old_properties
.items():
276 #Ok, if we got old_name and NO new name,
278 if hasattr(self
, old_name
) and not hasattr(self
, new_name
):
279 value
= getattr(self
, old_name
)
280 setattr(self
, new_name
, value
)
283 def add_downtime(self
, downtime
):
284 self
.downtimes
.append(downtime
)
287 def del_downtime(self
, downtime_id
):
289 for dt
in self
.downtimes
:
290 if dt
.id == downtime_id
:
292 dt
.can_be_deleted
= True
293 if d_to_del
is not None:
294 self
.downtimes
.remove(d_to_del
)
297 def add_comment(self
, comment
):
298 self
.comments
.append(comment
)
301 def del_comment(self
, comment_id
):
303 for c
in self
.comments
:
304 if c
.id == comment_id
:
306 c
.can_be_deleted
= True
307 if c_to_del
is not None:
308 self
.comments
.remove(c_to_del
)
311 def acknowledge_problem(self
, sticky
, notify
, persistent
, author
, comment
):
312 if self
.state
!= self
.ok_up
:
314 self
.create_notifications('ACKNOWLEDGEMENT')
315 self
.problem_has_been_acknowledged
= True
320 a
= Acknowledge(self
, sticky
, notify
, persistent
, author
, comment
)
321 self
.acknowledgement
= a
322 if self
.my_type
== 'host':
326 c
= Comment(self
, persistent
, author
, comment
,
327 comment_type
, 4, 0, False, 0)
329 self
.broks
.append(self
.get_update_status_brok())
332 # Delete the acknowledgement object and reset the flag
333 # but do not remove the associated comment.
334 def unacknowledge_problem(self
):
335 if self
.problem_has_been_acknowledged
:
336 self
.problem_has_been_acknowledged
= False
337 #Should not be deleted, a None is Good
338 self
.acknowledgement
= None
339 #del self.acknowledgement
340 # find comments of non-persistent ack-comments and delete them too
341 for c
in self
.comments
:
342 if c
.entry_type
== 4 and not c
.persistent
:
343 self
.del_comment(c
.id)
344 self
.broks
.append(self
.get_update_status_brok())
347 # Check if we have an acknowledgement and if this is marked as sticky.
348 # This is needed when a non-ok state changes
349 def unacknowledge_problem_if_not_sticky(self
):
350 if hasattr(self
, 'acknowledgement') and self
.acknowledgement
is not None:
351 if not self
.acknowledgement
.sticky
:
352 self
.unacknowledge_problem()
355 #Will flatten some parameters taggued by the 'conf_send_preparation'
356 #property because they are too "linked" to be send like that (like realms)
357 def prepare_for_conf_sending(self
):
360 for prop
, entry
in cls
.properties
.items():
361 #Is this property need preparation for sending?
362 if entry
.conf_send_preparation
is not None:
363 f
= entry
.conf_send_preparation
365 val
= f(getattr(self
, prop
))
366 setattr(self
, prop
, val
)
368 if hasattr(cls
, 'running_properties'):
369 for prop
, entry
in cls
.running_properties
.items():
370 #Is this property need preparation for sending?
371 if entry
.conf_send_preparation
is not None:
372 f
= entry
.conf_send_preparation
374 val
= f(getattr(self
, prop
))
375 setattr(self
, prop
, val
)
380 #Get the property for an object, with good value
381 #and brok_transformation if need
382 def get_property_value_for_brok(self
, prop
, tab
):
384 #Get the current value, or the default if need
385 value
= getattr(self
, prop
, entry
.default
)
387 #Apply brok_transformation if need
388 # Look if we must preprocess the value first
389 pre_op
= entry
.brok_transformation
390 if pre_op
is not None:
391 value
= pre_op(self
, value
)
396 #Fill data with info of item by looking at brok_type
397 #in props of properties or running_propterties
398 def fill_data_brok_from(self
, data
, brok_type
):
400 #Now config properties
401 for prop
, entry
in cls
.properties
.items():
402 #Is this property intended for brokking?
403 # if 'fill_brok' in cls.properties[prop]:
404 if brok_type
in entry
.fill_brok
:
405 data
[prop
] = self
.get_property_value_for_brok(prop
, cls
.properties
)
407 # Maybe the class do not have running_properties
408 if hasattr(cls
, 'running_properties'):
409 # We've got prop in running_properties too
410 for prop
, entry
in cls
.running_properties
.items():
411 # if 'fill_brok' in cls.running_properties[prop]:
412 if brok_type
in entry
.fill_brok
:
413 data
[prop
] = self
.get_property_value_for_brok(prop
, cls
.running_properties
)
416 #Get a brok with initial status
417 def get_initial_status_brok(self
):
419 my_type
= cls
.my_type
420 data
= {'id' : self
.id}
422 self
.fill_data_brok_from(data
, 'full_status')
423 b
= Brok('initial_'+my_type
+'_status', data
)
427 #Get a brok with update item status
428 def get_update_status_brok(self
):
430 my_type
= cls
.my_type
432 data
= {'id' : self
.id}
433 self
.fill_data_brok_from(data
, 'full_status')
434 b
= Brok('update_'+my_type
+'_status', data
)
438 #Get a brok with check_result
439 def get_check_result_brok(self
):
441 my_type
= cls
.my_type
444 self
.fill_data_brok_from(data
, 'check_result')
445 b
= Brok(my_type
+'_check_result', data
)
449 #Get brok about the new schedule (next_check)
450 def get_next_schedule_brok(self
):
452 my_type
= cls
.my_type
455 self
.fill_data_brok_from(data
, 'next_schedule')
456 b
= Brok(my_type
+'_next_schedule', data
)
460 #Link one command property to a class (for globals like oc*p_command)
461 def linkify_one_command_with_commands(self
, commands
, prop
):
462 if hasattr(self
, prop
):
463 command
= getattr(self
, prop
).strip()
465 if hasattr(self
, 'poller_tag'):
466 cmdCall
= CommandCall(commands
, command
,
467 poller_tag
=self
.poller_tag
)
468 elif hasattr(self
, 'reactionner_tag'):
469 cmdCall
= CommandCall(commands
, command
,
470 reactionner_tag
=self
.reactionner_tag
)
472 cmdCall
= CommandCall(commands
, command
)
473 setattr(self
, prop
, cmdCall
)
475 setattr(self
, prop
, None)
480 def __init__(self
, items
):
482 self
.configuration_warnings
= []
483 self
.configuration_errors
= []
491 return self
.items
.itervalues()
495 return len(self
.items
)
498 def __delitem__(self
, key
):
502 def __setitem__(self
, key
, value
):
503 self
.items
[key
] = value
506 def __getitem__(self
, key
):
507 return self
.items
[key
]
510 #We create the reversed list so search will be faster
511 #We also create a twins list with id of twins (not the original
512 #just the others, higher twins)
513 def create_reversed_list(self
):
514 self
.reversed_list
= {}
516 name_property
= self
.__class
__.name_property
517 for id in self
.items
:
518 if hasattr(self
.items
[id], name_property
):
519 name
= getattr(self
.items
[id], name_property
)
520 if name
not in self
.reversed_list
:
521 self
.reversed_list
[name
] = id
523 self
.twins
.append(id)
526 def find_id_by_name(self
, name
):
527 if hasattr(self
, 'reversed_list'):
528 if name
in self
.reversed_list
:
529 return self
.reversed_list
[name
]
532 else: #ok, an early ask, with no reversed list from now...
533 name_property
= self
.__class
__.name_property
535 if hasattr(i
, name_property
):
536 i_name
= getattr(i
, name_property
)
542 def find_by_name(self
, name
):
543 id = self
.find_id_by_name(name
)
545 return self
.items
[id]
551 for id in self
.items
:
552 self
.items
[id].pythonize()
555 def create_tpl_list(self
):
556 for id in self
.items
:
559 self
.templates
[id] = i
562 def find_tpl_by_name(self
, name
):
563 for id in self
.templates
:
565 if hasattr(i
, 'name') and i
.name
== name
:
570 def linkify_templates(self
):
571 #First we create a list of all templates
572 self
.create_tpl_list()
574 tpls
= i
.get_templates()
577 t
= self
.find_tpl_by_name(tpl
.strip())
580 else: # not find? not good!
581 err
= "ERROR: the template '%s' defined for '%s' is unkown" % (tpl
, i
.get_name())
582 i
.configuration_errors
.append(err
)
583 i
.templates
= new_tpls
587 def is_correct(self
):
588 #we are ok at the begining. Hope we still ok at the end...
590 #Some class do not have twins, because they do not have names
591 #like servicedependancies
592 if hasattr(self
, 'twins'):
593 #Ok, look at no twins (it's bad!)
594 for id in self
.twins
:
596 print "Error: the", i
.__class
__.my_type
, i
.get_name(), "is duplicated"
598 #Then look if we have some errors in the conf
599 #Juts print warnings, but raise errors
600 for err
in self
.configuration_warnings
:
602 for err
in self
.configuration_errors
:
606 #Then look for individual ok
612 #We remove useless properties and templates
613 def clean_useless(self
):
615 tpls
= [id for id in self
.items
if self
.items
[id].is_tpl()]
618 #Ok now delete useless in items
624 except AttributeError:
629 #If a prop is absent and is not required, put the default value
630 def fill_default(self
):
638 for id in self
.items
:
639 s
= s
+ str(cls
) + ':' + str(id) + str(self
.items
[id]) + '\n'
643 # Inheritance forjust a property
644 def apply_partial_inheritance(self
, prop
):
646 i
.get_property_by_inheritance(self
, prop
)
649 def apply_inheritance(self
):
650 #We check for all Class properties if the host has it
651 #if not, it check all host templates for a value
652 cls
= self
.inner_class
653 for prop
in cls
.properties
:
654 self
.apply_partial_inheritance(prop
)
656 i
.get_customs_properties_by_inheritance(self
)
660 #Remember: item id respect the order of conf. So if and item
661 # is defined multiple times,
662 #we want to keep the first one.
663 #Services are also managed here but they are specials:
664 #We remove twins services with the same host_name/service_description
665 #Remember: host service are take into account first before hostgroup service
666 #Id of host service are lower than hostgroups one, so they are
667 #in self.twins_services
668 #and we can remove them.
669 def remove_twins(self
):
670 for id in self
.twins
:
672 type = i
.__class
__.my_type
673 print 'Warning: the', type, i
.get_name(), 'is already defined.'
674 del self
.items
[id] #bye bye
675 #do not remove twins, we should look in it, but just void it
677 #del self.twins #no more need
681 #We've got a contacts property with , separated contacts names
682 #and we want have a list of Contacts
683 def linkify_with_contacts(self
, contacts
):
685 if hasattr(i
, 'contacts'):
686 contacts_tab
= i
.contacts
.split(',')
687 contacts_tab
= strip_and_uniq(contacts_tab
)
689 for c_name
in contacts_tab
:
691 c
= contacts
.find_by_name(c_name
)
693 new_contacts
.append(c
)
694 # Else : Add in the errors tab.
695 # will be raised at is_correct
697 err
= "ERROR: the contact '%s' defined for '%s' is unkown" % (c_name
, i
.get_name())
698 i
.configuration_errors
.append(err
)
699 # Get the list, but first make elements uniq
700 i
.contacts
= list(set(new_contacts
))
703 # Make link between an object and its escalations
704 def linkify_with_escalations(self
, escalations
):
706 if hasattr(i
, 'escalations'):
707 #print i.get_name(), 'going to link escalations', i.escalations
708 escalations_tab
= i
.escalations
.split(',')
709 escalations_tab
= strip_and_uniq(escalations_tab
)
711 for es_name
in escalations_tab
:
712 es
= escalations
.find_by_name(es_name
)
714 new_escalations
.append(es
)
717 i
.escalations
= new_escalations
718 #print i.get_name(), 'finallygot escalation', i.escalations
721 #Make link between item and it's resultmodulations
722 def linkify_with_resultmodulations(self
, resultmodulations
):
724 if hasattr(i
, 'resultmodulations'):
725 resultmodulations_tab
= i
.resultmodulations
.split(',')
726 resultmodulations_tab
= strip_and_uniq(resultmodulations_tab
)
727 new_resultmodulations
= []
728 for rm_name
in resultmodulations_tab
:
729 rm
= resultmodulations
.find_by_name(rm_name
)
731 new_resultmodulations
.append(rm
)
734 i
.resultmodulations
= new_resultmodulations
737 #If we've got a contact_groups properties, we search for all
738 #theses groups and ask them their contacts, and then add them
739 #all into our contacts property
740 def explode_contact_groups_into_contacts(self
, contactgroups
):
742 if hasattr(i
, 'contact_groups'):
743 cgnames
= i
.contact_groups
.split(',')
744 cgnames
= strip_and_uniq(cgnames
)
745 for cgname
in cgnames
:
746 cg
= contactgroups
.find_by_name(cgname
)
748 err
= "The contact group '%s'defined on the %s '%s' do not exist" % (cgname
, i
.__class
__.my_type
, i
.get_name())
749 i
.configuration_errors
.append(err
)
751 cnames
= contactgroups
.get_members_by_name(cgname
)
752 #We add contacts into our contacts
754 if hasattr(i
, 'contacts'):
755 i
.contacts
+= ','+cnames
759 #Link a timeperiod property (prop)
760 def linkify_with_timeperiods(self
, timeperiods
, prop
):
763 tpname
= getattr(i
, prop
)
764 tp
= timeperiods
.find_by_name(tpname
)
769 #Link one command property
770 def linkify_one_command_with_commands(self
, commands
, prop
):
773 command
= getattr(i
, prop
).strip()
775 if hasattr(i
, 'poller_tag'):
776 cmdCall
= CommandCall(commands
, command
,
777 poller_tag
=i
.poller_tag
)
778 elif hasattr(i
, 'reactionner_tag'):
779 cmdCall
= CommandCall(commands
, command
,
780 reactionner_tag
=i
.reactionner_tag
)
782 cmdCall
= CommandCall(commands
, command
)
784 setattr(i
, prop
, cmdCall
)
787 setattr(i
, prop
, None)
790 #Link a command list (commands with , between) in real CommandCalls
791 def linkify_command_list_with_commands(self
, commands
, prop
):
794 coms
= getattr(i
, prop
).split(',')
795 coms
= strip_and_uniq(coms
)
799 if hasattr(i
, 'poller_tag'):
800 cmdCall
= CommandCall(commands
, com
,
801 poller_tag
=i
.poller_tag
)
802 elif hasattr(i
, 'reactionner_tag'):
803 cmdCall
= CommandCall(commands
, com
,
804 reactionner_tag
=i
.reactionner_tag
)
806 cmdCall
= CommandCall(commands
, com
)
808 com_list
.append(cmdCall
)
811 setattr(i
, prop
, com_list
)
814 #Return a set with ALL hosts (used in ! expressions)
815 def get_all_host_names_set(self
, hosts
):
816 hnames
= [h
.host_name
for h
in hosts
.items
.values()
817 if hasattr(h
, 'host_name')]
821 def evaluate_hostgroup_expression(self
, expr
, hosts
, hostgroups
):
824 #print "I'm trying to prepare the expression", expr
826 #We've got problem with the "-" sign. It can be in a
827 #valid name but it's a sign of difference for sets
828 #so we change the - now by something, then we reverse after
830 expr
= expr
.replace('-', 'MINUSSIGN')
832 # ! (not) should be changed as "ALL-" (all but not...)
834 ALLELEMENTS
= self
.get_all_host_names_set(hosts
)
835 #print "Changing ! by ALLELEMENTS- in ", expr
836 expr
= expr
.replace('!', 'ALLELEMENTS-')
838 # We change all separaton token by 10 spaces
839 # (so names can still have some spaces
840 # on them like Europe Servers because we wil cut byy this 10spaces after
842 for c
in ['|', '&', '(', ')', ',', '-']:
843 strip_expr
= strip_expr
.replace(c
, ' '*10)
844 #print "Stripped expression:", strip_expr
846 tokens
= strip_expr
.split(' '*10)
847 # Strip and non void token
848 tokens
= [token
.strip() for token
in tokens
if token
!= '']
849 #print "Tokens:", tokens
851 #Now add in locals() dict (yes, real variables!)
853 #ALLELEMENTS is a private group for us
854 if token
!= 'ALLELEMENTS':
855 #Maybe the token was with - at the begining,
856 #but we change all by "MINUSSIGN". We must change it back now
858 if 'MINUSSIGN' in token
:
859 tmp_token
= token
.replace('MINUSSIGN', '-')
860 members
= hostgroups
.get_members_by_name(tmp_token
)
862 members
= hostgroups
.get_members_by_name(token
)
865 #print "Get members", members
866 elts
= members
.split(',')
867 elts
= strip_and_uniq(elts
)
869 #print "Elements:", elts
870 #print "Now set in locals the token new values"
871 locals()[token
.upper()] = elts
873 if 'MINUSSIGN' in token
:
874 token
= token
.replace('MINUSSIGN', '-')
875 print self
.__dict
__, type(self
)
876 err
= "ERROR: the group %s is unknown !" % (token
,)
878 self
.configuration_errors
.append(err
)
881 # Now changing the exprtoken value with
882 # UPPER one (so less risk of problem...
883 expr
= expr
.replace(token
, token
.upper())
885 #print "Final expression:", expr
887 evaluation
= eval(expr
)
889 print "The syntax of %s is invalid" % original_expr
892 print "There is a unknow name in %s" % original_expr
894 #print "Evaluation :", evaluation
896 # In evaluation we can have multiples values because
897 # of , (so it make a tuple in fact)
898 # we must OR them in the result
900 for part
in evaluation
:
902 res
.extend(list(part
))
903 else:#no , so we do not have a tuple but a simple uniq set
904 res
.extend(list(evaluation
))
905 res_string
= ','.join(res
)
906 #print "Final resolution is", res_string
910 #If we've got a hostgroup_name property, we search for all
911 #theses groups and ask them their hosts, and then add them
912 #all into our host_name property
913 def explode_host_groups_into_hosts(self
, hosts
, hostgroups
):
915 if hasattr(i
, 'hostgroup_name'):
916 hnames
= self
.evaluate_hostgroup_expression(i
.hostgroup_name
,
919 if hasattr(i
, 'host_name'):
920 i
.host_name
+= ',' + str(hnames
)
922 i
.host_name
= str(hnames
)