]> granicus.if.org Git - icinga2/blob - lib/icinga/service.cpp
compatlog: refactor custom/acknowledgement notifications with author/commenttext
[icinga2] / lib / icinga / service.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/)        *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "icinga/service.h"
21 #include "icinga/servicegroup.h"
22 #include "icinga/checkcommand.h"
23 #include "icinga/icingaapplication.h"
24 #include "icinga/macroprocessor.h"
25 #include "config/configitembuilder.h"
26 #include "base/dynamictype.h"
27 #include "base/objectlock.h"
28 #include "base/convert.h"
29 #include "base/utility.h"
30 #include <boost/smart_ptr/make_shared.hpp>
31 #include <boost/foreach.hpp>
32
33 using namespace icinga;
34
35 REGISTER_TYPE(Service);
36
37 Service::Service(const Dictionary::Ptr& serializedObject)
38         : DynamicObject(serializedObject), m_CheckRunning(false)
39 {
40
41         RegisterAttribute("display_name", Attribute_Config, &m_DisplayName);
42         RegisterAttribute("macros", Attribute_Config, &m_Macros);
43         RegisterAttribute("hostdependencies", Attribute_Config, &m_HostDependencies);
44         RegisterAttribute("servicedependencies", Attribute_Config, &m_ServiceDependencies);
45         RegisterAttribute("servicegroups", Attribute_Config, &m_ServiceGroups);
46
47         RegisterAttribute("check_command", Attribute_Config, &m_CheckCommand);
48         RegisterAttribute("max_check_attempts", Attribute_Config, &m_MaxCheckAttempts);
49         RegisterAttribute("check_period", Attribute_Config, &m_CheckPeriod);
50         RegisterAttribute("check_interval", Attribute_Config, &m_CheckInterval);
51         RegisterAttribute("retry_interval", Attribute_Config, &m_RetryInterval);
52         RegisterAttribute("checkers", Attribute_Config, &m_Checkers);
53
54         RegisterAttribute("event_command", Attribute_Config, &m_EventCommand);
55         RegisterAttribute("volatile", Attribute_Config, &m_Volatile);
56
57         RegisterAttribute("next_check", Attribute_Replicated, &m_NextCheck);
58         RegisterAttribute("current_checker", Attribute_Replicated, &m_CurrentChecker);
59         RegisterAttribute("check_attempt", Attribute_Replicated, &m_CheckAttempt);
60         RegisterAttribute("state", Attribute_Replicated, &m_State);
61         RegisterAttribute("state_type", Attribute_Replicated, &m_StateType);
62         RegisterAttribute("last_state", Attribute_Replicated, &m_LastState);
63         RegisterAttribute("last_state_type", Attribute_Replicated, &m_LastStateType);
64         RegisterAttribute("last_reachable", Attribute_Replicated, &m_LastReachable);
65         RegisterAttribute("last_result", Attribute_Replicated, &m_LastResult);
66         RegisterAttribute("last_state_change", Attribute_Replicated, &m_LastStateChange);
67         RegisterAttribute("last_hard_state_change", Attribute_Replicated, &m_LastHardStateChange);
68         RegisterAttribute("last_in_downtime", Attribute_Replicated, &m_LastInDowntime);
69         RegisterAttribute("enable_active_checks", Attribute_Replicated, &m_EnableActiveChecks);
70         RegisterAttribute("enable_passive_checks", Attribute_Replicated, &m_EnablePassiveChecks);
71         RegisterAttribute("force_next_check", Attribute_Replicated, &m_ForceNextCheck);
72
73         RegisterAttribute("short_name", Attribute_Config, &m_ShortName);
74         RegisterAttribute("host_name", Attribute_Config, &m_HostName);
75
76         RegisterAttribute("acknowledgement", Attribute_Replicated, &m_Acknowledgement);
77         RegisterAttribute("acknowledgement_expiry", Attribute_Replicated, &m_AcknowledgementExpiry);
78
79         RegisterAttribute("comments", Attribute_Replicated, &m_Comments);
80
81         RegisterAttribute("downtimes", Attribute_Replicated, &m_Downtimes);
82
83         RegisterAttribute("enable_notifications", Attribute_Replicated, &m_EnableNotifications);
84         RegisterAttribute("force_next_notification", Attribute_Replicated, &m_ForceNextNotification);
85
86         RegisterAttribute("flapping_positive", Attribute_Replicated, &m_FlappingPositive);
87         RegisterAttribute("flapping_negative", Attribute_Replicated, &m_FlappingNegative);
88         RegisterAttribute("flapping_lastchange", Attribute_Replicated, &m_FlappingLastChange);
89         RegisterAttribute("flapping_threshold", Attribute_Config, &m_FlappingThreshold);
90         RegisterAttribute("enable_flapping", Attribute_Config, &m_EnableFlapping);
91
92         SetSchedulingOffset(rand());
93 }
94
95 Service::~Service(void)
96 {
97         ServiceGroup::InvalidateMembersCache();
98         Host::InvalidateServicesCache();
99         Service::InvalidateDowntimesCache();
100         Service::InvalidateCommentsCache();
101 }
102
103 void Service::OnRegistrationCompleted(void)
104 {
105         ASSERT(!OwnsLock());
106
107         DynamicObject::OnRegistrationCompleted();
108
109         InvalidateNotificationsCache();
110 }
111
112 String Service::GetDisplayName(void) const
113 {
114         if (m_DisplayName.IsEmpty())
115                 return GetShortName();
116         else
117                 return m_DisplayName;
118 }
119
120 Service::Ptr Service::GetByName(const String& name)
121 {
122         DynamicObject::Ptr configObject = DynamicObject::GetObject("Service", name);
123
124         return dynamic_pointer_cast<Service>(configObject);
125 }
126
127 Service::Ptr Service::GetByNamePair(const String& hostName, const String& serviceName)
128 {
129         if (!hostName.IsEmpty()) {
130                 Host::Ptr host = Host::GetByName(hostName);
131
132                 if (!host)
133                         return Service::Ptr();
134
135                 return host->GetServiceByShortName(serviceName);
136         } else {
137                 return Service::GetByName(serviceName);
138         }
139 }
140
141 Host::Ptr Service::GetHost(void) const
142 {
143         return Host::GetByName(m_HostName);
144 }
145
146 Dictionary::Ptr Service::GetMacros(void) const
147 {
148         return m_Macros;
149 }
150
151 Array::Ptr Service::GetHostDependencies(void) const
152 {
153         return m_HostDependencies;
154 }
155
156 Array::Ptr Service::GetServiceDependencies(void) const
157 {
158         return m_ServiceDependencies;
159 }
160
161 Array::Ptr Service::GetGroups(void) const
162 {
163         return m_ServiceGroups;
164 }
165
166 String Service::GetHostName(void) const
167 {
168         return m_HostName;
169 }
170
171 String Service::GetShortName(void) const
172 {
173         if (m_ShortName.IsEmpty())
174                 return GetName();
175         else
176                 return m_ShortName;
177 }
178
179 bool Service::IsReachable(void) const
180 {
181         ASSERT(!OwnsLock());
182
183         BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
184                 /* ignore ourselves */
185                 if (service->GetName() == GetName())
186                         continue;
187
188                 ObjectLock olock(service);
189
190                 /* ignore pending services */
191                 if (!service->GetLastCheckResult())
192                         continue;
193
194                 /* ignore soft states */
195                 if (service->GetStateType() == StateTypeSoft)
196                         continue;
197
198                 /* ignore services states OK and Warning */
199                 if (service->GetState() == StateOK ||
200                     service->GetState() == StateWarning)
201                         continue;
202
203                 return false;
204         }
205
206         BOOST_FOREACH(const Host::Ptr& host, GetParentHosts()) {
207                 Service::Ptr hc = host->GetHostCheckService();
208
209                 /* ignore hosts that don't have a hostcheck */
210                 if (!hc)
211                         continue;
212
213                 /* ignore ourselves */
214                 if (hc->GetName() == GetName())
215                         continue;
216
217                 ObjectLock olock(hc);
218
219                 /* ignore soft states */
220                 if (hc->GetStateType() == StateTypeSoft)
221                         continue;
222
223                 /* ignore hosts that are up */
224                 if (hc->GetState() == StateOK)
225                         continue;
226
227                 return false;
228         }
229
230         return true;
231 }
232
233 bool Service::IsVolatile(void) const
234 {
235         if (m_Volatile.IsEmpty())
236                 return false;
237
238         return m_Volatile;
239 }
240
241 AcknowledgementType Service::GetAcknowledgement(void)
242 {
243         ASSERT(OwnsLock());
244
245         if (m_Acknowledgement.IsEmpty())
246                 return AcknowledgementNone;
247
248         int ivalue = static_cast<int>(m_Acknowledgement);
249         AcknowledgementType avalue = static_cast<AcknowledgementType>(ivalue);
250
251         if (avalue != AcknowledgementNone) {
252                 double expiry = GetAcknowledgementExpiry();
253
254                 if (expiry != 0 && expiry < Utility::GetTime()) {
255                         avalue = AcknowledgementNone;
256                         SetAcknowledgement(avalue);
257                         SetAcknowledgementExpiry(0);
258                 }
259         }
260
261         return avalue;
262 }
263
264 void Service::SetAcknowledgement(AcknowledgementType acknowledgement)
265 {
266         m_Acknowledgement = acknowledgement;
267         Touch("acknowledgement");
268 }
269
270 bool Service::IsAcknowledged(void)
271 {
272         return GetAcknowledgement() != AcknowledgementNone;
273 }
274
275 double Service::GetAcknowledgementExpiry(void) const
276 {
277         if (m_AcknowledgementExpiry.IsEmpty())
278                 return 0;
279
280         return static_cast<double>(m_AcknowledgementExpiry);
281 }
282
283 void Service::SetAcknowledgementExpiry(double timestamp)
284 {
285         m_AcknowledgementExpiry = timestamp;
286         Touch("acknowledgement_expiry");
287 }
288
289 void Service::AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, double expiry)
290 {
291         {
292                 ObjectLock olock(this);
293
294                 SetAcknowledgement(type);
295                 SetAcknowledgementExpiry(expiry);
296         }
297
298         (void) AddComment(CommentAcknowledgement, author, comment, 0);
299
300         RequestNotifications(NotificationAcknowledgement, GetLastCheckResult(), author, comment);
301 }
302
303 void Service::ClearAcknowledgement(void)
304 {
305         ObjectLock olock(this);
306
307         SetAcknowledgement(AcknowledgementNone);
308         SetAcknowledgementExpiry(0);
309 }
310
311 void Service::OnAttributeChanged(const String& name)
312 {
313         ASSERT(!OwnsLock());
314
315         Service::Ptr self = GetSelf();
316
317         if (name == "current_checker")
318                 OnCheckerChanged(self);
319         else if (name == "next_check")
320                 OnNextCheckChanged(self);
321         else if (name == "servicegroups")
322                 ServiceGroup::InvalidateMembersCache();
323         else if (name == "host_name" || name == "short_name") {
324                 Host::InvalidateServicesCache();
325
326                 UpdateSlaveNotifications();
327         } else if (name == "downtimes")
328                 Service::InvalidateDowntimesCache();
329         else if (name == "comments")
330                 Service::InvalidateCommentsCache();
331         else if (name == "notifications")
332                 UpdateSlaveNotifications();
333         else if (name == "check_interval") {
334                 ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName());
335
336                 /* update the next check timestamp if we're the owner of this service */
337                 if (item)
338                         UpdateNextCheck();
339         }
340 }
341
342 std::set<Host::Ptr> Service::GetParentHosts(void) const
343 {
344         std::set<Host::Ptr> parents;
345
346         Host::Ptr host = GetHost();
347
348         /* The service's host is implicitly a parent. */
349         if (host)
350                 parents.insert(host);
351
352         Array::Ptr dependencies = GetHostDependencies();
353
354         if (dependencies) {
355                 ObjectLock olock(dependencies);
356
357                 BOOST_FOREACH(const Value& dependency, dependencies) {
358                         Host::Ptr host = Host::GetByName(dependency);
359
360                         if (!host)
361                                 continue;
362
363                         parents.insert(host);
364                 }
365         }
366
367         return parents;
368 }
369
370 std::set<Service::Ptr> Service::GetParentServices(void) const
371 {
372         std::set<Service::Ptr> parents;
373
374         Host::Ptr host = GetHost();
375         Array::Ptr dependencies = GetServiceDependencies();
376
377         if (host && dependencies) {
378                 ObjectLock olock(dependencies);
379
380                 BOOST_FOREACH(const Value& dependency, dependencies) {
381                         Service::Ptr service = host->GetServiceByShortName(dependency);
382
383                         if (!service)
384                                 continue;
385
386                         if (service->GetName() == GetName())
387                                 continue;
388
389                         parents.insert(service);
390                 }
391         }
392
393         return parents;
394 }
395
396 bool Service::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const
397 {
398         if (macro == "SERVICEDESC") {
399                 *result = GetShortName();
400                 return true;
401         } else if (macro == "SERVICEDISPLAYNAME") {
402                 *result = GetDisplayName();
403                 return true;
404         } else if (macro == "SERVICECHECKCOMMAND") {
405                 CheckCommand::Ptr commandObj = GetCheckCommand();
406
407                 if (commandObj)
408                         *result = commandObj->GetName();
409                 else
410                         *result = "";
411
412                 return true;
413         }
414
415         if (macro == "SERVICESTATE") {
416                 *result = StateToString(GetState());
417                 return true;
418         } else if (macro == "SERVICESTATEID") {
419                 *result = Convert::ToString(GetState());
420                 return true;
421         } else if (macro == "SERVICESTATETYPE") {
422                 *result = StateTypeToString(GetStateType());
423                 return true;
424         } else if (macro == "SERVICEATTEMPT") {
425                 *result = Convert::ToString(GetCurrentCheckAttempt());
426                 return true;
427         } else if (macro == "MAXSERVICEATTEMPT") {
428                 *result = Convert::ToString(GetMaxCheckAttempts());
429                 return true;
430         } else if (macro == "LASTSERVICESTATE") {
431                 *result = StateToString(GetLastState());
432                 return true;
433         } else if (macro == "LASTSERVICESTATEID") {
434                 *result = Convert::ToString(GetLastState());
435                 return true;
436         } else if (macro == "LASTSERVICESTATETYPE") {
437                 *result = StateTypeToString(GetLastStateType());
438                 return true;
439         } else if (macro == "LASTSERVICESTATECHANGE") {
440                 *result = Convert::ToString((long)GetLastStateChange());
441                 return true;
442         }
443
444         if (cr) {
445                 if (macro == "SERVICELATENCY") {
446                         *result = Convert::ToString(Service::CalculateLatency(cr));
447                         return true;
448                 } else if (macro == "SERVICEEXECUTIONTIME") {
449                         *result = Convert::ToString(Service::CalculateExecutionTime(cr));
450                         return true;
451                 } else if (macro == "SERVICEOUTPUT") {
452                         *result = cr->Get("output");
453                         return true;
454                 } else if (macro == "SERVICEPERFDATA") {
455                         *result = cr->Get("performance_data_raw");
456                         return true;
457                 } else if (macro == "LASTSERVICECHECK") {
458                         *result = Convert::ToString((long)cr->Get("execution_end"));
459                         return true;
460                 }
461         }
462
463         Dictionary::Ptr macros = GetMacros();
464
465         if (macros && macros->Contains(macro)) {
466                 *result = macros->Get(macro);
467                 return true;
468         }
469
470         return false;
471 }