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