]> granicus.if.org Git - icinga2/blob - lib/icinga/host.cpp
Clean up the DynamicType class.
[icinga2] / lib / icinga / host.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2013 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/host.h"
21 #include "icinga/service.h"
22 #include "icinga/hostgroup.h"
23 #include "icinga/icingaapplication.h"
24 #include "icinga/pluginutility.h"
25 #include "base/dynamictype.h"
26 #include "base/objectlock.h"
27 #include "base/logger_fwd.h"
28 #include "base/timer.h"
29 #include "base/convert.h"
30 #include "base/utility.h"
31 #include "base/scriptfunction.h"
32 #include "base/debug.h"
33 #include "base/serializer.h"
34 #include "config/configitembuilder.h"
35 #include "config/configcompilercontext.h"
36 #include <boost/tuple/tuple.hpp>
37 #include <boost/foreach.hpp>
38
39 using namespace icinga;
40
41 REGISTER_TYPE(Host);
42
43 void Host::Start(void)
44 {
45         DynamicObject::Start();
46
47         ASSERT(!OwnsLock());
48
49         Array::Ptr groups = GetGroups();
50
51         if (groups) {
52                 ObjectLock olock(groups);
53
54                 BOOST_FOREACH(const String& name, groups) {
55                         HostGroup::Ptr hg = HostGroup::GetByName(name);
56
57                         if (hg)
58                                 hg->AddMember(GetSelf());
59                 }
60         }
61 }
62
63 void Host::OnConfigLoaded(void)
64 {
65         UpdateSlaveServices();
66 }
67
68 void Host::Stop(void)
69 {
70         DynamicObject::Stop();
71
72         Array::Ptr groups = GetGroups();
73
74         if (groups) {
75                 ObjectLock olock(groups);
76
77                 BOOST_FOREACH(const String& name, groups) {
78                         HostGroup::Ptr hg = HostGroup::GetByName(name);
79
80                         if (hg)
81                                 hg->RemoveMember(GetSelf());
82                 }
83         }
84
85         // TODO: unregister slave services/notifications?
86 }
87
88 bool Host::IsReachable(void) const
89 {
90         ASSERT(!OwnsLock());
91
92         std::set<Service::Ptr> parentServices = GetParentServices();
93
94         BOOST_FOREACH(const Service::Ptr& service, parentServices) {
95                 ObjectLock olock(service);
96
97                 /* ignore pending services */
98                 if (!service->GetLastCheckResult())
99                         continue;
100
101                 /* ignore soft states */
102                 if (service->GetStateType() == StateTypeSoft)
103                         continue;
104
105                 /* ignore services states OK and Warning */
106                 if (service->GetState() == StateOK ||
107                     service->GetState() == StateWarning)
108                         continue;
109
110                 return false;
111         }
112
113         std::set<Host::Ptr> parentHosts = GetParentHosts();
114
115         BOOST_FOREACH(const Host::Ptr& host, parentHosts) {
116                 Service::Ptr hc = host->GetCheckService();
117
118                 /* ignore hosts that don't have a check */
119                 if (!hc)
120                         continue;
121
122                 ObjectLock olock(hc);
123
124                 /* ignore soft states */
125                 if (hc->GetStateType() == StateTypeSoft)
126                         continue;
127
128                 /* ignore hosts that are up */
129                 if (hc->GetState() == StateOK)
130                         continue;
131
132                 return false;
133         }
134
135         return true;
136 }
137
138 void Host::UpdateSlaveServices(void)
139 {
140         ASSERT(!OwnsLock());
141
142         ConfigItem::Ptr item = ConfigItem::GetObject("Host", GetName());
143
144         /* Don't create slave services unless we own this object */
145         if (!item)
146                 return;
147
148         Dictionary::Ptr service_descriptions = GetServiceDescriptions();
149
150         if (!service_descriptions)
151                 return;
152
153         ObjectLock olock(service_descriptions);
154         String svcname;
155         Value svcdesc;
156         BOOST_FOREACH(boost::tie(svcname, svcdesc), service_descriptions) {
157                 if (svcdesc.IsScalar())
158                         svcname = svcdesc;
159
160                 std::ostringstream namebuf;
161                 namebuf << GetName() << ":" << svcname;
162                 String name = namebuf.str();
163
164                 std::vector<String> path;
165                 path.push_back("services");
166                 path.push_back(svcname);
167
168                 DebugInfo di;
169                 item->GetLinkedExpressionList()->FindDebugInfoPath(path, di);
170
171                 if (di.Path.IsEmpty())
172                         di = item->GetDebugInfo();
173
174                 ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
175                 builder->SetType("Service");
176                 builder->SetName(name);
177                 builder->AddExpression("host", OperatorSet, GetName());
178                 builder->AddExpression("display_name", OperatorSet, svcname);
179                 builder->AddExpression("short_name", OperatorSet, svcname);
180
181                 if (!svcdesc.IsObjectType<Dictionary>())
182                         BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be either a string or a dictionary."));
183
184                 Dictionary::Ptr service = svcdesc;
185
186                 Array::Ptr templates = service->Get("templates");
187
188                 if (templates) {
189                         ObjectLock olock(templates);
190
191                         BOOST_FOREACH(const Value& tmpl, templates) {
192                                 builder->AddParent(tmpl);
193                         }
194                 }
195
196                 /* Clone attributes from the service expression list. */
197                 ExpressionList::Ptr svc_exprl = make_shared<ExpressionList>();
198                 item->GetLinkedExpressionList()->ExtractPath(path, svc_exprl);
199
200                 std::vector<String> dpath;
201                 dpath.push_back("templates");
202                 svc_exprl->ErasePath(dpath);
203
204                 builder->AddExpressionList(svc_exprl);
205
206                 ConfigItem::Ptr serviceItem = builder->Compile();
207                 serviceItem->Register();
208                 DynamicObject::Ptr dobj = serviceItem->Commit();
209                 dobj->OnConfigLoaded();
210         }
211 }
212
213 std::set<Service::Ptr> Host::GetServices(void) const
214 {
215         boost::mutex::scoped_lock lock(m_ServicesMutex);
216
217         std::set<Service::Ptr> services;
218         Service::WeakPtr wservice;
219         BOOST_FOREACH(boost::tie(boost::tuples::ignore, wservice), m_Services) {
220                 Service::Ptr service = wservice.lock();
221
222                 if (!service)
223                         continue;
224
225                 services.insert(service);
226         }
227
228         return services;
229 }
230
231 void Host::AddService(const Service::Ptr& service)
232 {
233         boost::mutex::scoped_lock lock(m_ServicesMutex);
234
235         m_Services[service->GetShortName()] = service;
236 }
237
238 void Host::RemoveService(const Service::Ptr& service)
239 {
240         boost::mutex::scoped_lock lock(m_ServicesMutex);
241
242         m_Services.erase(service->GetShortName());
243 }
244
245 int Host::GetTotalServices(void) const
246 {
247         return GetServices().size();
248 }
249
250 Service::Ptr Host::GetServiceByShortName(const Value& name) const
251 {
252         if (name.IsScalar()) {
253                 {
254                         boost::mutex::scoped_lock lock(m_ServicesMutex);
255
256                         std::map<String, Service::Ptr>::const_iterator it = m_Services.find(name);
257
258                         if (it != m_Services.end())
259                                 return it->second;
260                 }
261
262                 return Service::Ptr();
263         } else if (name.IsObjectType<Dictionary>()) {
264                 Dictionary::Ptr dict = name;
265                 String short_name;
266
267                 return Service::GetByNamePair(dict->Get("host"), dict->Get("service"));
268         } else {
269                 BOOST_THROW_EXCEPTION(std::invalid_argument("Host/Service name pair is invalid: " + JsonSerialize(name)));
270         }
271 }
272
273 std::set<Host::Ptr> Host::GetParentHosts(void) const
274 {
275         std::set<Host::Ptr> parents;
276
277         Array::Ptr dependencies = GetHostDependencies();
278
279         if (dependencies) {
280                 ObjectLock olock(dependencies);
281
282                 BOOST_FOREACH(const Value& value, dependencies) {
283                         if (value == GetName())
284                                 continue;
285
286                         Host::Ptr host = GetByName(value);
287
288                         if (!host)
289                                 continue;
290
291                         parents.insert(host);
292                 }
293         }
294
295         return parents;
296 }
297
298 std::set<Host::Ptr> Host::GetChildHosts(void) const
299 {
300         std::set<Host::Ptr> children;
301
302         BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
303                 Array::Ptr dependencies = host->GetHostDependencies();
304
305                 if (dependencies) {
306                         ObjectLock olock(dependencies);
307
308                         BOOST_FOREACH(const Value& value, dependencies) {
309                                 if (value == GetName())
310                                         children.insert(host);
311                         }
312                 }
313         }
314
315         return children;
316 }
317
318 Service::Ptr Host::GetCheckService(void) const
319 {
320         String host_check = GetCheck();
321
322         if (host_check.IsEmpty())
323                 return Service::Ptr();
324
325         return GetServiceByShortName(host_check);
326 }
327
328 std::set<Service::Ptr> Host::GetParentServices(void) const
329 {
330         std::set<Service::Ptr> parents;
331
332         Array::Ptr dependencies = GetServiceDependencies();
333
334         if (dependencies) {
335                 ObjectLock olock(dependencies);
336
337                 BOOST_FOREACH(const Value& value, dependencies) {
338                         parents.insert(GetServiceByShortName(value));
339                 }
340         }
341
342         return parents;
343 }
344
345 HostState Host::CalculateState(ServiceState state, bool reachable)
346 {
347         if (!reachable)
348                 return HostUnreachable;
349
350         switch (state) {
351                 case StateOK:
352                 case StateWarning:
353                         return HostUp;
354                 default:
355                         return HostDown;
356         }
357 }
358
359 HostState Host::GetState(void) const
360 {
361         ASSERT(!OwnsLock());
362
363         if (!IsReachable())
364                 return HostUnreachable;
365
366         Service::Ptr hc = GetCheckService();
367
368         if (!hc)
369                 return HostUp;
370
371         switch (hc->GetState()) {
372                 case StateOK:
373                 case StateWarning:
374                         return HostUp;
375                 default:
376                         return HostDown;
377         }
378
379 }
380
381 HostState Host::GetLastState(void) const
382 {
383         ASSERT(!OwnsLock());
384
385         if (!IsReachable())
386                 return HostUnreachable;
387
388         Service::Ptr hc = GetCheckService();
389
390         if (!hc)
391                 return HostUp;
392
393         switch (hc->GetLastState()) {
394                 case StateOK:
395                 case StateWarning:
396                         return HostUp;
397                 default:
398                         return HostDown;
399         }
400 }
401
402 HostState Host::GetLastHardState(void) const
403 {
404         ASSERT(!OwnsLock());
405
406         if (!IsReachable())
407                 return HostUnreachable;
408
409         Service::Ptr hc = GetCheckService();
410
411         if (!hc)
412                 return HostUp;
413
414         switch (hc->GetLastHardState()) {
415                 case StateOK:
416                 case StateWarning:
417                         return HostUp;
418                 default:
419                         return HostDown;
420         }
421 }
422
423 double Host::GetLastStateUp(void) const
424 {
425         ASSERT(!OwnsLock());
426
427         Service::Ptr hc = GetCheckService();
428
429         if (!hc)
430                 return 0;
431
432         if (hc->GetLastStateOK() > hc->GetLastStateWarning())
433                 return hc->GetLastStateOK();
434         else
435                 return hc->GetLastStateWarning();
436 }
437
438 double Host::GetLastStateDown(void) const
439 {
440         ASSERT(!OwnsLock());
441
442         Service::Ptr hc = GetCheckService();
443
444         if (!hc)
445                 return 0;
446
447         return hc->GetLastStateCritical();
448 }
449
450 double Host::GetLastStateUnreachable(void) const
451 {
452         ASSERT(!OwnsLock());
453
454         Service::Ptr hc = GetCheckService();
455
456         if (!hc)
457                 return 0;
458
459         return hc->GetLastStateUnreachable();
460 }
461
462 double Host::GetLastStateChange(void) const
463 {
464         Service::Ptr hc = GetCheckService();
465
466         if (!hc)
467                 return Application::GetStartTime();
468
469         return hc->GetLastStateChange();
470 }
471
472
473 double Host::GetLastHardStateChange(void) const
474 {
475         Service::Ptr hc = GetCheckService();
476
477         if (!hc)
478                 return Application::GetStartTime();
479
480         return hc->GetLastHardStateChange();
481 }
482
483 StateType Host::GetLastStateType(void) const
484 {
485         Service::Ptr hc = GetCheckService();
486
487         if (!hc)
488                 return StateTypeHard;
489
490         return hc->GetLastStateType();
491 }
492
493 StateType Host::GetStateType(void) const
494 {
495         Service::Ptr hc = GetCheckService();
496
497         if (!hc)
498                 return StateTypeHard;
499
500         return hc->GetStateType();
501 }
502
503 HostState Host::StateFromString(const String& state)
504 {
505         if (state == "UP")
506                 return HostUp;
507         else if (state == "DOWN")
508                 return HostDown;
509         else if (state == "UNREACHABLE")
510                 return HostUnreachable;
511         else
512                 return HostUnreachable;
513 }
514
515 String Host::StateToString(HostState state)
516 {
517         switch (state) {
518                 case HostUp:
519                         return "UP";
520                 case HostDown:
521                         return "DOWN";
522                 case HostUnreachable:
523                         return "UNREACHABLE";
524                 default:
525                         return "INVALID";
526         }
527 }
528
529 StateType Host::StateTypeFromString(const String& type)
530 {
531         if (type == "SOFT")
532                 return StateTypeSoft;
533         else
534                 return StateTypeHard;
535 }
536
537 String Host::StateTypeToString(StateType type)
538 {
539         if (type == StateTypeSoft)
540                 return "SOFT";
541         else
542                 return "HARD";
543 }
544
545 bool Host::ResolveMacro(const String& macro, const Dictionary::Ptr&, String *result) const
546 {
547         if (macro == "HOSTNAME") {
548                 *result = GetName();
549                 return true;
550         }
551         else if (macro == "HOSTDISPLAYNAME" || macro == "HOSTALIAS") {
552                 *result = GetDisplayName();
553                 return true;
554         }
555
556         Service::Ptr hc = GetCheckService();
557         Dictionary::Ptr hccr;
558
559         if (hc) {
560                 ServiceState state = hc->GetState();
561                 bool reachable = IsReachable();
562
563                 if (macro == "HOSTSTATE") {
564                         HostState hstate = CalculateState(state, reachable);
565
566                         switch (hstate) {
567                                 case HostUnreachable:
568                                         *result = "UNREACHABLE";
569                                         break;
570                                 case HostUp:
571                                         *result = "UP";
572                                         break;
573                                 case HostDown:
574                                         *result = "DOWN";
575                                         break;
576                                 default:
577                                         ASSERT(0);
578                         }
579
580                         return true;
581                 } else if (macro == "HOSTSTATEID") {
582                         *result = Convert::ToString(state);
583                         return true;
584                 } else if (macro == "HOSTSTATETYPE") {
585                         *result = Service::StateTypeToString(hc->GetStateType());
586                         return true;
587                 } else if (macro == "HOSTATTEMPT") {
588                         *result = Convert::ToString(hc->GetCheckAttempt());
589                         return true;
590                 } else if (macro == "MAXHOSTATTEMPT") {
591                         *result = Convert::ToString(hc->GetMaxCheckAttempts());
592                         return true;
593                 } else if (macro == "LASTHOSTSTATE") {
594                         *result = StateToString(GetLastState());
595                         return true;
596                 } else if (macro == "LASTHOSTSTATEID") {
597                         *result = Convert::ToString(GetLastState());
598                         return true;
599                 } else if (macro == "LASTHOSTSTATETYPE") {
600                         *result = Service::StateTypeToString(GetLastStateType());
601                         return true;
602                 } else if (macro == "LASTHOSTSTATECHANGE") {
603                         *result = Convert::ToString((long)hc->GetLastStateChange());
604                         return true;
605                 } else if (macro == "HOSTDURATIONSEC") {
606                         *result = Convert::ToString((long)(Utility::GetTime() - hc->GetLastStateChange()));
607                         return true;
608                 }
609
610                 hccr = hc->GetLastCheckResult();
611         }
612
613         if (hccr) {
614                 if (macro == "HOSTLATENCY") {
615                         *result = Convert::ToString(Service::CalculateLatency(hccr));
616                         return true;
617                 } else if (macro == "HOSTEXECUTIONTIME") {
618                         *result = Convert::ToString(Service::CalculateExecutionTime(hccr));
619                         return true;
620                 } else if (macro == "HOSTOUTPUT") {
621                         *result = hccr->Get("output");
622                         return true;
623                 } else if (macro == "HOSTPERFDATA") {
624                         *result = PluginUtility::FormatPerfdata(hccr->Get("performance_data"));
625                         return true;
626                 } else if (macro == "LASTHOSTCHECK") {
627                         *result = Convert::ToString((long)hccr->Get("schedule_start"));
628                         return true;
629                 }
630         }
631
632         Dictionary::Ptr macros = GetMacros();
633
634         String name = macro;
635
636         if (name == "HOSTADDRESS")
637                 name = "address";
638         else if (macro == "HOSTADDRESS6")
639                 name = "address6";
640
641         if (macros && macros->Contains(name)) {
642                 *result = macros->Get(name);
643                 return true;
644         }
645
646         if (macro == "HOSTADDRESS" || macro == "HOSTADDRESS6") {
647                 *result = GetName();
648                 return true;
649         }
650
651         return false;
652 }