]> granicus.if.org Git - icinga2/blob - lib/icinga/host.cpp
Update copyright information.
[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_HostGroups;
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::GetHostCheck(void) const
115 {
116         return m_HostCheck;
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->GetHostCheckService();
153
154                 /* ignore hosts that don't have a hostcheck */
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 host object. */
231                 std::set<String, string_iless> keys;
232                 keys.insert("check_interval");
233                 keys.insert("retry_interval");
234                 keys.insert("servicegroups");
235                 keys.insert("notification_interval");
236                 keys.insert("notification_type_filter");
237                 keys.insert("notification_state_filter");
238                 keys.insert("check_period");
239                 keys.insert("servicedependencies");
240                 keys.insert("hostdependencies");
241                 keys.insert("authorities");
242                 keys.insert("domains");
243
244                 ExpressionList::Ptr host_exprl = boost::make_shared<ExpressionList>();
245                 item->GetLinkedExpressionList()->ExtractFiltered(keys, host_exprl);
246                 builder->AddExpressionList(host_exprl);
247
248                 /* Clone attributes from the service expression list. */
249                 ExpressionList::Ptr svc_exprl = boost::make_shared<ExpressionList>();
250                 item->GetLinkedExpressionList()->ExtractPath(path, svc_exprl);
251
252                 std::vector<String> dpath;
253                 dpath.push_back("templates");
254                 svc_exprl->ErasePath(dpath);
255
256                 builder->AddExpressionList(svc_exprl);
257
258                 ConfigItem::Ptr serviceItem = builder->Compile();
259                 serviceItem->Register();
260                 DynamicObject::Ptr dobj = serviceItem->Commit();
261                 dobj->OnConfigLoaded();
262         }
263 }
264
265 std::set<Service::Ptr> Host::GetServices(void) const
266 {
267         boost::mutex::scoped_lock lock(m_ServicesMutex);
268
269         std::set<Service::Ptr> services;
270         Service::WeakPtr wservice;
271         BOOST_FOREACH(boost::tie(boost::tuples::ignore, wservice), m_Services) {
272                 Service::Ptr service = wservice.lock();
273
274                 if (!service)
275                         continue;
276
277                 services.insert(service);
278         }
279
280         return services;
281 }
282
283 void Host::AddService(const Service::Ptr& service)
284 {
285         boost::mutex::scoped_lock lock(m_ServicesMutex);
286
287         m_Services[service->GetShortName()] = service;
288 }
289
290 void Host::RemoveService(const Service::Ptr& service)
291 {
292         boost::mutex::scoped_lock lock(m_ServicesMutex);
293
294         m_Services.erase(service->GetShortName());
295 }
296
297 int Host::GetTotalServices(void) const
298 {
299         return GetServices().size();
300 }
301
302 Service::Ptr Host::GetServiceByShortName(const Value& name) const
303 {
304         if (name.IsScalar()) {
305                 {
306                         boost::mutex::scoped_lock lock(m_ServicesMutex);
307
308                         std::map<String, Service::Ptr>::const_iterator it = m_Services.find(name);
309
310                         if (it != m_Services.end())
311                                 return it->second;
312                 }
313
314                 return Service::Ptr();
315         } else if (name.IsObjectType<Dictionary>()) {
316                 Dictionary::Ptr dict = name;
317                 String short_name;
318
319                 return Service::GetByNamePair(dict->Get("host"), dict->Get("service"));
320         } else {
321                 BOOST_THROW_EXCEPTION(std::invalid_argument("Host/Service name pair is invalid: " + name.Serialize()));
322         }
323 }
324
325 std::set<Host::Ptr> Host::GetParentHosts(void) const
326 {
327         std::set<Host::Ptr> parents;
328
329         Array::Ptr dependencies = GetHostDependencies();
330
331         if (dependencies) {
332                 ObjectLock olock(dependencies);
333
334                 BOOST_FOREACH(const Value& value, dependencies) {
335                         if (value == GetName())
336                                 continue;
337
338                         Host::Ptr host = GetByName(value);
339
340                         if (!host)
341                                 continue;
342
343                         parents.insert(host);
344                 }
345         }
346
347         return parents;
348 }
349
350 std::set<Host::Ptr> Host::GetChildHosts(void) const
351 {
352         std::set<Host::Ptr> childs;
353
354         BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
355                 Array::Ptr dependencies = host->GetHostDependencies();
356
357                 if (dependencies) {
358                         ObjectLock olock(dependencies);
359
360                         BOOST_FOREACH(const Value& value, dependencies) {
361                                 if (value == GetName())
362                                         childs.insert(host);
363                         }
364                 }
365         }
366
367         return childs;
368
369 }
370
371 Service::Ptr Host::GetHostCheckService(void) const
372 {
373         String host_check = GetHostCheck();
374
375         if (host_check.IsEmpty())
376                 return Service::Ptr();
377
378         return GetServiceByShortName(host_check);
379 }
380
381 std::set<Service::Ptr> Host::GetParentServices(void) const
382 {
383         std::set<Service::Ptr> parents;
384
385         Array::Ptr dependencies = GetServiceDependencies();
386
387         if (dependencies) {
388                 ObjectLock olock(dependencies);
389
390                 BOOST_FOREACH(const Value& value, dependencies) {
391                         parents.insert(GetServiceByShortName(value));
392                 }
393         }
394
395         return parents;
396 }
397
398 HostState Host::CalculateState(ServiceState state, bool reachable)
399 {
400         if (!reachable)
401                 return HostUnreachable;
402
403         switch (state) {
404                 case StateOK:
405                 case StateWarning:
406                         return HostUp;
407                 default:
408                         return HostDown;
409         }
410 }
411
412 HostState Host::GetState(void) const
413 {
414         ASSERT(!OwnsLock());
415
416         if (!IsReachable())
417                 return HostUnreachable;
418
419         Service::Ptr hc = GetHostCheckService();
420
421         if (!hc)
422                 return HostUp;
423
424         switch (hc->GetState()) {
425                 case StateOK:
426                 case StateWarning:
427                         return HostUp;
428                 default:
429                         return HostDown;
430         }
431
432 }
433
434 HostState Host::GetLastState(void) const
435 {
436         ASSERT(!OwnsLock());
437
438         if (!IsReachable())
439                 return HostUnreachable;
440
441         Service::Ptr hc = GetHostCheckService();
442
443         if (!hc)
444                 return HostUp;
445
446         switch (hc->GetLastState()) {
447                 case StateOK:
448                 case StateWarning:
449                         return HostUp;
450                 default:
451                         return HostDown;
452         }
453 }
454
455 HostState Host::GetLastHardState(void) const
456 {
457         ASSERT(!OwnsLock());
458
459         if (!IsReachable())
460                 return HostUnreachable;
461
462         Service::Ptr hc = GetHostCheckService();
463
464         if (!hc)
465                 return HostUp;
466
467         switch (hc->GetLastHardState()) {
468                 case StateOK:
469                 case StateWarning:
470                         return HostUp;
471                 default:
472                         return HostDown;
473         }
474 }
475
476 double Host::GetLastStateUp(void) const
477 {
478         ASSERT(!OwnsLock());
479
480         Service::Ptr hc = GetHostCheckService();
481
482         if (!hc)
483                 return 0;
484
485         if (hc->GetLastStateOK() > hc->GetLastStateWarning())
486                 return hc->GetLastStateOK();
487         else
488                 return hc->GetLastStateWarning();
489 }
490
491 double Host::GetLastStateDown(void) const
492 {
493         ASSERT(!OwnsLock());
494
495         Service::Ptr hc = GetHostCheckService();
496
497         if (!hc)
498                 return 0;
499
500         return hc->GetLastStateCritical();
501 }
502
503 double Host::GetLastStateUnreachable(void) const
504 {
505         ASSERT(!OwnsLock());
506
507         Service::Ptr hc = GetHostCheckService();
508
509         if (!hc)
510                 return 0;
511
512         return hc->GetLastStateUnreachable();
513 }
514
515 double Host::GetLastStateChange(void) const
516 {
517         Service::Ptr hc = GetHostCheckService();
518
519         if (!hc)
520                 return IcingaApplication::GetInstance()->GetStartTime();
521
522         return hc->GetLastStateChange();
523 }
524
525
526 double Host::GetLastHardStateChange(void) const
527 {
528         Service::Ptr hc = GetHostCheckService();
529
530         if (!hc)
531                 return IcingaApplication::GetInstance()->GetStartTime();
532
533         return hc->GetLastHardStateChange();
534 }
535
536 StateType Host::GetLastStateType(void) const
537 {
538         Service::Ptr hc = GetHostCheckService();
539
540         if (!hc)
541                 return StateTypeHard;
542
543         return hc->GetLastStateType();
544 }
545
546 StateType Host::GetStateType(void) const
547 {
548         Service::Ptr hc = GetHostCheckService();
549
550         if (!hc)
551                 return StateTypeHard;
552
553         return hc->GetStateType();
554 }
555
556 String Host::StateToString(HostState state)
557 {
558         switch (state) {
559                 case HostUp:
560                         return "UP";
561                 case HostDown:
562                         return "DOWN";
563                 case HostUnreachable:
564                         return "UNREACHABLE";
565                 default:
566                         return "INVALID";
567         }
568 }
569
570 bool Host::ResolveMacro(const String& macro, const Dictionary::Ptr&, String *result) const
571 {
572         if (macro == "HOSTNAME") {
573                 *result = GetName();
574                 return true;
575         }
576         else if (macro == "HOSTDISPLAYNAME" || macro == "HOSTALIAS") {
577                 *result = GetDisplayName();
578                 return true;
579         }
580
581         Service::Ptr hc = GetHostCheckService();
582         Dictionary::Ptr hccr;
583
584         if (hc) {
585                 ServiceState state = hc->GetState();
586                 bool reachable = IsReachable();
587
588                 if (macro == "HOSTSTATE") {
589                         HostState hstate = CalculateState(state, reachable);
590
591                         switch (hstate) {
592                                 case HostUnreachable:
593                                         *result = "UNREACHABLE";
594                                         break;
595                                 case HostUp:
596                                         *result = "UP";
597                                         break;
598                                 case HostDown:
599                                         *result = "DOWN";
600                                         break;
601                                 default:
602                                         ASSERT(0);
603                         }
604
605                         return true;
606                 } else if (macro == "HOSTSTATEID") {
607                         *result = Convert::ToString(state);
608                         return true;
609                 } else if (macro == "HOSTSTATETYPE") {
610                         *result = Service::StateTypeToString(hc->GetStateType());
611                         return true;
612                 } else if (macro == "HOSTATTEMPT") {
613                         *result = Convert::ToString(hc->GetCurrentCheckAttempt());
614                         return true;
615                 } else if (macro == "MAXHOSTATTEMPT") {
616                         *result = Convert::ToString(hc->GetMaxCheckAttempts());
617                         return true;
618                 } else if (macro == "LASTHOSTSTATE") {
619                         *result = StateToString(GetLastState());
620                         return true;
621                 } else if (macro == "LASTHOSTSTATEID") {
622                         *result = Convert::ToString(GetLastState());
623                         return true;
624                 } else if (macro == "LASTHOSTSTATETYPE") {
625                         *result = Service::StateTypeToString(GetLastStateType());
626                         return true;
627                 } else if (macro == "LASTHOSTSTATECHANGE") {
628                         *result = Convert::ToString((long)hc->GetLastStateChange());
629                         return true;
630                 }
631
632                 hccr = hc->GetLastCheckResult();
633         }
634
635         if (hccr) {
636                 if (macro == "HOSTLATENCY") {
637                         *result = Convert::ToString(Service::CalculateLatency(hccr));
638                         return true;
639                 } else if (macro == "HOSTEXECUTIONTIME") {
640                         *result = Convert::ToString(Service::CalculateExecutionTime(hccr));
641                         return true;
642                 } else if (macro == "HOSTOUTPUT") {
643                         *result = hccr->Get("output");
644                         return true;
645                 } else if (macro == "HOSTPERFDATA") {
646                         *result = hccr->Get("performance_data_raw");
647                         return true;
648                 } else if (macro == "LASTHOSTCHECK") {
649                         *result = Convert::ToString((long)hccr->Get("schedule_start"));
650                         return true;
651                 }
652         }
653
654         Dictionary::Ptr macros = GetMacros();
655
656         String name = macro;
657
658         if (name == "HOSTADDRESS")
659                 name = "address";
660         else if (macro == "HOSTADDRESS6")
661                 name = "address6";
662
663         if (macros && macros->Contains(name)) {
664                 *result = macros->Get(name);
665                 return true;
666         }
667
668         if (macro == "HOSTADDRESS" || macro == "HOSTADDRESS6") {
669                 *result = GetName();
670                 return true;
671         }
672
673         return false;
674 }
675
676 void Host::InternalSerialize(const Dictionary::Ptr& bag, int attributeTypes) const
677 {
678         DynamicObject::InternalSerialize(bag, attributeTypes);
679
680         if (attributeTypes & Attribute_Config) {
681                 bag->Set("display_name", m_DisplayName);
682                 bag->Set("hostgroups", m_HostGroups);
683                 bag->Set("macros", m_Macros);
684                 bag->Set("hostdependencies", m_HostDependencies);
685                 bag->Set("servicedependencies", m_ServiceDependencies);
686                 bag->Set("hostcheck", m_HostCheck);
687                 bag->Set("services", m_ServiceDescriptions);
688                 bag->Set("notifications", m_NotificationDescriptions);
689         }
690 }
691
692 void Host::InternalDeserialize(const Dictionary::Ptr& bag, int attributeTypes)
693 {
694         DynamicObject::InternalDeserialize(bag, attributeTypes);
695
696         if (attributeTypes & Attribute_Config) {
697                 m_DisplayName = bag->Get("display_name");
698                 m_HostGroups = bag->Get("hostgroups");
699                 m_Macros = bag->Get("macros");
700                 m_HostDependencies = bag->Get("hostdependencies");
701                 m_ServiceDependencies = bag->Get("servicedependencies");
702                 m_HostCheck = bag->Get("hostcheck");
703                 m_ServiceDescriptions = bag->Get("services");
704                 m_NotificationDescriptions = bag->Get("notifications");
705         }
706 }