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/>.
25 from shinken
.comment
import Comment
30 #Just to list the properties we will send as pickle
31 #so to others daemons, so all but NOT REF
40 'real_end_time': 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.
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())
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
74 self
.end_time
= end_time
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
84 self
.real_end_time
= end_time
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()
94 if self
.is_in_effect
== True:
98 if self
.fixed
== True:
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
117 self
.is_in_effect
= True
118 if self
.fixed
== False:
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())
131 #The end of the downtime was reached.
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
143 #This was probably a flexible downtime which was not triggered
144 #In this case it silently disappears
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
156 #A scheduled downtime was prematurely cancelled
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())
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
)
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':
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
):
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
)
214 #Inversed funtion of getstate
215 def __setstate__(self
, state
):
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
)
224 self
.id = state
['id']
225 for prop
in cls
.properties
:
227 setattr(self
, prop
, state
[prop
])
229 if self
.id >= cls
.id:
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
):
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"
245 self
.id = state
.pop()
246 for prop
in cls
.properties
:
248 setattr(self
, prop
, val
)
249 if self
.id >= cls
.id: