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'
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),
62 # For debugging purpose only (nice name)
64 return self
.escalation_name
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
):
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
:
87 #self.last_notification = 0 mean no end
88 if self
.last_notification
!= 0 and notif_number
> self
.last_notification
:
90 # Else we are time based, we must check for the good value
92 # Begin with the easy cases
93 if in_notif_time
< self
.first_notification_time
* interval
:
96 #self.last_notification = 0 mean no end
97 if self
.last_notification_time
!= 0 and in_notif_time
> self
.last_notification_time
* interval
:
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
:
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
):
108 #Ok, I do not see why not escalade. So it's 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
:
122 # Check if we are valid
123 if status
in small_states
and small_states
[status
] not in self
.escalation_options
:
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
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
):
137 # Ok so I ask for my start as a possibility for the next notification time
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? :)
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
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
!= []:
164 for err
in self
.configuration_errors
:
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())
172 # If time_based or not, we do not check all properties
174 if not hasattr(self
, 'first_notification_time'):
175 logger
.log('%s : I do not have first_notification_time' % self
.get_name())
177 if not hasattr(self
, 'last_notification_time'):
178 logger
.log('%s : I do not have last_notification_time' % self
.get_name())
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())
184 if not hasattr(self
, 'last_notification'):
185 logger
.log('%s : I do not have last_notification' % self
.get_name())
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
):
210 #If no host, no hope of having a service
211 if not (hasattr(es
, 'host_name') and hasattr(es
, 'service_description')):
213 es_hname
, sdesc
= es
.host_name
, es
.service_description
214 if '' in (es_hname
.strip(), sdesc
.strip()):
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
)
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
):
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() != '')):
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
)
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
)