Add : the full demoCA certification autority so people can sign their own keys.
[shinken.git] / shinken / escalation.py
blob6fb0b94fb39416a71863230b0affe6f5f413f04b
1 #!/usr/bin/env python
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 from shinken.item import Item, Items
22 from shinken.util import to_int, to_split, strip_and_uniq
23 from shinken.property import UnusedProp, BoolProp, IntegerProp, FloatProp, CharProp, StringProp, ListProp
24 from shinken.log import logger
26 class Escalation(Item):
27 id = 1 #0 is always special in database, so we do not take risk here
28 my_type = 'escalation'
30 properties={'escalation_name': StringProp(),
31 'first_notification': IntegerProp(),
32 'last_notification': IntegerProp(),
33 'first_notification_time': IntegerProp(),
34 'last_notification_time': IntegerProp(),
35 'notification_interval': IntegerProp(),
36 'escalation_period': StringProp(default=None),
37 'escalation_options': ListProp(default='d,u,r,w,c'),
38 'contacts': StringProp(),
39 'contact_groups': StringProp(),
41 running_properties = {
42 # All errors and warning raised during the configuration parsing
43 # and that will raised real warning/errors during the is_correct
44 'configuration_warnings': StringProp(default=[]),
45 'configuration_errors': StringProp(default=[]),
46 'time_based' : BoolProp(default=False),
49 macros = {}
52 # For debugging purpose only (nice name)
53 def get_name(self):
54 return self.escalation_name
57 # Return True if :
58 # *time in in escalation_period or we do not have escalation_period
59 # *status is in escalation_options
60 # *the notification number is in our interval [[first_notification .. last_notification]]
61 # if we are a classic escalation.
62 # *If we are time based, we check if the time that we were in notification
63 # is in our time interval
64 def is_eligible(self, t, status, notif_number, in_notif_time, interval):
65 small_states = {'WARNING' : 'w', 'UNKNOWN' : 'u', 'CRITICAL' : 'c',
66 'RECOVERY' : 'r', 'FLAPPING' : 'f', 'DOWNTIME' : 's',
67 'DOWN' : 'd', 'UNREACHABLE' : 'u', 'OK' : 'o', 'UP' : 'o'}
69 # If we are not time based, we check notification numbers:
70 if not self.time_based:
71 # Begin with the easy cases
72 if notif_number < self.first_notification:
73 return False
75 #self.last_notification = 0 mean no end
76 if self.last_notification != 0 and notif_number > self.last_notification:
77 return False
78 # Else we are time based, we must check for the good value
79 else:
80 # Begin with the easy cases
81 if in_notif_time < self.first_notification_time * interval:
82 return False
84 #self.last_notification = 0 mean no end
85 if self.last_notification_time != 0 and in_notif_time > self.last_notification_time * interval:
86 return False
88 # If our status is not good, we bail out too
89 if status in small_states and small_states[status] not in self.escalation_options:
90 return False
92 #Maybe the time is not in our escalation_period
93 if self.escalation_period != None and not self.escalation_period.is_time_valid(t):
94 return False
96 #Ok, I do not see why not escalade. So it's True :)
97 return True
100 # t = the reference time
101 def get_next_notif_time(self, t_wished, status, creation_time, interval):
102 small_states = {'WARNING' : 'w', 'UNKNOWN' : 'u', 'CRITICAL' : 'c',
103 'RECOVERY' : 'r', 'FLAPPING' : 'f', 'DOWNTIME' : 's',
104 'DOWN' : 'd', 'UNREACHABLE' : 'u', 'OK' : 'o', 'UP' : 'o'}
106 # If we are not time based, we bail out!
107 if not self.time_based:
108 return None
110 # Check if we are valid
111 if status in small_states and small_states[status] not in self.escalation_options:
112 return None
114 # Look for the min of our future validify
115 start = self.first_notification_time * interval + creation_time
117 # If we are after the classic next time, we are not asking for a smaller interval
118 if start > t_wished:
119 return None
121 # Maybe the time we found is not a valid one....
122 if self.escalation_period != None and not self.escalation_period.is_time_valid(start):
123 return None
125 # Ok so I ask for my start as a possibility for the next notification time
126 return start
131 # Check is required prop are set:
132 # template are always correct
133 # contacts OR contactgroups is need
134 def is_correct(self):
135 state = True # guilty or not? :)
136 cls = self.__class__
138 # If we got the _time parameters, we are time based. Unless, we are not :)
139 if hasattr(self, 'first_notification_time') or hasattr(self, 'last_notification_time'):
140 self.time_based = True
141 special_properties = ['contacts', 'contact_groups', 'first_notification', 'last_notification']
142 else: #classic ones
143 special_properties = ['contacts', 'contact_groups', 'first_notification_time', 'last_notification_time']
145 for prop in cls.properties:
146 if prop not in special_properties:
147 if not hasattr(self, prop) and cls.properties[prop].required:
148 logger.log('%s : I do not have %s' % (self.get_name(), prop))
149 state = False # Bad boy...
151 # Raised all previously saw errors like unknown contacts and co
152 if self.configuration_errors != []:
153 state = False
154 for err in self.configuration_errors:
155 logger.log(err)
157 # Ok now we manage special cases...
158 if not hasattr(self, 'contacts') and not hasattr(self, 'contact_groups'):
159 logger.log('%s : I do not have contacts nor contact_groups' % self.get_name())
160 state = False
162 # If time_based or not, we do not check all properties
163 if self.time_based:
164 if not hasattr(self, 'first_notification_time'):
165 logger.log('%s : I do not have first_notification_time' % self.get_name())
166 state = False
167 if not hasattr(self, 'last_notification_time'):
168 logger.log('%s : I do not have last_notification_time' % self.get_name())
169 state = False
170 else: # we check classical properties
171 if not hasattr(self, 'first_notification'):
172 logger.log('%s : I do not have first_notification' % self.get_name())
173 state = False
174 if not hasattr(self, 'last_notification'):
175 logger.log('%s : I do not have last_notification' % self.get_name())
176 state = False
178 return state
182 class Escalations(Items):
183 name_property = "escalation_name"
184 inner_class = Escalation
186 def linkify(self, timeperiods, contacts, services, hosts):
187 self.linkify_with_timeperiods(timeperiods, 'escalation_period')
188 self.linkify_with_contacts(contacts)
189 self.linkify_es_by_s(services)
190 self.linkify_es_by_h(hosts)
193 def add_escalation(self, es):
194 self.items[es.id] = es
197 #Will register esclations into service.escalations
198 def linkify_es_by_s(self, services):
199 for es in self:
200 #If no host, no hope of having a service
201 if not (hasattr(es, 'host_name') and hasattr(es, 'service_description')):
202 continue
203 es_hname, sdesc = es.host_name, es.service_description
204 if '' in (es_hname.strip(), sdesc.strip()):
205 continue
206 for hname in strip_and_uniq( es_hname.split(',') ):
207 for sname in strip_and_uniq( sdesc.split(',') ):
208 s = services.find_srv_by_name_and_hostname(hname, sname)
209 if s != None:
210 #print "Linking service", s.get_name(), 'with me', es.get_name()
211 s.escalations.append(es)
212 #print "Now service", s.get_name(), 'have', s.escalations
215 #Will rgister escalations into host.escalations
216 def linkify_es_by_h(self, hosts):
217 for es in self:
218 #If no host, no hope of having a service
219 if (not hasattr(es, 'host_name') or es.host_name.strip() == ''
220 or (hasattr(es, 'service_description') and es.service_description.strip() != '')):
221 continue
222 #I must be NOT a escalati on for service
223 for hname in strip_and_uniq(es.host_name.split(',')):
224 h = hosts.find_by_name(hname)
225 if h != None:
226 #print "Linking host", h.get_name(), 'with me', es.get_name()
227 h.escalations.append(es)
228 #print "Now host", h.get_name(), 'have', h.escalations
231 #We look for contacts property in contacts and
232 def explode(self, hosts, hostgroups, contactgroups):
234 #items::explode_host_groups_into_hosts
235 #take all hosts from our hostgroup_name into our host_name property
236 self.explode_host_groups_into_hosts(hosts, hostgroups)
238 #items::explode_contact_groups_into_contacts
239 #take all contacts from our contact_groups into our contact property
240 self.explode_contact_groups_into_contacts(contactgroups)