Fix : get back LiveStatus as default.
[shinken.git] / shinken / downtime.py
blobc17250355a8c72e0e0555e0362058c672eaf00f4
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/>.
24 import time
25 from shinken.comment import Comment
27 class Downtime:
28 id = 1
30 #Just to list the properties we will send as pickle
31 #so to others daemons, so all but NOT REF
32 properties = {
33 'activate_me': None,
34 'entry_time': None,
35 'fixed': None,
36 'start_time': None,
37 'duration': None,
38 'trigger_id': None,
39 'end_time': None,
40 'real_end_time': None,
41 'author': None,
42 'comment': None,
43 'is_in_effect': None,
44 'has_been_triggered': None,
45 'can_be_deleted': None,
46 # TODO: find a very good way to handle the downtime "ref"
47 # ref must effectively not be in properties because it points onto a real object.
48 # 'ref': None
52 #Schedules downtime for a specified service. If the "fixed" argument is set
53 #to one (1), downtime will start and end at the times specified by the
54 #"start" and "end" arguments.
55 #Otherwise, downtime will begin between the "start" and "end" times and last
56 #for "duration" seconds. The "start" and "end" arguments are specified
57 #in time_t format (seconds since the UNIX epoch). The specified service
58 #downtime can be triggered by another downtime entry if the "trigger_id"
59 #is set to the ID of another scheduled downtime entry.
60 #Set the "trigger_id" argument to zero (0) if the downtime for the
61 #specified service should not be triggered by another downtime entry.
62 def __init__(self, ref, start_time, end_time, fixed, trigger_id, duration, author, comment):
63 self.id = self.__class__.id
64 self.__class__.id += 1
65 self.ref = ref #pointer to srv or host we are apply
66 self.activate_me = [] #The other downtimes i need to activate
67 self.entry_time = int(time.time())
68 self.fixed = fixed
69 self.start_time = start_time
70 self.duration = duration
71 self.trigger_id = trigger_id
72 if self.trigger_id != 0: # triggered plus fixed makes no sense
73 self.fixed = False
74 self.end_time = end_time
75 if fixed:
76 self.duration = end_time - start_time
77 #This is important for flexible downtimes. Here start_time and
78 #end_time mean: in this time interval it is possible to trigger
79 #the beginning of the downtime which lasts for duration.
80 #Later, when a non-ok event happens, real_end_time will be
81 #recalculated from now+duration
82 #end_time will be displayed in the web interface, but real_end_time
83 #is used internally
84 self.real_end_time = end_time
85 self.author = author
86 self.comment = comment
87 self.is_in_effect = False # fixed: start_time has been reached, flexible: non-ok checkresult
88 self.has_been_triggered = False # another downtime has triggered me
89 self.can_be_deleted = False
90 self.add_automatic_comment()
93 def __str__(self):
94 if self.is_in_effect == True:
95 active = "active"
96 else:
97 active = "inactive"
98 if self.fixed == True:
99 type = "fixed"
100 else:
101 type = "flexible"
102 return "%s %s Downtime id=%d %s - %s" % (active, type, self.id, time.ctime(self.start_time), time.ctime(self.end_time))
105 def trigger_me(self, other_downtime):
106 self.activate_me.append(other_downtime)
109 def in_scheduled_downtime(self):
110 return self.is_in_effect
113 #The referenced host/service object enters now a (or another) scheduled
114 #downtime. Write a log message only if it was not already in a downtime
115 def enter(self):
116 res = []
117 self.is_in_effect = True
118 if self.fixed == False:
119 now = time.time()
120 self.real_end_time = now + self.duration
121 if self.ref.scheduled_downtime_depth == 0:
122 self.ref.raise_enter_downtime_log_entry()
123 self.ref.create_notifications('DOWNTIMESTART')
124 self.ref.scheduled_downtime_depth += 1
125 self.ref.in_scheduled_downtime = True
126 for dt in self.activate_me:
127 res.extend(dt.enter())
128 return res
131 #The end of the downtime was reached.
132 def exit(self):
133 res = []
134 if self.is_in_effect == True:
135 #This was a fixed or a flexible+triggered downtime
136 self.is_in_effect = False
137 self.ref.scheduled_downtime_depth -= 1
138 if self.ref.scheduled_downtime_depth == 0:
139 self.ref.raise_exit_downtime_log_entry()
140 self.ref.create_notifications('DOWNTIMEEND')
141 self.ref.in_scheduled_downtime = False
142 else:
143 #This was probably a flexible downtime which was not triggered
144 #In this case it silently disappears
145 pass
146 self.del_automatic_comment()
147 self.can_be_deleted = True
148 #when a downtime ends and the service was critical
149 #a notification is sent with the next critical check
150 #So we should set a flag here which signals consume_result
151 #to send a notification
152 self.ref.in_scheduled_downtime_during_last_check = True
153 return res
156 #A scheduled downtime was prematurely cancelled
157 def cancel(self):
158 res = []
159 self.is_in_effect = False
160 self.ref.scheduled_downtime_depth -= 1
161 if self.ref.scheduled_downtime_depth == 0:
162 self.ref.raise_cancel_downtime_log_entry()
163 self.ref.in_scheduled_downtime = False
164 self.del_automatic_comment()
165 self.can_be_deleted = True
166 self.ref.in_scheduled_downtime_during_last_check = True
167 #Nagios does not notify on cancelled downtimes
168 #res.extend(self.ref.create_notifications('DOWNTIMECANCELLED'))
169 #Also cancel other downtimes triggered by me
170 for dt in self.activate_me:
171 res.extend(dt.cancel())
172 return res
175 #Scheduling a downtime creates a comment automatically
176 def add_automatic_comment(self):
177 if self.fixed == True:
178 text = "This %s has been scheduled for fixed downtime from %s to %s. Notifications for the %s will not be sent out during that time period." % (self.ref.my_type, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.start_time)), time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.end_time)), self.ref.my_type)
179 else:
180 hours, remainder = divmod(self.duration, 3600)
181 minutes, seconds = divmod(remainder, 60)
182 text = "This %s has been scheduled for flexible downtime starting between %s and %s and lasting for a period of %d hours and %d minutes. Notifications for the %s will not be sent out during that time period." % (self.ref.my_type, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.start_time)), time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.end_time)), hours, minutes, self.ref.my_type)
183 if self.ref.my_type == 'host':
184 comment_type = 1
185 else:
186 comment_type = 2
187 c = Comment(self.ref, False, "(Nagios Process)", text, comment_type, 2, 0, False, 0)
188 self.comment_id = c.id
189 self.extra_comment = c
190 self.ref.add_comment(c)
193 def del_automatic_comment(self):
194 # Extra comment can be None if we load it from a old version of Shinken
195 # TODO : remove it in a future verszion when every oen got upgrade
196 if self.extra_comment is not None:
197 self.extra_comment.can_be_deleted = True
198 #self.ref.del_comment(self.comment_id)
202 #Call by picle for dataify the downtime
203 #because we DO NOT WANT REF in this pickleisation!
204 def __getstate__(self):
205 cls = self.__class__
206 # id is not in *_properties
207 res = { 'id' : self.id }
208 for prop in cls.properties:
209 if hasattr(self, prop):
210 res[prop] = getattr(self, prop)
211 return res
214 #Inversed funtion of getstate
215 def __setstate__(self, state):
216 cls = self.__class__
218 # Maybe it's not a dict but a list like in the old 0.4 format
219 # so we should call the 0.4 function for it
220 if isinstance(state, list):
221 self.__setstate_deprecated__(state)
222 return
224 self.id = state['id']
225 for prop in cls.properties:
226 if prop in state:
227 setattr(self, prop, state[prop])
229 if self.id >= cls.id:
230 cls.id = self.id + 1
232 # Theses 2 functions are DEPRECATED and will be removed in a future version of
233 # Shinken. They should not be useful any more after a first load/save pass.
235 #Inversed funtion of getstate
236 def __setstate_deprecated__(self, state):
237 cls = self.__class__
238 #Check if the len of this state is like the previous,
239 # if not, we will do errors!
240 # -1 because of the 'id' prop
241 if len(cls.properties) != (len(state) - 1):
242 print "Passing downtime"
243 return
245 self.id = state.pop()
246 for prop in cls.properties:
247 val = state.pop()
248 setattr(self, prop, val)
249 if self.id >= cls.id:
250 cls.id = self.id + 1