1 /******************************************************************************
3 * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
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. *
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. *
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 ******************************************************************************/
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>
33 using namespace icinga;
35 REGISTER_TYPE(Service);
37 Service::Service(const Dictionary::Ptr& serializedObject)
38 : DynamicObject(serializedObject), m_CheckRunning(false)
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);
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);
54 RegisterAttribute("event_command", Attribute_Config, &m_EventCommand);
55 RegisterAttribute("volatile", Attribute_Config, &m_Volatile);
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);
73 RegisterAttribute("short_name", Attribute_Config, &m_ShortName);
74 RegisterAttribute("host_name", Attribute_Config, &m_HostName);
76 RegisterAttribute("acknowledgement", Attribute_Replicated, &m_Acknowledgement);
77 RegisterAttribute("acknowledgement_expiry", Attribute_Replicated, &m_AcknowledgementExpiry);
79 RegisterAttribute("comments", Attribute_Replicated, &m_Comments);
81 RegisterAttribute("downtimes", Attribute_Replicated, &m_Downtimes);
83 RegisterAttribute("enable_notifications", Attribute_Replicated, &m_EnableNotifications);
84 RegisterAttribute("force_next_notification", Attribute_Replicated, &m_ForceNextNotification);
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);
92 SetSchedulingOffset(rand());
95 Service::~Service(void)
97 ServiceGroup::InvalidateMembersCache();
98 Host::InvalidateServicesCache();
99 Service::InvalidateDowntimesCache();
100 Service::InvalidateCommentsCache();
103 void Service::OnRegistrationCompleted(void)
107 DynamicObject::OnRegistrationCompleted();
109 InvalidateNotificationsCache();
112 String Service::GetDisplayName(void) const
114 if (m_DisplayName.IsEmpty())
115 return GetShortName();
117 return m_DisplayName;
120 Service::Ptr Service::GetByName(const String& name)
122 DynamicObject::Ptr configObject = DynamicObject::GetObject("Service", name);
124 return dynamic_pointer_cast<Service>(configObject);
127 Service::Ptr Service::GetByNamePair(const String& hostName, const String& serviceName)
129 if (!hostName.IsEmpty()) {
130 Host::Ptr host = Host::GetByName(hostName);
133 return Service::Ptr();
135 return host->GetServiceByShortName(serviceName);
137 return Service::GetByName(serviceName);
141 Host::Ptr Service::GetHost(void) const
143 return Host::GetByName(m_HostName);
146 Dictionary::Ptr Service::GetMacros(void) const
151 Array::Ptr Service::GetHostDependencies(void) const
153 return m_HostDependencies;
156 Array::Ptr Service::GetServiceDependencies(void) const
158 return m_ServiceDependencies;
161 Array::Ptr Service::GetGroups(void) const
163 return m_ServiceGroups;
166 String Service::GetHostName(void) const
171 String Service::GetShortName(void) const
173 if (m_ShortName.IsEmpty())
179 bool Service::IsReachable(void) const
183 BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
184 /* ignore ourselves */
185 if (service->GetName() == GetName())
188 ObjectLock olock(service);
190 /* ignore pending services */
191 if (!service->GetLastCheckResult())
194 /* ignore soft states */
195 if (service->GetStateType() == StateTypeSoft)
198 /* ignore services states OK and Warning */
199 if (service->GetState() == StateOK ||
200 service->GetState() == StateWarning)
206 BOOST_FOREACH(const Host::Ptr& host, GetParentHosts()) {
207 Service::Ptr hc = host->GetHostCheckService();
209 /* ignore hosts that don't have a hostcheck */
213 /* ignore ourselves */
214 if (hc->GetName() == GetName())
217 ObjectLock olock(hc);
219 /* ignore soft states */
220 if (hc->GetStateType() == StateTypeSoft)
223 /* ignore hosts that are up */
224 if (hc->GetState() == StateOK)
233 bool Service::IsVolatile(void) const
235 if (m_Volatile.IsEmpty())
241 AcknowledgementType Service::GetAcknowledgement(void)
245 if (m_Acknowledgement.IsEmpty())
246 return AcknowledgementNone;
248 int ivalue = static_cast<int>(m_Acknowledgement);
249 AcknowledgementType avalue = static_cast<AcknowledgementType>(ivalue);
251 if (avalue != AcknowledgementNone) {
252 double expiry = GetAcknowledgementExpiry();
254 if (expiry != 0 && expiry < Utility::GetTime()) {
255 avalue = AcknowledgementNone;
256 SetAcknowledgement(avalue);
257 SetAcknowledgementExpiry(0);
264 void Service::SetAcknowledgement(AcknowledgementType acknowledgement)
266 m_Acknowledgement = acknowledgement;
267 Touch("acknowledgement");
270 bool Service::IsAcknowledged(void)
272 return GetAcknowledgement() != AcknowledgementNone;
275 double Service::GetAcknowledgementExpiry(void) const
277 if (m_AcknowledgementExpiry.IsEmpty())
280 return static_cast<double>(m_AcknowledgementExpiry);
283 void Service::SetAcknowledgementExpiry(double timestamp)
285 m_AcknowledgementExpiry = timestamp;
286 Touch("acknowledgement_expiry");
289 void Service::AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, double expiry)
292 ObjectLock olock(this);
294 SetAcknowledgement(type);
295 SetAcknowledgementExpiry(expiry);
298 (void) AddComment(CommentAcknowledgement, author, comment, 0);
300 RequestNotifications(NotificationAcknowledgement, GetLastCheckResult(), author, comment);
303 void Service::ClearAcknowledgement(void)
305 ObjectLock olock(this);
307 SetAcknowledgement(AcknowledgementNone);
308 SetAcknowledgementExpiry(0);
311 void Service::OnAttributeChanged(const String& name)
315 Service::Ptr self = GetSelf();
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();
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());
336 /* update the next check timestamp if we're the owner of this service */
342 std::set<Host::Ptr> Service::GetParentHosts(void) const
344 std::set<Host::Ptr> parents;
346 Host::Ptr host = GetHost();
348 /* The service's host is implicitly a parent. */
350 parents.insert(host);
352 Array::Ptr dependencies = GetHostDependencies();
355 ObjectLock olock(dependencies);
357 BOOST_FOREACH(const Value& dependency, dependencies) {
358 Host::Ptr host = Host::GetByName(dependency);
363 parents.insert(host);
370 std::set<Service::Ptr> Service::GetParentServices(void) const
372 std::set<Service::Ptr> parents;
374 Host::Ptr host = GetHost();
375 Array::Ptr dependencies = GetServiceDependencies();
377 if (host && dependencies) {
378 ObjectLock olock(dependencies);
380 BOOST_FOREACH(const Value& dependency, dependencies) {
381 Service::Ptr service = host->GetServiceByShortName(dependency);
386 if (service->GetName() == GetName())
389 parents.insert(service);
396 bool Service::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const
398 if (macro == "SERVICEDESC") {
399 *result = GetShortName();
401 } else if (macro == "SERVICEDISPLAYNAME") {
402 *result = GetDisplayName();
404 } else if (macro == "SERVICECHECKCOMMAND") {
405 CheckCommand::Ptr commandObj = GetCheckCommand();
408 *result = commandObj->GetName();
415 if (macro == "SERVICESTATE") {
416 *result = StateToString(GetState());
418 } else if (macro == "SERVICESTATEID") {
419 *result = Convert::ToString(GetState());
421 } else if (macro == "SERVICESTATETYPE") {
422 *result = StateTypeToString(GetStateType());
424 } else if (macro == "SERVICEATTEMPT") {
425 *result = Convert::ToString(GetCurrentCheckAttempt());
427 } else if (macro == "MAXSERVICEATTEMPT") {
428 *result = Convert::ToString(GetMaxCheckAttempts());
430 } else if (macro == "LASTSERVICESTATE") {
431 *result = StateToString(GetLastState());
433 } else if (macro == "LASTSERVICESTATEID") {
434 *result = Convert::ToString(GetLastState());
436 } else if (macro == "LASTSERVICESTATETYPE") {
437 *result = StateTypeToString(GetLastStateType());
439 } else if (macro == "LASTSERVICESTATECHANGE") {
440 *result = Convert::ToString((long)GetLastStateChange());
445 if (macro == "SERVICELATENCY") {
446 *result = Convert::ToString(Service::CalculateLatency(cr));
448 } else if (macro == "SERVICEEXECUTIONTIME") {
449 *result = Convert::ToString(Service::CalculateExecutionTime(cr));
451 } else if (macro == "SERVICEOUTPUT") {
452 *result = cr->Get("output");
454 } else if (macro == "SERVICEPERFDATA") {
455 *result = cr->Get("performance_data_raw");
457 } else if (macro == "LASTSERVICECHECK") {
458 *result = Convert::ToString((long)cr->Get("execution_end"));
463 Dictionary::Ptr macros = GetMacros();
465 if (macros && macros->Contains(macro)) {
466 *result = macros->Get(macro);