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