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
7 #This file is part of Shinken.
9 #Shinken is free software: you can redistribute it and/or modify
10 #it under the terms of the GNU Affero General Public License as published by
11 #the Free Software Foundation, either version 3 of the License, or
12 #(at your option) any later version.
14 #Shinken is distributed in the hope that it will be useful,
15 #but WITHOUT ANY WARRANTY; without even the implied warranty of
16 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 #GNU Affero General Public License for more details.
19 #You should have received a copy of the GNU Affero General Public License
20 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
24 from comment
import Comment
29 #Just to list the properties we will send as pickle
30 #so to others daemons, so all but NOT REF
39 'real_end_time' : None,
42 'is_in_effect' : None,
43 'has_been_triggered' : None,
44 'can_be_deleted' : None,
48 #Schedules downtime for a specified service. If the "fixed" argument is set
49 #to one (1), downtime will start and end at the times specified by the
50 #"start" and "end" arguments.
51 #Otherwise, downtime will begin between the "start" and "end" times and last
52 #for "duration" seconds. The "start" and "end" arguments are specified
53 #in time_t format (seconds since the UNIX epoch). The specified service
54 #downtime can be triggered by another downtime entry if the "trigger_id"
55 #is set to the ID of another scheduled downtime entry.
56 #Set the "trigger_id" argument to zero (0) if the downtime for the
57 #specified service should not be triggered by another downtime entry.
58 def __init__(self
, ref
, start_time
, end_time
, fixed
, trigger_id
, duration
, author
, comment
):
59 self
.id = self
.__class
__.id
60 self
.__class
__.id += 1
61 self
.ref
= ref
#pointer to srv or host we are apply
62 self
.activate_me
= [] #The other downtimes i need to activate
63 self
.entry_time
= int(time
.time())
65 self
.start_time
= start_time
66 self
.duration
= duration
67 self
.trigger_id
= trigger_id
68 if self
.trigger_id
!= 0: # triggered plus fixed makes no sense
70 self
.end_time
= end_time
72 self
.duration
= end_time
- start_time
73 #This is important for flexible downtimes. Here start_time and
74 #end_time mean: in this time interval it is possible to trigger
75 #the beginning of the downtime which lasts for duration.
76 #Later, when a non-ok event happens, real_end_time will be
77 #recalculated from now+duration
78 #end_time will be displayed in the web interface, but real_end_time
80 self
.real_end_time
= end_time
82 self
.comment
= comment
83 self
.is_in_effect
= False # fixed: start_time has been reached, flexible: non-ok checkresult
84 self
.has_been_triggered
= False # another downtime has triggered me
85 self
.can_be_deleted
= False
86 self
.add_automatic_comment()
90 if self
.is_in_effect
== True:
94 if self
.fixed
== True:
98 return "%s %s Downtime id=%d %s - %s" % (active
, type, self
.id, time
.ctime(self
.start_time
), time
.ctime(self
.end_time
))
101 def trigger_me(self
, other_downtime
):
102 self
.activate_me
.append(other_downtime
)
105 def in_scheduled_downtime(self
):
106 return self
.is_in_effect
109 #The referenced host/service object enters now a (or another) scheduled
110 #downtime. Write a log message only if it was not already in a downtime
113 self
.is_in_effect
= True
114 if self
.fixed
== False:
116 self
.real_end_time
= now
+ self
.duration
117 if self
.ref
.scheduled_downtime_depth
== 0:
118 self
.ref
.raise_enter_downtime_log_entry()
119 self
.ref
.create_notifications('DOWNTIMESTART')
120 self
.ref
.scheduled_downtime_depth
+= 1
121 self
.ref
.in_scheduled_downtime
= True
122 for dt
in self
.activate_me
:
123 res
.extend(dt
.enter())
127 #The end of the downtime was reached.
130 if self
.is_in_effect
== True:
131 #This was a fixed or a flexible+triggered downtime
132 self
.is_in_effect
= False
133 self
.ref
.scheduled_downtime_depth
-= 1
134 if self
.ref
.scheduled_downtime_depth
== 0:
135 self
.ref
.raise_exit_downtime_log_entry()
136 self
.ref
.create_notifications('DOWNTIMEEND')
137 self
.ref
.in_scheduled_downtime
= False
139 #This was probably a flexible downtime which was not triggered
140 #In this case it silently disappears
142 self
.del_automatic_comment()
143 self
.can_be_deleted
= True
144 #when a downtime ends and the service was critical
145 #a notification is sent with the next critical check
146 #So we should set a flag here which signals consume_result
147 #to send a notification
148 self
.ref
.in_scheduled_downtime_during_last_check
= True
152 #A scheduled downtime was prematurely cancelled
155 self
.is_in_effect
= False
156 self
.ref
.scheduled_downtime_depth
-= 1
157 if self
.ref
.scheduled_downtime_depth
== 0:
158 self
.ref
.raise_cancel_downtime_log_entry()
159 self
.ref
.in_scheduled_downtime
= False
160 self
.del_automatic_comment()
161 self
.can_be_deleted
= True
162 self
.ref
.in_scheduled_downtime_during_last_check
= True
163 #Nagios does not notify on cancelled downtimes
164 #res.extend(self.ref.create_notifications('DOWNTIMECANCELLED'))
165 #Also cancel other downtimes triggered by me
166 for dt
in self
.activate_me
:
167 res
.extend(dt
.cancel())
171 #Scheduling a downtime creates a comment automatically
172 def add_automatic_comment(self
):
173 if self
.fixed
== True:
174 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
)
176 hours
, remainder
= divmod(self
.duration
, 3600)
177 minutes
, seconds
= divmod(remainder
, 60)
178 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
)
179 if self
.ref
.my_type
== 'host':
183 c
= Comment(self
.ref
, False, "(Nagios Process)", text
, comment_type
, 2, 0, False, 0)
184 self
.comment_id
= c
.id
185 self
.extra_comment
= c
186 self
.ref
.add_comment(c
)
189 def del_automatic_comment(self
):
190 # Extra comment can be None if we load it from a old version of Shinken
191 # TODO : remove it in a future verszion when every oen got upgrade
192 if self
.extra_comment
!= None:
193 self
.extra_comment
.can_be_deleted
= True
194 #self.ref.del_comment(self.comment_id)
198 #Call by picle for dataify the downtime
199 #because we DO NOT WANT REF in this pickleisation!
200 def __getstate__(self
):
202 # id is not in *_properties
203 res
= {'id' : self
.id}
204 for prop
in cls
.properties
:
205 if hasattr(self
, prop
):
206 res
[prop
] = getattr(self
, prop
)
210 #Inversed funtion of getstate
211 def __setstate__(self
, state
):
214 # Maybe it's not a dict but a list like in the old 0.4 format
215 # so we should call the 0.4 function for it
216 if isinstance(state
, list):
217 self
.__setstate
_deprecated
__(state
)
220 self
.id = state
['id']
221 for prop
in cls
.properties
:
223 setattr(self
, prop
, state
[prop
])
226 # Theses 2 functions are DEPRECATED and will be removed in a future version of
227 # Shinken. They should not be useful any more after a first load/save pass.
229 #Inversed funtion of getstate
230 def __setstate_deprecated__(self
, state
):
232 #Check if the len of this state is like the previous,
233 # if not, we will do errors!
234 # -1 because of the 'id' prop
235 if len(cls
.properties
) != (len(state
) - 1):
236 print "Passing downtime"
239 self
.id = state
.pop()
240 for prop
in cls
.properties
:
242 setattr(self
, prop
, val
)