Fix : get back LiveStatus as default.
[shinken.git] / shinken / objects / escalation.py
blobe622aa6f1e4b4c4795f13f597820e65af4330171
1 #!/usr/bin/env python
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/>.
23 from shinken.objects.item import Item, Items
25 from shinken.util import strip_and_uniq
26 from shinken.property import BoolProp, IntegerProp, StringProp, ListProp
27 from shinken.log import logger
30 _special_properties = ( 'contacts', 'contact_groups', 'first_notification_time', 'last_notification_time' )
31 _special_properties_time_based = ( 'contacts', 'contact_groups', 'first_notification', 'last_notification' )
34 class Escalation(Item):
35 id = 1 #0 is always special in database, so we do not take risk here
36 my_type = 'escalation'
38 properties = {
39 'escalation_name': StringProp(),
40 'first_notification': IntegerProp(),
41 'last_notification': IntegerProp(),
42 'first_notification_time': IntegerProp(),
43 'last_notification_time': IntegerProp(),
44 'notification_interval': IntegerProp(),
45 'escalation_period': StringProp(default=None),
46 'escalation_options': ListProp(default='d,u,r,w,c'),
47 'contacts': StringProp(),
48 'contact_groups': StringProp(),
51 running_properties = {
52 # All errors and warning raised during the configuration parsing
53 # and that will raised real warning/errors during the is_correct
54 'configuration_warnings': StringProp(default=[]),
55 'configuration_errors': StringProp(default=[]),
56 'time_based': BoolProp(default=False),
59 macros = {}
62 # For debugging purpose only (nice name)
63 def get_name(self):
64 return self.escalation_name
67 # Return True if :
68 # *time in in escalation_period or we do not have escalation_period
69 # *status is in escalation_options
70 # *the notification number is in our interval [[first_notification .. last_notification]]
71 # if we are a classic escalation.
72 # *If we are time based, we check if the time that we were in notification
73 # is in our time interval
74 def is_eligible(self, t, status, notif_number, in_notif_time, interval):
75 small_states = {
76 'WARNING' : 'w', 'UNKNOWN' : 'u', 'CRITICAL' : 'c',
77 'RECOVERY' : 'r', 'FLAPPING' : 'f', 'DOWNTIME' : 's',
78 'DOWN' : 'd', 'UNREACHABLE' : 'u', 'OK' : 'o', 'UP' : 'o'
81 # If we are not time based, we check notification numbers:
82 if not self.time_based:
83 # Begin with the easy cases
84 if notif_number < self.first_notification:
85 return False
87 #self.last_notification = 0 mean no end
88 if self.last_notification != 0 and notif_number > self.last_notification:
89 return False
90 # Else we are time based, we must check for the good value
91 else:
92 # Begin with the easy cases
93 if in_notif_time < self.first_notification_time * interval:
94 return False
96 #self.last_notification = 0 mean no end
97 if self.last_notification_time != 0 and in_notif_time > self.last_notification_time * interval:
98 return False
100 # If our status is not good, we bail out too
101 if status in small_states and small_states[status] not in self.escalation_options:
102 return False
104 #Maybe the time is not in our escalation_period
105 if self.escalation_period is not None and not self.escalation_period.is_time_valid(t):
106 return False
108 #Ok, I do not see why not escalade. So it's True :)
109 return True
112 # t = the reference time
113 def get_next_notif_time(self, t_wished, status, creation_time, interval):
114 small_states = {'WARNING' : 'w', 'UNKNOWN' : 'u', 'CRITICAL' : 'c',
115 'RECOVERY' : 'r', 'FLAPPING' : 'f', 'DOWNTIME' : 's',
116 'DOWN' : 'd', 'UNREACHABLE' : 'u', 'OK' : 'o', 'UP' : 'o'}
118 # If we are not time based, we bail out!
119 if not self.time_based:
120 return None
122 # Check if we are valid
123 if status in small_states and small_states[status] not in self.escalation_options:
124 return None
126 # Look for the min of our future validify
127 start = self.first_notification_time * interval + creation_time
129 # If we are after the classic next time, we are not asking for a smaller interval
130 if start > t_wished:
131 return None
133 # Maybe the time we found is not a valid one....
134 if self.escalation_period is not None and not self.escalation_period.is_time_valid(start):
135 return None
137 # Ok so I ask for my start as a possibility for the next notification time
138 return start
141 # Check is required prop are set:
142 # template are always correct
143 # contacts OR contactgroups is need
144 def is_correct(self):
145 state = True # guilty or not? :)
146 cls = self.__class__
148 # If we got the _time parameters, we are time based. Unless, we are not :)
149 if hasattr(self, 'first_notification_time') or hasattr(self, 'last_notification_time'):
150 self.time_based = True
151 special_properties = _special_properties_time_based
152 else: #classic ones
153 special_properties = _special_properties
155 for prop, entry in cls.properties.items():
156 if prop not in special_properties:
157 if not hasattr(self, prop) and entry.required:
158 logger.log('%s : I do not have %s' % (self.get_name(), prop))
159 state = False # Bad boy...
161 # Raised all previously saw errors like unknown contacts and co
162 if self.configuration_errors != []:
163 state = False
164 for err in self.configuration_errors:
165 logger.log(err)
167 # Ok now we manage special cases...
168 if not hasattr(self, 'contacts') and not hasattr(self, 'contact_groups'):
169 logger.log('%s : I do not have contacts nor contact_groups' % self.get_name())
170 state = False
172 # If time_based or not, we do not check all properties
173 if self.time_based:
174 if not hasattr(self, 'first_notification_time'):
175 logger.log('%s : I do not have first_notification_time' % self.get_name())
176 state = False
177 if not hasattr(self, 'last_notification_time'):
178 logger.log('%s : I do not have last_notification_time' % self.get_name())
179 state = False
180 else: # we check classical properties
181 if not hasattr(self, 'first_notification'):
182 logger.log('%s : I do not have first_notification' % self.get_name())
183 state = False
184 if not hasattr(self, 'last_notification'):
185 logger.log('%s : I do not have last_notification' % self.get_name())
186 state = False
188 return state
192 class Escalations(Items):
193 name_property = "escalation_name"
194 inner_class = Escalation
196 def linkify(self, timeperiods, contacts, services, hosts):
197 self.linkify_with_timeperiods(timeperiods, 'escalation_period')
198 self.linkify_with_contacts(contacts)
199 self.linkify_es_by_s(services)
200 self.linkify_es_by_h(hosts)
203 def add_escalation(self, es):
204 self.items[es.id] = es
207 #Will register esclations into service.escalations
208 def linkify_es_by_s(self, services):
209 for es in self:
210 #If no host, no hope of having a service
211 if not (hasattr(es, 'host_name') and hasattr(es, 'service_description')):
212 continue
213 es_hname, sdesc = es.host_name, es.service_description
214 if '' in (es_hname.strip(), sdesc.strip()):
215 continue
216 for hname in strip_and_uniq( es_hname.split(',') ):
217 for sname in strip_and_uniq( sdesc.split(',') ):
218 s = services.find_srv_by_name_and_hostname(hname, sname)
219 if s is not None:
220 #print "Linking service", s.get_name(), 'with me', es.get_name()
221 s.escalations.append(es)
222 #print "Now service", s.get_name(), 'have', s.escalations
225 #Will rgister escalations into host.escalations
226 def linkify_es_by_h(self, hosts):
227 for es in self:
228 #If no host, no hope of having a service
229 if (not hasattr(es, 'host_name') or es.host_name.strip() == ''
230 or (hasattr(es, 'service_description') and es.service_description.strip() != '')):
231 continue
232 #I must be NOT a escalati on for service
233 for hname in strip_and_uniq(es.host_name.split(',')):
234 h = hosts.find_by_name(hname)
235 if h is not None:
236 #print "Linking host", h.get_name(), 'with me', es.get_name()
237 h.escalations.append(es)
238 #print "Now host", h.get_name(), 'have', h.escalations
241 #We look for contacts property in contacts and
242 def explode(self, hosts, hostgroups, contactgroups):
244 #items::explode_host_groups_into_hosts
245 #take all hosts from our hostgroup_name into our host_name property
246 self.explode_host_groups_into_hosts(hosts, hostgroups)
248 #items::explode_contact_groups_into_contacts
249 #take all contacts from our contact_groups into our contact property
250 self.explode_contact_groups_into_contacts(contactgroups)