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