1 /******************************************************************************
3 * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
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. *
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. *
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 ******************************************************************************/
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>
37 using namespace icinga;
39 REGISTER_SCRIPTFUNCTION(ValidateServiceDictionary, &Host::ValidateServiceDictionary);
43 void Host::Start(void)
45 DynamicObject::Start();
49 Array::Ptr groups = GetGroups();
52 BOOST_FOREACH(const String& name, groups) {
53 HostGroup::Ptr hg = HostGroup::GetByName(name);
56 hg->AddMember(GetSelf());
61 void Host::OnConfigLoaded(void)
63 UpdateSlaveServices();
68 DynamicObject::Stop();
70 Array::Ptr groups = GetGroups();
73 BOOST_FOREACH(const String& name, groups) {
74 HostGroup::Ptr hg = HostGroup::GetByName(name);
77 hg->RemoveMember(GetSelf());
81 // TODO: unregister slave services/notifications?
84 String Host::GetDisplayName(void) const
86 if (!m_DisplayName.IsEmpty())
92 Array::Ptr Host::GetGroups(void) const
97 Dictionary::Ptr Host::GetMacros(void) const
102 Array::Ptr Host::GetHostDependencies(void) const
104 return m_HostDependencies;;
107 Array::Ptr Host::GetServiceDependencies(void) const
109 return m_ServiceDependencies;
112 String Host::GetHostCheck(void) const
117 Dictionary::Ptr Host::GetNotificationDescriptions(void) const
119 return m_NotificationDescriptions;
122 bool Host::IsReachable(void) const
126 std::set<Service::Ptr> parentServices = GetParentServices();
128 BOOST_FOREACH(const Service::Ptr& service, parentServices) {
129 ObjectLock olock(service);
131 /* ignore pending services */
132 if (!service->GetLastCheckResult())
135 /* ignore soft states */
136 if (service->GetStateType() == StateTypeSoft)
139 /* ignore services states OK and Warning */
140 if (service->GetState() == StateOK ||
141 service->GetState() == StateWarning)
147 std::set<Host::Ptr> parentHosts = GetParentHosts();
149 BOOST_FOREACH(const Host::Ptr& host, parentHosts) {
150 Service::Ptr hc = host->GetHostCheckService();
152 /* ignore hosts that don't have a hostcheck */
156 ObjectLock olock(hc);
158 /* ignore soft states */
159 if (hc->GetStateType() == StateTypeSoft)
162 /* ignore hosts that are up */
163 if (hc->GetState() == StateOK)
172 void Host::UpdateSlaveServices(void)
176 ConfigItem::Ptr item = ConfigItem::GetObject("Host", GetName());
178 /* Don't create slave services unless we own this object */
182 if (!m_ServiceDescriptions)
185 ObjectLock olock(m_ServiceDescriptions);
188 BOOST_FOREACH(boost::tie(svcname, svcdesc), m_ServiceDescriptions) {
189 if (svcdesc.IsScalar())
192 std::ostringstream namebuf;
193 namebuf << GetName() << ":" << svcname;
194 String name = namebuf.str();
196 ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(item->GetDebugInfo());
197 builder->SetType("Service");
198 builder->SetName(name);
199 builder->AddExpression("host_name", OperatorSet, GetName());
200 builder->AddExpression("display_name", OperatorSet, svcname);
201 builder->AddExpression("short_name", OperatorSet, svcname);
203 if (!svcdesc.IsObjectType<Dictionary>())
204 BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be either a string or a dictionary."));
206 Dictionary::Ptr service = svcdesc;
208 Array::Ptr templates = service->Get("templates");
211 ObjectLock olock(templates);
213 BOOST_FOREACH(const Value& tmpl, templates) {
214 builder->AddParent(tmpl);
218 /* Clone attributes from the host object. */
219 std::set<String, string_iless> keys;
220 keys.insert("check_interval");
221 keys.insert("retry_interval");
222 keys.insert("servicegroups");
223 keys.insert("checkers");
224 keys.insert("notification_interval");
225 keys.insert("notification_type_filter");
226 keys.insert("notification_state_filter");
227 keys.insert("check_period");
228 keys.insert("servicedependencies");
229 keys.insert("hostdependencies");
230 keys.insert("export_macros");
231 keys.insert("macros");
232 keys.insert("custom");
234 ExpressionList::Ptr host_exprl = boost::make_shared<ExpressionList>();
235 item->GetLinkedExpressionList()->ExtractFiltered(keys, host_exprl);
236 builder->AddExpressionList(host_exprl);
238 /* Clone attributes from the service expression list. */
239 std::vector<String> path;
240 path.push_back("services");
241 path.push_back(svcname);
243 ExpressionList::Ptr svc_exprl = boost::make_shared<ExpressionList>();
244 item->GetLinkedExpressionList()->ExtractPath(path, svc_exprl);
245 builder->AddExpressionList(svc_exprl);
247 ConfigItem::Ptr serviceItem = builder->Compile();
248 DynamicObject::Ptr dobj = serviceItem->Commit();
253 std::set<Service::Ptr> Host::GetServices(void) const
255 boost::mutex::scoped_lock lock(m_ServicesMutex);
257 std::set<Service::Ptr> services;
258 Service::WeakPtr wservice;
259 BOOST_FOREACH(boost::tie(boost::tuples::ignore, wservice), m_Services) {
260 Service::Ptr service = wservice.lock();
265 services.insert(service);
271 void Host::AddService(const Service::Ptr& service)
273 boost::mutex::scoped_lock lock(m_ServicesMutex);
275 m_Services[service->GetShortName()] = service;
278 void Host::RemoveService(const Service::Ptr& service)
280 boost::mutex::scoped_lock lock(m_ServicesMutex);
282 m_Services.erase(service->GetShortName());
285 int Host::GetTotalServices(void) const
287 return GetServices().size();
290 Value Host::ValidateServiceDictionary(const String& location, const Dictionary::Ptr& attrs)
292 ObjectLock olock(attrs);
296 BOOST_FOREACH(boost::tie(key, value), attrs) {
297 std::vector<String> templates;
299 if (!value.IsObjectType<Dictionary>())
300 BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be a dictionary."));
302 Dictionary::Ptr serviceDesc = value;
304 Array::Ptr templatesArray = serviceDesc->Get("templates");
306 if (templatesArray) {
307 ObjectLock tlock(templatesArray);
309 BOOST_FOREACH(const Value& tmpl, templatesArray) {
310 templates.push_back(tmpl);
314 BOOST_FOREACH(const String& name, templates) {
315 ConfigItem::Ptr item = ConfigItem::GetObject("Service", name);
318 ConfigCompilerContext::GetInstance()->AddError(false, "Validation failed for " +
319 location + ": Template '" + name + "' not found.");
326 Service::Ptr Host::GetServiceByShortName(const Value& name) const
328 if (name.IsScalar()) {
330 boost::mutex::scoped_lock lock(m_ServicesMutex);
332 std::map<String, Service::Ptr>::const_iterator it = m_Services.find(name);
334 if (it != m_Services.end())
338 return Service::Ptr();
339 } else if (name.IsObjectType<Dictionary>()) {
340 Dictionary::Ptr dict = name;
343 return Service::GetByNamePair(dict->Get("host"), dict->Get("service"));
345 BOOST_THROW_EXCEPTION(std::invalid_argument("Host/Service name pair is invalid: " + name.Serialize()));
349 std::set<Host::Ptr> Host::GetParentHosts(void) const
351 std::set<Host::Ptr> parents;
353 Array::Ptr dependencies = GetHostDependencies();
356 ObjectLock olock(dependencies);
358 BOOST_FOREACH(const Value& value, dependencies) {
359 if (value == GetName())
362 Host::Ptr host = GetByName(value);
367 parents.insert(host);
374 std::set<Host::Ptr> Host::GetChildHosts(void) const
376 std::set<Host::Ptr> childs;
378 BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
379 Array::Ptr dependencies = host->GetHostDependencies();
382 ObjectLock olock(dependencies);
384 BOOST_FOREACH(const Value& value, dependencies) {
385 if (value == GetName())
395 Service::Ptr Host::GetHostCheckService(void) const
397 String host_check = GetHostCheck();
399 if (host_check.IsEmpty())
400 return Service::Ptr();
402 return GetServiceByShortName(host_check);
405 std::set<Service::Ptr> Host::GetParentServices(void) const
407 std::set<Service::Ptr> parents;
409 Array::Ptr dependencies = GetServiceDependencies();
412 ObjectLock olock(dependencies);
414 BOOST_FOREACH(const Value& value, dependencies) {
415 parents.insert(GetServiceByShortName(value));
422 HostState Host::CalculateState(ServiceState state, bool reachable)
425 return HostUnreachable;
436 HostState Host::GetState(void) const
441 return HostUnreachable;
443 Service::Ptr hc = GetHostCheckService();
448 switch (hc->GetState()) {
458 HostState Host::GetLastState(void) const
463 return HostUnreachable;
465 Service::Ptr hc = GetHostCheckService();
470 switch (hc->GetLastState()) {
479 HostState Host::GetLastHardState(void) const
484 return HostUnreachable;
486 Service::Ptr hc = GetHostCheckService();
491 switch (hc->GetLastHardState()) {
500 double Host::GetLastStateUp(void) const
504 Service::Ptr hc = GetHostCheckService();
509 if (hc->GetLastStateOK() > hc->GetLastStateWarning())
510 return hc->GetLastStateOK();
512 return hc->GetLastStateWarning();
515 double Host::GetLastStateDown(void) const
519 Service::Ptr hc = GetHostCheckService();
524 return hc->GetLastStateCritical();
527 double Host::GetLastStateUnreachable(void) const
531 Service::Ptr hc = GetHostCheckService();
536 return hc->GetLastStateUnreachable();
539 double Host::GetLastStateChange(void) const
541 Service::Ptr hc = GetHostCheckService();
544 return IcingaApplication::GetInstance()->GetStartTime();
546 return hc->GetLastStateChange();
550 double Host::GetLastHardStateChange(void) const
552 Service::Ptr hc = GetHostCheckService();
555 return IcingaApplication::GetInstance()->GetStartTime();
557 return hc->GetLastHardStateChange();
560 StateType Host::GetLastStateType(void) const
562 Service::Ptr hc = GetHostCheckService();
565 return StateTypeHard;
567 return hc->GetLastStateType();
570 StateType Host::GetStateType(void) const
572 Service::Ptr hc = GetHostCheckService();
575 return StateTypeHard;
577 return hc->GetStateType();
580 String Host::StateToString(HostState state)
587 case HostUnreachable:
588 return "UNREACHABLE";
594 bool Host::ResolveMacro(const String& macro, const Dictionary::Ptr&, String *result) const
596 if (macro == "HOSTNAME") {
600 else if (macro == "HOSTDISPLAYNAME" || macro == "HOSTALIAS") {
601 *result = GetDisplayName();
605 Service::Ptr hc = GetHostCheckService();
606 Dictionary::Ptr hccr;
609 ServiceState state = hc->GetState();
610 bool reachable = IsReachable();
612 if (macro == "HOSTSTATE") {
613 *result = Convert::ToString(CalculateState(state, reachable));
615 } else if (macro == "HOSTSTATEID") {
616 *result = Convert::ToString(state);
618 } else if (macro == "HOSTSTATETYPE") {
619 *result = Service::StateTypeToString(hc->GetStateType());
621 } else if (macro == "HOSTATTEMPT") {
622 *result = Convert::ToString(hc->GetCurrentCheckAttempt());
624 } else if (macro == "MAXHOSTATTEMPT") {
625 *result = Convert::ToString(hc->GetMaxCheckAttempts());
627 } else if (macro == "LASTHOSTSTATE") {
628 *result = StateToString(GetLastState());
630 } else if (macro == "LASTHOSTSTATEID") {
631 *result = Convert::ToString(GetLastState());
633 } else if (macro == "LASTHOSTSTATETYPE") {
634 *result = Service::StateTypeToString(GetLastStateType());
636 } else if (macro == "LASTHOSTSTATECHANGE") {
637 *result = Convert::ToString((long)hc->GetLastStateChange());
641 hccr = hc->GetLastCheckResult();
645 if (macro == "HOSTLATENCY") {
646 *result = Convert::ToString(Service::CalculateLatency(hccr));
648 } else if (macro == "HOSTEXECUTIONTIME") {
649 *result = Convert::ToString(Service::CalculateExecutionTime(hccr));
651 } else if (macro == "HOSTOUTPUT") {
652 *result = hccr->Get("output");
654 } else if (macro == "HOSTPERFDATA") {
655 *result = hccr->Get("performance_data_raw");
657 } else if (macro == "LASTHOSTCHECK") {
658 *result = Convert::ToString((long)hccr->Get("schedule_start"));
663 Dictionary::Ptr macros = GetMacros();
667 if (name == "HOSTADDRESS")
669 else if (macro == "HOSTADDRESS6")
672 if (macros && macros->Contains(name)) {
673 *result = macros->Get(name);
677 if (macro == "HOSTADDRESS" || macro == "HOSTADDRESS6") {
685 void Host::InternalSerialize(const Dictionary::Ptr& bag, int attributeTypes) const
687 DynamicObject::InternalSerialize(bag, attributeTypes);
689 if (attributeTypes & Attribute_Config) {
690 bag->Set("display_name", m_DisplayName);
691 bag->Set("hostgroups", m_HostGroups);
692 bag->Set("macros", m_Macros);
693 bag->Set("hostdependencies", m_HostDependencies);
694 bag->Set("servicedependencies", m_ServiceDependencies);
695 bag->Set("hostcheck", m_HostCheck);
696 bag->Set("services", m_ServiceDescriptions);
697 bag->Set("notifications", m_NotificationDescriptions);
701 void Host::InternalDeserialize(const Dictionary::Ptr& bag, int attributeTypes)
703 DynamicObject::InternalDeserialize(bag, attributeTypes);
705 if (attributeTypes & Attribute_Config) {
706 m_DisplayName = bag->Get("display_name");
707 m_HostGroups = bag->Get("hostgroups");
708 m_Macros = bag->Get("macros");
709 m_HostDependencies = bag->Get("hostdependencies");
710 m_ServiceDependencies = bag->Get("servicedependencies");
711 m_HostCheck = bag->Get("hostcheck");
712 m_ServiceDescriptions = bag->Get("services");
713 m_NotificationDescriptions = bag->Get("notifications");