]> granicus.if.org Git - icinga2/blob - lib/icinga/service.cpp
Implemented LAST*STATE* macros.
[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 "i2-icinga.h"
21
22 using namespace icinga;
23
24 REGISTER_TYPE(Service);
25
26 Service::Service(const Dictionary::Ptr& serializedObject)
27         : DynamicObject(serializedObject), m_CheckRunning(false)
28 {
29
30         RegisterAttribute("display_name", Attribute_Config, &m_DisplayName);
31         RegisterAttribute("macros", Attribute_Config, &m_Macros);
32         RegisterAttribute("hostdependencies", Attribute_Config, &m_HostDependencies);
33         RegisterAttribute("servicedependencies", Attribute_Config, &m_ServiceDependencies);
34         RegisterAttribute("servicegroups", Attribute_Config, &m_ServiceGroups);
35
36         RegisterAttribute("check_command", Attribute_Config, &m_CheckCommand);
37         RegisterAttribute("max_check_attempts", Attribute_Config, &m_MaxCheckAttempts);
38         RegisterAttribute("check_interval", Attribute_Config, &m_CheckInterval);
39         RegisterAttribute("retry_interval", Attribute_Config, &m_RetryInterval);
40         RegisterAttribute("checkers", Attribute_Config, &m_Checkers);
41
42         RegisterAttribute("next_check", Attribute_Replicated, &m_NextCheck);
43         RegisterAttribute("current_checker", Attribute_Replicated, &m_CurrentChecker);
44         RegisterAttribute("check_attempt", Attribute_Replicated, &m_CheckAttempt);
45         RegisterAttribute("state", Attribute_Replicated, &m_State);
46         RegisterAttribute("state_type", Attribute_Replicated, &m_StateType);
47         RegisterAttribute("last_state", Attribute_Replicated, &m_LastState);
48         RegisterAttribute("last_state_type", Attribute_Replicated, &m_LastStateType);
49         RegisterAttribute("last_result", Attribute_Replicated, &m_LastResult);
50         RegisterAttribute("last_state_change", Attribute_Replicated, &m_LastStateChange);
51         RegisterAttribute("last_hard_state_change", Attribute_Replicated, &m_LastHardStateChange);
52         RegisterAttribute("enable_active_checks", Attribute_Replicated, &m_EnableActiveChecks);
53         RegisterAttribute("enable_passive_checks", Attribute_Replicated, &m_EnablePassiveChecks);
54         RegisterAttribute("force_next_check", Attribute_Replicated, &m_ForceNextCheck);
55
56         RegisterAttribute("short_name", Attribute_Config, &m_ShortName);
57         RegisterAttribute("host_name", Attribute_Config, &m_HostName);
58
59         RegisterAttribute("acknowledgement", Attribute_Replicated, &m_Acknowledgement);
60         RegisterAttribute("acknowledgement_expiry", Attribute_Replicated, &m_AcknowledgementExpiry);
61
62         RegisterAttribute("comments", Attribute_Replicated, &m_Comments);
63
64         RegisterAttribute("downtimes", Attribute_Replicated, &m_Downtimes);
65
66         RegisterAttribute("enable_notifications", Attribute_Replicated, &m_EnableNotifications);
67         RegisterAttribute("last_notification", Attribute_Replicated, &m_LastNotification);
68         RegisterAttribute("notification_interval", Attribute_Config, &m_NotificationInterval);
69
70         SetSchedulingOffset(rand());
71 }
72
73 Service::~Service(void)
74 {
75         ServiceGroup::InvalidateMembersCache();
76         Host::InvalidateServicesCache();
77         Service::InvalidateDowntimesCache();
78         Service::InvalidateCommentsCache();
79 }
80
81 /**
82  * @threadsafety Always.
83  */
84 void Service::OnRegistrationCompleted(void)
85 {
86         assert(!OwnsLock());
87
88         DynamicObject::OnRegistrationCompleted();
89
90         InvalidateNotificationsCache();
91 }
92
93 /**
94  * @threadsafety Always.
95  */
96 String Service::GetDisplayName(void) const
97 {
98         if (m_DisplayName.IsEmpty())
99                 return GetShortName();
100         else
101                 return m_DisplayName;
102 }
103
104 /**
105  * @threadsafety Always.
106  */
107 Service::Ptr Service::GetByName(const String& name)
108 {
109         DynamicObject::Ptr configObject = DynamicObject::GetObject("Service", name);
110
111         return dynamic_pointer_cast<Service>(configObject);
112 }
113
114 /**
115  * @threadsafety Always.
116  */
117 Service::Ptr Service::GetByNamePair(const String& hostName, const String& serviceName)
118 {
119         if (!hostName.IsEmpty()) {
120                 Host::Ptr host = Host::GetByName(hostName);
121
122                 if (!host)
123                         return Service::Ptr();
124
125                 return host->GetServiceByShortName(serviceName);
126         } else {
127                 return Service::GetByName(serviceName);
128         }
129 }
130
131 /**
132  * @threadsafety Always.
133  */
134 Host::Ptr Service::GetHost(void) const
135 {
136         return Host::GetByName(m_HostName);
137 }
138
139 /**
140  * @threadsafety Always.
141  */
142 Dictionary::Ptr Service::GetMacros(void) const
143 {
144         return m_Macros;
145 }
146
147 /**
148  * @threadsafety Always.
149  */
150 Dictionary::Ptr Service::GetHostDependencies(void) const
151 {
152         return m_HostDependencies;
153 }
154
155 /**
156  * @threadsafety Always.
157  */
158 Dictionary::Ptr Service::GetServiceDependencies(void) const
159 {
160         return m_ServiceDependencies;
161 }
162
163 /**
164  * @threadsafety Always.
165  */
166 Dictionary::Ptr Service::GetGroups(void) const
167 {
168         return m_ServiceGroups;
169 }
170
171 /**
172  * @threadsafety Always.
173  */
174 String Service::GetHostName(void) const
175 {
176         return m_HostName;
177 }
178
179 /**
180  * @threadsafety Always.
181  */
182 String Service::GetShortName(void) const
183 {
184         if (m_ShortName.IsEmpty())
185                 return GetName();
186         else
187                 return m_ShortName;
188 }
189
190 /**
191  * @threadsafety Always.
192  */
193 bool Service::IsReachable(void) const
194 {
195         assert(!OwnsLock());
196
197         BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
198                 /* ignore ourselves */
199                 if (service->GetName() == GetName())
200                         continue;
201
202                 ObjectLock olock(service);
203
204                 /* ignore pending services */
205                 if (!service->GetLastCheckResult())
206                         continue;
207
208                 /* ignore soft states */
209                 if (service->GetStateType() == StateTypeSoft)
210                         continue;
211
212                 /* ignore services states OK and Warning */
213                 if (service->GetState() == StateOK ||
214                     service->GetState() == StateWarning)
215                         continue;
216
217                 return false;
218         }
219
220         BOOST_FOREACH(const Host::Ptr& host, GetParentHosts()) {
221                 Service::Ptr hc = host->GetHostCheckService();
222
223                 /* ignore hosts that don't have a hostcheck */
224                 if (!hc)
225                         continue;
226
227                 /* ignore ourselves */
228                 if (hc->GetName() == GetName())
229                         continue;
230
231                 ObjectLock olock(hc);
232
233                 /* ignore soft states */
234                 if (hc->GetStateType() == StateTypeSoft)
235                         continue;
236
237                 /* ignore hosts that are up */
238                 if (hc->GetState() == StateOK)
239                         continue;
240
241                 return false;
242         }
243
244         return true;
245 }
246
247 /**
248  * @threadsafety Always.
249  */
250 AcknowledgementType Service::GetAcknowledgement(void)
251 {
252         assert(OwnsLock());
253
254         if (m_Acknowledgement.IsEmpty())
255                 return AcknowledgementNone;
256
257         int ivalue = static_cast<int>(m_Acknowledgement);
258         AcknowledgementType avalue = static_cast<AcknowledgementType>(ivalue);
259
260         if (avalue != AcknowledgementNone) {
261                 double expiry = GetAcknowledgementExpiry();
262
263                 if (expiry != 0 && expiry < Utility::GetTime()) {
264                         avalue = AcknowledgementNone;
265                         SetAcknowledgement(avalue);
266                         SetAcknowledgementExpiry(0);
267                 }
268         }
269
270         return avalue;
271 }
272
273 /**
274  * @threadsafety Always.
275  */
276 void Service::SetAcknowledgement(AcknowledgementType acknowledgement)
277 {
278         m_Acknowledgement = acknowledgement;
279         Touch("acknowledgement");
280 }
281
282 /**
283  * @threadsafety Always.
284  */
285 bool Service::IsAcknowledged(void)
286 {
287         return GetAcknowledgement() != AcknowledgementNone;
288 }
289
290 /**
291  * @threadsafety Always.
292  */
293 double Service::GetAcknowledgementExpiry(void) const
294 {
295         if (m_AcknowledgementExpiry.IsEmpty())
296                 return 0;
297
298         return static_cast<double>(m_AcknowledgementExpiry);
299 }
300
301 /**
302  * @threadsafety Always.
303  */
304 void Service::SetAcknowledgementExpiry(double timestamp)
305 {
306         m_AcknowledgementExpiry = timestamp;
307         Touch("acknowledgement_expiry");
308 }
309
310 /**
311  * @threadsafety Always.
312  */
313 void Service::AcknowledgeProblem(AcknowledgementType type, double expiry)
314 {
315         ObjectLock olock(this);
316
317         SetAcknowledgement(type);
318         SetAcknowledgementExpiry(expiry);
319
320         RequestNotifications(NotificationAcknowledgement, GetLastCheckResult());
321 }
322
323 /**
324  * @threadsafety Always.
325  */
326 void Service::ClearAcknowledgement(void)
327 {
328         ObjectLock olock(this);
329
330         SetAcknowledgement(AcknowledgementNone);
331         SetAcknowledgementExpiry(0);
332 }
333
334 /**
335  * @threadsafety Always.
336  */
337 void Service::OnAttributeChanged(const String& name)
338 {
339         assert(!OwnsLock());
340
341         Service::Ptr self = GetSelf();
342
343         if (name == "current_checker")
344                 OnCheckerChanged(self);
345         else if (name == "next_check")
346                 OnNextCheckChanged(self);
347         else if (name == "servicegroups")
348                 ServiceGroup::InvalidateMembersCache();
349         else if (name == "host_name" || name == "short_name") {
350                 Host::InvalidateServicesCache();
351
352                 UpdateSlaveNotifications();
353         } else if (name == "downtimes")
354                 Service::InvalidateDowntimesCache();
355         else if (name == "comments")
356                 Service::InvalidateCommentsCache();
357         else if (name == "notifications")
358                 UpdateSlaveNotifications();
359         else if (name == "check_interval") {
360                 ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName());
361
362                 /* update the next check timestamp if we're the owner of this service */
363                 if (item && !IsAbstract())
364                         UpdateNextCheck();
365         }
366 }
367
368 /**
369  * @threadsafety Always.
370  */
371 set<Host::Ptr> Service::GetParentHosts(void) const
372 {
373         set<Host::Ptr> parents;
374
375         Host::Ptr host = GetHost();
376
377         /* The service's host is implicitly a parent. */
378         if (host)
379                 parents.insert(host);
380
381         Dictionary::Ptr dependencies = GetHostDependencies();
382
383         if (dependencies) {
384                 ObjectLock olock(dependencies);
385
386                 String key;
387                 BOOST_FOREACH(tie(key, tuples::ignore), dependencies) {
388                         Host::Ptr host = Host::GetByName(key);
389
390                         if (!host)
391                                 continue;
392
393                         parents.insert(host);
394                 }
395         }
396
397         return parents;
398 }
399
400 /**
401  * @threadsafety Always.
402  */
403 set<Service::Ptr> Service::GetParentServices(void) const
404 {
405         set<Service::Ptr> parents;
406
407         Host::Ptr host = GetHost();
408         Dictionary::Ptr dependencies = GetServiceDependencies();
409
410         if (host && dependencies) {
411                 String key;
412                 Value value;
413                 BOOST_FOREACH(tie(key, value), dependencies) {
414                         Service::Ptr service = host->GetServiceByShortName(value);
415
416                         if (!service)
417                                 continue;
418
419                         if (service->GetName() == GetName())
420                                 continue;
421
422                         parents.insert(service);
423                 }
424         }
425
426         return parents;
427 }
428
429 /**
430  * @threadsafety Always.
431  */
432 Dictionary::Ptr Service::CalculateDynamicMacros(void) const
433 {
434         Dictionary::Ptr macros = boost::make_shared<Dictionary>();
435
436         Dictionary::Ptr cr;
437
438         {
439                 ObjectLock olock(this);
440                 macros->Set("SERVICEDESC", GetShortName());
441                 macros->Set("SERVICEDISPLAYNAME", GetDisplayName());
442                 macros->Set("SERVICESTATE", StateToString(GetState()));
443                 macros->Set("SERVICESTATEID", GetState());
444                 macros->Set("SERVICESTATETYPE", StateTypeToString(GetStateType()));
445                 macros->Set("SERVICEATTEMPT", GetCurrentCheckAttempt());
446                 macros->Set("MAXSERVICEATTEMPT", GetMaxCheckAttempts());
447                 macros->Set("SERVICECHECKCOMMAND", "check_i2");
448                 macros->Set("LASTSERVICESTATE", StateToString(GetLastState()));
449                 macros->Set("LASTSERVICESTATEID", GetLastState());
450                 macros->Set("LASTSERVICESTATETYPE", StateTypeToString(GetLastStateType()));
451                 macros->Set("LASTSERVICESTATECHANGE", (time_t)GetLastStateChange());
452
453                 cr = GetLastCheckResult();
454         }
455
456         if (cr) {
457                 assert(cr->IsSealed());
458
459                 macros->Set("SERVICELATENCY", Service::CalculateLatency(cr));
460                 macros->Set("SERVICEEXECUTIONTIME", Service::CalculateExecutionTime(cr));
461
462                 macros->Set("SERVICEOUTPUT", cr->Get("output"));
463                 macros->Set("SERVICEPERFDATA", cr->Get("performance_data_raw"));
464
465                 macros->Set("LASTSERVICECHECK", (time_t)cr->Get("schedule_start"));
466         }
467
468         macros->Seal();
469
470         return macros;
471 }
472
473 Dictionary::Ptr Service::CalculateAllMacros(void) const
474 {
475         vector<Dictionary::Ptr> macroDicts;
476         macroDicts.push_back(GetMacros());
477
478         Host::Ptr host = GetHost();
479
480         macroDicts.push_back(CalculateDynamicMacros());
481
482         if (host) {
483                 macroDicts.push_back(host->GetMacros());
484                 macroDicts.push_back(host->CalculateDynamicMacros());
485         }
486
487         IcingaApplication::Ptr app = IcingaApplication::GetInstance();
488         macroDicts.push_back(app->GetMacros());
489
490         macroDicts.push_back(IcingaApplication::CalculateDynamicMacros());
491
492         return MacroProcessor::MergeMacroDicts(macroDicts);
493 }