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