#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (C) 2009-2012:
# Gabes Jean, naparuba@gmail.com
# Gerhard Lausser, Gerhard.Lausser@consol.de
# Gregory Starck, g.starck@gmail.com
# Hartmut Goebel, h.goebel@goebel-consult.de
#
# This file is part of Shinken.
#
# Shinken is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Shinken is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Shinken. If not, see <http://www.gnu.org/licenses/>.
""" This class is a base class for nearly all configuration
elements like service, hosts or contacts.
"""
import time
import cPickle # for hashing compute
# Try to import md5 function
try:
from hashlib import md5
except ImportError:
from md5 import md5
from copy import copy
from shinken.graph import Graph
from shinken.commandcall import CommandCall
from shinken.property import StringProp, ListProp, BoolProp
from shinken.brok import Brok
from shinken.util import strip_and_uniq
from shinken.acknowledge import Acknowledge
from shinken.comment import Comment
from shinken.complexexpression import ComplexExpressionFactory
from shinken.log import logger
[docs]class Item(object):
properties = {
'imported_from': StringProp(default='unknown'),
'use': ListProp(default=''),
'name': StringProp(default=''),
# TODO: find why we can't uncomment this line below.
#'register': BoolProp(default='1'),
}
running_properties = {
# All errors and warning raised during the configuration parsing
# and that will raised real warning/errors during the is_correct
'configuration_warnings': ListProp(default=[]),
'configuration_errors': ListProp(default=[]),
'hash': StringProp(default=''),
# We save all template we asked us to load from
'tags': ListProp(default=set(), fill_brok=['full_status']),
}
macros = {
}
def __init__(self, params={}):
# We have our own id of My Class type :)
# use set attr for going into the slots
# instead of __dict__ :)
cls = self.__class__
self.id = cls.id
cls.id += 1
self.customs = {} # for custom variables
self.plus = {} # for value with a +
self.init_running_properties()
# [0] = + -> new key-plus
# [0] = _ -> new custom entry in UPPER case
for key in params:
if len(params[key]) >= 1 and params[key][0] == '+':
# Special case: a _MACRO can be a plus. so add to plus
# but upper the key for the macro name
if key[0] == "_":
self.plus[key.upper()] = params[key][1:] # we remove the +
else:
self.plus[key] = params[key][1:] # we remove the +
elif key[0] == "_":
custom_name = key.upper()
self.customs[custom_name] = params[key]
else:
setattr(self, key, params[key])
[docs] def init_running_properties(self):
for prop, entry in self.__class__.running_properties.items():
# Copy is slow, so we check type
# Type with __iter__ are list or dict, or tuple.
# Item need it's own list, so we copy
val = entry.default
if hasattr(val, '__iter__'):
setattr(self, prop, copy(val))
else:
setattr(self, prop, val)
# each instance to have his own running prop!
[docs] def copy(self):
""" Return a copy of the item, but give him a new id """
cls = self.__class__
i = cls({}) # Dummy item but with it's own running properties
for prop in cls.properties:
if hasattr(self, prop):
val = getattr(self, prop)
setattr(i, prop, val)
# Also copy the customs tab
i.customs = copy(self.customs)
return i
[docs] def clean(self):
""" Clean useless things not requested once item has been fully initialized&configured.
Like temporary attributes such as "imported_from", etc.. """
for name in ('imported_from', 'use', 'plus', 'templates',):
try:
delattr(self, name)
except AttributeError:
pass
def __str__(self):
return str(self.__dict__) + '\n'
[docs] def is_tpl(self):
""" Return if the elements is a template """
try:
return self.register == '0'
except Exception, exp:
return False
# If a prop is absent and is not required, put the default value
[docs] def fill_default(self):
""" Fill missing properties if they are missing """
cls = self.__class__
for prop, entry in cls.properties.items():
if not hasattr(self, prop) and entry.has_default:
setattr(self, prop, entry.default)
# We load every useful parameter so no need to access global conf later
# Must be called after a change in a global conf parameter
[docs] def load_global_conf(cls, conf):
""" Used to put global values in the sub Class like
hosts or services """
# conf have properties, if 'enable_notifications':
# { [...] 'class_inherit': [(Host, None), (Service, None),
# (Contact, None)]}
# get the name and put the value if None, put the Name
# (not None) if not (not clear?)
for prop, entry in conf.properties.items():
# If we have a class_inherit, and the arbiter really send us it
# if 'class_inherit' in entry and hasattr(conf, prop):
if hasattr(conf, prop):
for (cls_dest, change_name) in entry.class_inherit:
if cls_dest == cls: # ok, we've got something to get
value = getattr(conf, prop)
if change_name is None:
setattr(cls, prop, value)
else:
setattr(cls, change_name, value)
# Make this method a classmethod
load_global_conf = classmethod(load_global_conf)
# Use to make python properties
[docs] def pythonize(self):
cls = self.__class__
for prop, tab in cls.properties.items():
try:
new_val = tab.pythonize(getattr(self, prop))
setattr(self, prop, new_val)
except AttributeError, exp:
#print exp
pass # Will be catch at the is_correct moment
except KeyError, exp:
#print "Missing prop value", exp
err = "the property '%s' of '%s' do not have value" % (prop, self.get_name())
self.configuration_errors.append(err)
except ValueError, exp:
err = "incorrect type for property '%s' of '%s'" % (prop, self.get_name())
self.configuration_errors.append(err)
# Compute a hash of this element values. Should be launched
# When we got all our values, but not linked with other objects
[docs] def compute_hash(self):
# ID will always changed between runs, so we remove it
# for hash compute
i = self.id
del self.id
m = md5()
tmp = cPickle.dumps(self, cPickle.HIGHEST_PROTOCOL)
m.update(tmp)
self.hash = m.digest()
# and put again our id
self.id = i
[docs] def get_templates(self):
if hasattr(self, 'use') and self.use != '':
return self.use.split(',')
else:
return []
# We fillfull properties with template ones if need
[docs] def get_property_by_inheritance(self, items, prop):
# If I have the prop, I take mine but I check if I must
# add a plus property
if hasattr(self, prop):
value = getattr(self, prop)
# Maybe this value is 'null'. If so, we should NOT inherit
# and just delete this entry, and hope of course.
# Keep "null" values, because in "inheritance chaining" they must
# be passed from one level to the next.
#if value == 'null':
# delattr(self, prop)
# return None
# Manage the additive inheritance for the property,
# if property is in plus, add or replace it
# Template should keep the '+' at the beginning of the chain
if self.has_plus(prop):
value = self.get_plus_and_delete(prop) + ',' + value
if self.is_tpl():
value = '+' + value
return value
# Ok, I do not have prop, Maybe my templates do?
# Same story for plus
for i in self.templates:
value = i.get_property_by_inheritance(items, prop)
if value is not None:
# If our template give us a '+' value, we should continue to loop
still_loop = False
if value.startswith('+'):
# Templates should keep their + inherited from their parents
if not self.is_tpl():
value = value[1:]
still_loop = True
# Maybe in the previous loop, we set a value, use it too
if hasattr(self, prop):
# If the current value is strong, it will simplify the problem
if value.startswith('+'):
# In this case we can remove the + from our current
# tpl because our value will be final
value = ','.join([getattr(self, prop), value[1:]])
else: # If not, se should keep the + sign of need
value = ','.join([getattr(self, prop), value])
# Ok, we can set it
setattr(self, prop, value)
# If we only got some '+' values, we must still loop
# for an end value without it
if not still_loop:
# And set my own value in the end if need
if self.has_plus(prop):
value = ','.join([getattr(self, prop), self.get_plus_and_delete(prop)])
# Template should keep their '+'
if self.is_tpl() and not value.startswith('+'):
value = '+' + value
setattr(self, prop, value)
return value
# Maybe templates only give us + values, so we didn't quit, but we already got a
# self.prop value after all
template_with_only_plus = hasattr(self, prop)
# I do not have endingprop, my templates too... Maybe a plus?
# warning: if all my templates gave me '+' values, do not forgot to
# add the already set self.prop value
if self.has_plus(prop):
if template_with_only_plus:
value = ','.join([getattr(self, prop), self.get_plus_and_delete(prop)])
else:
value = self.get_plus_and_delete(prop)
# Template should keep their '+' chain
# We must say it's a '+' value, so our son will now that it must
# still loop
if self.is_tpl() and not value.startswith('+'):
value = '+' + value
setattr(self, prop, value)
return value
# Ok so in the end, we give the value we got if we have one, or None
# Not even a plus... so None :)
return getattr(self, prop, None)
# We fillfull properties with template ones if need
[docs] def get_customs_properties_by_inheritance(self, items):
for i in self.templates:
tpl_cv = i.get_customs_properties_by_inheritance(items)
if tpl_cv is not {}:
for prop in tpl_cv:
if prop not in self.customs:
value = tpl_cv[prop]
else:
value = self.customs[prop]
if self.has_plus(prop):
value = self.get_plus_and_delete(prop) + ',' + value
self.customs[prop] = value
for prop in self.customs:
value = self.customs[prop]
if self.has_plus(prop):
value = self.get_plus_and_delete(prop) + ',' + value
self.customs[prop] = value
# We can get custom properties in plus, we need to get all
# entires and put
# them into customs
cust_in_plus = self.get_all_plus_and_delete()
for prop in cust_in_plus:
self.customs[prop] = cust_in_plus[prop]
return self.customs
[docs] def has_plus(self, prop):
try:
self.plus[prop]
except:
return False
return True
[docs] def get_all_plus_and_delete(self):
res = {}
props = self.plus.keys() # we delete entries, so no for ... in ...
for prop in props:
res[prop] = self.get_plus_and_delete(prop)
return res
[docs] def get_plus_and_delete(self, prop):
val = self.plus[prop]
del self.plus[prop]
return val
# Check is required prop are set:
# template are always correct
[docs] def is_correct(self):
state = True
properties = self.__class__.properties
# Raised all previously saw errors like unknown contacts and co
if self.configuration_errors != []:
state = False
for err in self.configuration_errors:
logger.error("[item::%s] %s" % (self.get_name(), err))
for prop, entry in properties.items():
if not hasattr(self, prop) and entry.required:
logger.warning("[item::%s] %s property is missing" % (self.get_name(), prop))
state = False
return state
# This function is used by service and hosts
# to transform Nagios2 parameters to Nagios3
# ones, like normal_check_interval to
# check_interval. There is a old_parameters tab
# in Classes that give such modifications to do.
[docs] def old_properties_names_to_new(self):
old_properties = self.__class__.old_properties
for old_name, new_name in old_properties.items():
# Ok, if we got old_name and NO new name,
# we switch the name
if hasattr(self, old_name) and not hasattr(self, new_name):
value = getattr(self, old_name)
setattr(self, new_name, value)
# The arbiter is asking us our raw value before all explode or linking
[docs] def get_raw_import_values(self):
r = {}
properties = self.__class__.properties.keys()
# Register is not by default in the properties
if not 'register' in properties:
properties.append('register')
for prop in properties:
if hasattr(self, prop):
v = getattr(self, prop)
#print prop, ":", v
r[prop] = v
return r
[docs] def add_downtime(self, downtime):
self.downtimes.append(downtime)
[docs] def del_downtime(self, downtime_id):
d_to_del = None
for dt in self.downtimes:
if dt.id == downtime_id:
d_to_del = dt
dt.can_be_deleted = True
if d_to_del is not None:
self.downtimes.remove(d_to_del)
[docs] def acknowledge_problem(self, sticky, notify, persistent, author, comment, end_time=0):
if self.state != self.ok_up:
if notify:
self.create_notifications('ACKNOWLEDGEMENT')
self.problem_has_been_acknowledged = True
if sticky == 2:
sticky = True
else:
sticky = False
a = Acknowledge(self, sticky, notify, persistent, author, comment, end_time=end_time)
self.acknowledgement = a
if self.my_type == 'host':
comment_type = 1
else:
comment_type = 2
c = Comment(self, persistent, author, comment,
comment_type, 4, 0, False, 0)
self.add_comment(c)
self.broks.append(self.get_update_status_brok())
# Look if we got an ack that is too old with an expire date and should
# be delete
[docs] def check_for_expire_acknowledge(self):
if self.acknowledgement and self.acknowledgement.end_time != 0 and self.acknowledgement.end_time < time.time():
self.unacknowledge_problem()
# Delete the acknowledgement object and reset the flag
# but do not remove the associated comment.
[docs] def unacknowledge_problem(self):
if self.problem_has_been_acknowledged:
logger.debug("[item::%s] deleting acknowledge of %s" % (self.get_name(), self.get_dbg_name()))
self.problem_has_been_acknowledged = False
# Should not be deleted, a None is Good
self.acknowledgement = None
# del self.acknowledgement
# find comments of non-persistent ack-comments and delete them too
for c in self.comments:
if c.entry_type == 4 and not c.persistent:
self.del_comment(c.id)
self.broks.append(self.get_update_status_brok())
# Check if we have an acknowledgement and if this is marked as sticky.
# This is needed when a non-ok state changes
[docs] def unacknowledge_problem_if_not_sticky(self):
if hasattr(self, 'acknowledgement') and self.acknowledgement is not None:
if not self.acknowledgement.sticky:
self.unacknowledge_problem()
# Will flatten some parameters tagged by the 'conf_send_preparation'
# property because they are too "linked" to be send like that (like realms)
[docs] def prepare_for_conf_sending(self):
cls = self.__class__
for prop, entry in cls.properties.items():
# Is this property need preparation for sending?
if entry.conf_send_preparation is not None:
f = entry.conf_send_preparation
if f is not None:
val = f(getattr(self, prop))
setattr(self, prop, val)
if hasattr(cls, 'running_properties'):
for prop, entry in cls.running_properties.items():
# Is this property need preparation for sending?
if entry.conf_send_preparation is not None:
f = entry.conf_send_preparation
if f is not None:
val = f(getattr(self, prop))
setattr(self, prop, val)
# Get the property for an object, with good value
# and brok_transformation if need
[docs] def get_property_value_for_brok(self, prop, tab):
entry = tab[prop]
# Get the current value, or the default if need
value = getattr(self, prop, entry.default)
# Apply brok_transformation if need
# Look if we must preprocess the value first
pre_op = entry.brok_transformation
if pre_op is not None:
value = pre_op(self, value)
return value
# Fill data with info of item by looking at brok_type
# in props of properties or running_properties
[docs] def fill_data_brok_from(self, data, brok_type):
cls = self.__class__
# Now config properties
for prop, entry in cls.properties.items():
# Is this property intended for broking?
if brok_type in entry.fill_brok:
data[prop] = self.get_property_value_for_brok(prop, cls.properties)
# Maybe the class do not have running_properties
if hasattr(cls, 'running_properties'):
# We've got prop in running_properties too
for prop, entry in cls.running_properties.items():
#if 'fill_brok' in cls.running_properties[prop]:
if brok_type in entry.fill_brok:
data[prop] = self.get_property_value_for_brok(prop, cls.running_properties)
# Get a brok with initial status
[docs] def get_initial_status_brok(self):
cls = self.__class__
my_type = cls.my_type
data = {'id': self.id}
self.fill_data_brok_from(data, 'full_status')
b = Brok('initial_' + my_type + '_status', data)
return b
# Get a brok with update item status
[docs] def get_update_status_brok(self):
cls = self.__class__
my_type = cls.my_type
data = {'id': self.id}
self.fill_data_brok_from(data, 'full_status')
b = Brok('update_' + my_type + '_status', data)
return b
# Get a brok with check_result
[docs] def get_check_result_brok(self):
cls = self.__class__
my_type = cls.my_type
data = {}
self.fill_data_brok_from(data, 'check_result')
b = Brok(my_type + '_check_result', data)
return b
# Get brok about the new schedule (next_check)
[docs] def get_next_schedule_brok(self):
cls = self.__class__
my_type = cls.my_type
data = {}
self.fill_data_brok_from(data, 'next_schedule')
b = Brok(my_type + '_next_schedule', data)
return b
# Link one command property to a class (for globals like oc*p_command)
[docs] def linkify_one_command_with_commands(self, commands, prop):
if hasattr(self, prop):
command = getattr(self, prop).strip()
if command != '':
if hasattr(self, 'poller_tag'):
cmdCall = CommandCall(commands, command,
poller_tag=self.poller_tag)
elif hasattr(self, 'reactionner_tag'):
cmdCall = CommandCall(commands, command,
reactionner_tag=self.reactionner_tag)
else:
cmdCall = CommandCall(commands, command)
setattr(self, prop, cmdCall)
else:
setattr(self, prop, None)
# We look at the 'trigger' prop and we create a trigger for it
[docs] def explode_trigger_string_into_triggers(self, triggers):
src = getattr(self, 'trigger', '')
if src:
# Change on the fly the characters
src = src.replace(r'\n', '\n').replace(r'\t', '\t')
t = triggers.create_trigger(src, 'inner-trigger-' + self.__class__.my_type + '' + str(self.id))
if t:
# Maybe the trigger factory give me a already existing trigger,
# so my name can be dropped
self.triggers.append(t.get_name())
# Link with triggers. Can be with a "in source" trigger, or a file name
[docs] def linkify_with_triggers(self, triggers):
# Get our trigger string and trigger names in the same list
self.triggers.extend(self.trigger_name)
#print "I am linking my triggers", self.get_full_name(), self.triggers
new_triggers = []
for tname in self.triggers:
t = triggers.find_by_name(tname)
if t:
setattr(t, 'trigger_broker_raise_enabled', self.trigger_broker_raise_enabled)
new_triggers.append(t)
else:
self.configuration_errors.append('the %s %s does have a unknown trigger_name "%s"' % (self.__class__.my_type, self.get_full_name(), tname))
self.triggers = new_triggers
[docs]class Items(object):
def __init__(self, items):
self.items = {}
self.configuration_warnings = []
self.configuration_errors = []
for i in items:
self.items[i.id] = i
self.templates = {}
# We should keep a graph of templates relations
self.templates_graph = Graph()
def __iter__(self):
return self.items.itervalues()
def __len__(self):
return len(self.items)
def __delitem__(self, key):
try:
del self.items[key]
except KeyError: # we don't want it, we do not have it. All is perfect
pass
def __setitem__(self, key, value):
self.items[key] = value
def __getitem__(self, key):
return self.items[key]
def __contains__(self, key):
return key in self.items
[docs] def compute_hash(self):
for i in self:
i.compute_hash()
# We create the reversed list so search will be faster
# We also create a twins list with id of twins (not the original
# just the others, higher twins)
[docs] def create_reversed_list(self):
self.reversed_list = {}
self.twins = []
name_property = self.__class__.name_property
for id in self.items:
if hasattr(self.items[id], name_property):
name = getattr(self.items[id], name_property)
if name not in self.reversed_list:
self.reversed_list[name] = id
else:
self.twins.append(id)
[docs] def find_id_by_name(self, name):
if hasattr(self, 'reversed_list'):
if name in self.reversed_list:
return self.reversed_list[name]
else:
return None
else: # ok, an early ask, with no reversed list from now...
name_property = self.__class__.name_property
for i in self:
if hasattr(i, name_property):
i_name = getattr(i, name_property)
if i_name == name:
return i.id
return None
[docs] def find_by_name(self, name):
id = self.find_id_by_name(name)
if id is not None:
return self.items[id]
else:
return None
# prepare_for_conf_sending to flatten some properties
[docs] def prepare_for_sending(self):
for i in self:
i.prepare_for_conf_sending()
# It's used to change old Nagios2 names to
# Nagios3 ones
[docs] def old_properties_names_to_new(self):
for i in self:
i.old_properties_names_to_new()
[docs] def pythonize(self):
for id in self.items:
self.items[id].pythonize()
[docs] def create_tpl_list(self):
for id in self.items:
i = self.items[id]
if i.is_tpl():
self.templates[id] = i
[docs] def find_tpl_by_name(self, name):
for i in self.templates.values():
if hasattr(i, 'name') and i.name == name:
return i
return None
# We will link all templates, and create the template
# graph too
[docs] def linkify_templates(self):
# First we create a list of all templates
self.create_tpl_list()
for i in self:
tpls = i.get_templates()
new_tpls = []
for tpl in tpls:
tpl = tpl.strip()
# We save this template in the 'tags' set
i.tags.add(tpl)
# Then we link it
t = self.find_tpl_by_name(tpl)
# If it's ok, add the template and update the
# template graph too
if t is not None:
# add the template object to us
new_tpls.append(t)
else: # not find? not good!
err = "the template '%s' defined for '%s' is unknown" % (tpl, i.get_name())
i.configuration_warnings.append(err)
i.templates = new_tpls
# Now we will create the template graph, so
# we look only for templates here. First we should declare our nodes
for tpl in self.templates.values():
self.templates_graph.add_node(tpl)
# And then really create our edge
for tpl in self.templates.values():
for father in tpl.templates:
self.templates_graph.add_edge(father, tpl)
[docs] def is_correct(self):
# we are ok at the beginning. Hope we still ok at the end...
r = True
# Some class do not have twins, because they do not have names
# like servicedependencies
twins = getattr(self, 'twins', None)
if twins is not None:
# Ok, look at no twins (it's bad!)
for id in twins:
i = self.items[id]
logger.error("[items] %s.%s is duplicated from %s" %\
(i.__class__.my_type, i.get_name(), getattr(i, 'imported_from', "unknown source")))
r = False
# Then look if we have some errors in the conf
# Juts print warnings, but raise errors
for err in self.configuration_warnings:
logger.warning("[items] %s" % err)
for err in self.configuration_errors:
logger.error("[items] %s" % err)
r = False
# Then look for individual ok
for i in self:
# Alias and display_name hook hook
prop_name = getattr(self.__class__, 'name_property', None)
if prop_name and not hasattr(i, 'alias') and hasattr(i, prop_name):
setattr(i, 'alias', getattr(i, prop_name))
if prop_name and getattr(i, 'display_name', '') == '' and hasattr(i, prop_name):
setattr(i, 'display_name', getattr(i, prop_name))
# Now other checks
if not i.is_correct():
n = getattr(i, 'imported_from', "unknown source")
logger.error("[items] In %s is incorrect ; from %s" % (i.get_name(), n))
r = False
return r
[docs] def remove_templates(self):
""" Remove useless templates (& properties) of our items ; otherwise we could get errors on config.is_correct() """
tpls = [i for i in self if i.is_tpl()]
for i in tpls:
del self[i.id]
del self.templates
del self.templates_graph
[docs] def clean(self):
""" Request to remove the unnecessary attributes/others from our items """
for i in self:
i.clean()
Item.clean(self)
# If a prop is absent and is not required, put the default value
[docs] def fill_default(self):
for i in self:
i.fill_default()
def __str__(self):
s = ''
cls = self.__class__
for id in self.items:
s = s + str(cls) + ':' + str(id) + str(self.items[id]) + '\n'
return s
# Inheritance for just a property
[docs] def apply_partial_inheritance(self, prop):
for i in self:
i.get_property_by_inheritance(self, prop)
if not i.is_tpl():
# If a "null" attribute was inherited, delete it
try:
if getattr(i, prop) == 'null':
delattr(i, prop)
except:
pass
[docs] def apply_inheritance(self):
# We check for all Class properties if the host has it
# if not, it check all host templates for a value
cls = self.inner_class
for prop in cls.properties:
self.apply_partial_inheritance(prop)
for i in self:
i.get_customs_properties_by_inheritance(self)
# We remove twins
# Remember: item id respect the order of conf. So if and item
# is defined multiple times,
# we want to keep the first one.
# Services are also managed here but they are specials:
# We remove twins services with the same host_name/service_description
# Remember: host service are take into account first before hostgroup service
# Id of host service are lower than hostgroups one, so they are
# in self.twins_services
# and we can remove them.
[docs] def remove_twins(self):
for id in self.twins:
i = self.items[id]
type = i.__class__.my_type
logger.warning("[items] %s.%s is already defined '%s'" % (type, i.get_name(), getattr(i, 'imported_from', "unknown source")))
del self[id] # bye bye
# do not remove twins, we should look in it, but just void it
self.twins = []
#del self.twins #no more need
# We've got a contacts property with , separated contacts names
# and we want have a list of Contacts
[docs] def linkify_with_escalations(self, escalations):
for i in self:
if hasattr(i, 'escalations'):
escalations_tab = i.escalations.split(',')
escalations_tab = strip_and_uniq(escalations_tab)
new_escalations = []
for es_name in [e for e in escalations_tab if e != '']:
es = escalations.find_by_name(es_name)
if es is not None:
new_escalations.append(es)
else: # Escalation not find, not good!
err = "the escalation '%s' defined for '%s' is unknown" % (es_name, i.get_name())
i.configuration_errors.append(err)
i.escalations = new_escalations
# Make link between item and it's resultmodulations
[docs] def linkify_with_resultmodulations(self, resultmodulations):
for i in self:
if hasattr(i, 'resultmodulations'):
resultmodulations_tab = i.resultmodulations.split(',')
resultmodulations_tab = strip_and_uniq(resultmodulations_tab)
new_resultmodulations = []
for rm_name in resultmodulations_tab:
rm = resultmodulations.find_by_name(rm_name)
if rm is not None:
new_resultmodulations.append(rm)
else:
err = "the result modulation '%s' defined on the %s '%s' do not exist" % (rm_name, i.__class__.my_type, i.get_name())
i.configuration_errors.append(err)
continue
i.resultmodulations = new_resultmodulations
# Make link between item and it's business_impact_modulations
[docs] def linkify_with_business_impact_modulations(self, business_impact_modulations):
for i in self:
if hasattr(i, 'business_impact_modulations'):
business_impact_modulations_tab = i.business_impact_modulations.split(',')
business_impact_modulations_tab = strip_and_uniq(business_impact_modulations_tab)
new_business_impact_modulations = []
for rm_name in business_impact_modulations_tab:
rm = business_impact_modulations.find_by_name(rm_name)
if rm is not None:
new_business_impact_modulations.append(rm)
else:
err = "the business impact modulation '%s' defined on the %s '%s' do not exist" % (rm_name, i.__class__.my_type, i.get_name())
i.configuration_errors.append(err)
continue
i.business_impact_modulations = new_business_impact_modulations
# If we've got a contact_groups properties, we search for all
# theses groups and ask them their contacts, and then add them
# all into our contacts property
[docs] def linkify_with_timeperiods(self, timeperiods, prop):
for i in self:
if hasattr(i, prop):
tpname = getattr(i, prop).strip()
# some default values are '', so set None
if tpname == '':
setattr(i, prop, None)
continue
# Ok, get a real name, search for it
tp = timeperiods.find_by_name(tpname)
# If not found, it's an error
if tp is None:
err = "The %s of the %s '%s' named '%s' is unknown!" % (prop, i.__class__.my_type, i.get_name(), tpname)
i.configuration_errors.append(err)
continue
# Got a real one, just set it :)
setattr(i, prop, tp)
# Link one command property
[docs] def linkify_one_command_with_commands(self, commands, prop):
for i in self:
if hasattr(i, prop):
command = getattr(i, prop).strip()
if command != '':
if hasattr(i, 'poller_tag'):
cmdCall = CommandCall(commands, command,
poller_tag=i.poller_tag)
elif hasattr(i, 'reactionner_tag'):
cmdCall = CommandCall(commands, command,
reactionner_tag=i.reactionner_tag)
else:
cmdCall = CommandCall(commands, command)
# TODO: catch None?
setattr(i, prop, cmdCall)
else:
setattr(i, prop, None)
# Link a command list (commands with , between) in real CommandCalls
[docs] def linkify_command_list_with_commands(self, commands, prop):
for i in self:
if hasattr(i, prop):
coms = getattr(i, prop).split(',')
coms = strip_and_uniq(coms)
com_list = []
for com in coms:
if com != '':
if hasattr(i, 'poller_tag'):
cmdCall = CommandCall(commands, com,
poller_tag=i.poller_tag)
elif hasattr(i, 'reactionner_tag'):
cmdCall = CommandCall(commands, com,
reactionner_tag=i.reactionner_tag)
else:
cmdCall = CommandCall(commands, com)
# TODO: catch None?
com_list.append(cmdCall)
else: # TODO: catch?
pass
setattr(i, prop, com_list)
# Link with triggers. Can be with a "in source" trigger, or a file name
[docs] def linkify_with_triggers(self, triggers):
for i in self:
i.linkify_with_triggers(triggers)
# We've got a notificationways property with , separated contacts names
# and we want have a list of NotificationWay
[docs] def linkify_with_checkmodulations(self, checkmodulations):
for i in self:
if not hasattr(i, 'checkmodulations'):
continue
new_checkmodulations = []
for cw_name in i.checkmodulations:
cw = checkmodulations.find_by_name(cw_name)
if cw is not None:
new_checkmodulations.append(cw)
else:
err = "The checkmodulations of the %s '%s' named '%s' is unknown!" % (i.__class__.my_type, i.get_name(), cw_name)
i.configuration_errors.append(err)
# Get the list, but first make elements uniq
i.checkmodulations = new_checkmodulations
# We've got list of macro modulations as list of names, and
# we want real objects
[docs] def linkify_with_macromodulations(self, macromodulations):
for i in self:
if not hasattr(i, 'macromodulations'):
continue
new_macromodulations = []
for cw_name in i.macromodulations:
cw = macromodulations.find_by_name(cw_name)
if cw is not None:
new_macromodulations.append(cw)
else:
err = "The macromodulations of the %s '%s' named '%s' is unknown!" % (i.__class__.my_type, i.get_name(), cw_name)
i.configuration_errors.append(err)
# Get the list, but first make elements uniq
i.macromodulations = new_macromodulations
[docs] def evaluate_hostgroup_expression(self, expr, hosts, hostgroups, look_in='hostgroups'):
#print "\n"*10, "looking for expression", expr
if look_in=='hostgroups':
f = ComplexExpressionFactory(look_in, hostgroups, hosts)
else: # templates
f = ComplexExpressionFactory(look_in, hosts, hosts)
expr_tree = f.eval_cor_pattern(expr)
#print "RES of ComplexExpressionFactory"
#print expr_tree
#print "Try to resolve the Tree"
set_res = expr_tree.resolve_elements()
#print "R2d2 final is", set_res
# HOOK DBG
return list(set_res)
# If we've got a hostgroup_name property, we search for all
# theses groups and ask them their hosts, and then add them
# all into our host_name property
[docs] def explode_host_groups_into_hosts(self, hosts, hostgroups):
for i in self:
hnames_list = []
if hasattr(i, 'hostgroup_name'):
hnames_list.extend(self.evaluate_hostgroup_expression(i.hostgroup_name, hosts, hostgroups))
# Maybe there is no host in the groups, and do not have any
# host_name too, so tag is as template to do not look at
if hnames_list == [] and not hasattr(i, 'host_name'):
i.register = '0'
if hasattr(i, 'host_name'):
hst = i.host_name.split(',')
for h in hst:
h = h.strip()
# If the host start with a !, it's to be removed from
# the hostgroup get list
if h.startswith('!'):
hst_to_remove = h[1:].strip()
try:
hnames_list.remove(hst_to_remove)
# was not in it
except ValueError:
pass
# Else it's an host to add, but maybe it's ALL
elif h == '*':
for newhost in set(h.host_name for h in hosts.items.values() \
if getattr(h, 'host_name', '') != '' and not h.is_tpl()):
hnames_list.append(newhost)
#print "DBG in item.explode_host_groups_into_hosts , added '%s' to group '%s'" % (newhost, i)
else:
hnames_list.append(h)
i.host_name = ','.join(list(set(hnames_list)))
# Ok, even with all of it, there is still no host, put it as a template
if i.host_name == '':
i.register = '0'
# Take our trigger strings and create true objects with it
[docs] def explode_trigger_string_into_triggers(self, triggers):
for i in self:
i.explode_trigger_string_into_triggers(triggers)