/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/dependency.hpp" #include "icinga/dependency.tcpp" #include "icinga/service.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include #include #include using namespace icinga; REGISTER_TYPE(Dependency); String DependencyNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Dependency::Ptr dependency = dynamic_pointer_cast(context); if (!dependency) return ""; String name = dependency->GetChildHostName(); if (!dependency->GetChildServiceName().IsEmpty()) name += "!" + dependency->GetChildServiceName(); name += "!" + shortName; return name; } Dictionary::Ptr DependencyNameComposer::ParseName(const String& name) const { std::vector tokens; boost::algorithm::split(tokens, name, boost::is_any_of("!")); if (tokens.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Dependency name.")); Dictionary::Ptr result = new Dictionary(); result->Set("child_host_name", tokens[0]); if (tokens.size() > 2) { result->Set("child_service_name", tokens[1]); result->Set("name", tokens[2]); } else { result->Set("name", tokens[1]); } return result; } void Dependency::OnConfigLoaded(void) { Value defaultFilter; if (GetParentServiceName().IsEmpty()) defaultFilter = StateFilterUp; else defaultFilter = StateFilterOK | StateFilterWarning; SetStateFilter(FilterArrayToInt(GetStates(), Notification::GetStateFilterMap(), defaultFilter)); } void Dependency::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); Host::Ptr childHost = Host::GetByName(GetChildHostName()); if (childHost) { if (GetChildServiceName().IsEmpty()) { Log(LogDebug, "Dependency") << "Dependency '" << GetName() << "' child host '" << GetChildHostName() << "."; m_Child = childHost; } else { Log(LogDebug, "Dependency") << "Dependency '" << GetName() << "' child host '" << GetChildHostName() << "' service '" << GetChildServiceName() << "' ."; m_Child = childHost->GetServiceByShortName(GetChildServiceName()); } } if (!m_Child) BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a child host/service which doesn't exist.", GetDebugInfo())); m_Child->AddDependency(this); Host::Ptr parentHost = Host::GetByName(GetParentHostName()); if (parentHost) { if (GetParentServiceName().IsEmpty()) { Log(LogDebug, "Dependency") << "Dependency '" << GetName() << "' parent host '" << GetParentHostName() << "."; m_Parent = parentHost; } else { Log(LogDebug, "Dependency") << "Dependency '" << GetName() << "' parent host '" << GetParentHostName() << "' service '" << GetParentServiceName() << "' ."; m_Parent = parentHost->GetServiceByShortName(GetParentServiceName()); } } if (!m_Parent) BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a parent host/service which doesn't exist.", GetDebugInfo())); m_Parent->AddReverseDependency(this); } void Dependency::Stop(bool runtimeRemoved) { ObjectImpl::Stop(runtimeRemoved); GetChild()->RemoveDependency(this); GetParent()->RemoveReverseDependency(this); } bool Dependency::IsAvailable(DependencyType dt) const { Checkable::Ptr parent = GetParent(); Host::Ptr parentHost; Service::Ptr parentService; tie(parentHost, parentService) = GetHostService(parent); /* ignore if it's the same checkable object */ if (parent == GetChild()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Parent and child " << (parentService ? "service" : "host") << " are identical."; return true; } /* ignore pending */ if (!parent->GetLastCheckResult()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' hasn't been checked yet."; return true; } if (GetIgnoreSoftStates()) { /* ignore soft states */ if (parent->GetStateType() == StateTypeSoft) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is in a soft state."; return true; } } else { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' failed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is in a soft state."; } int state; if (parentService) state = ServiceStateToFilter(parentService->GetState()); else state = HostStateToFilter(parentHost->GetState()); /* check state */ if (state & GetStateFilter()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' matches state filter."; return true; } /* ignore if not in time period */ TimePeriod::Ptr tp = GetPeriod(); if (tp && !tp->IsInside(Utility::GetTime())) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Outside time period."; return true; } if (dt == DependencyCheckExecution && !GetDisableChecks()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Checks are not disabled."; return true; } else if (dt == DependencyNotification && !GetDisableNotifications()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Notifications are not disabled"; return true; } Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' failed. Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is " << (parentService ? Service::StateToString(parentService->GetState()) : Host::StateToString(parentHost->GetState())); return false; } Checkable::Ptr Dependency::GetChild(void) const { return m_Child; } Checkable::Ptr Dependency::GetParent(void) const { return m_Parent; } TimePeriod::Ptr Dependency::GetPeriod(void) const { return TimePeriod::GetByName(GetPeriodRaw()); } void Dependency::ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateStates(value, utils); int sfilter = FilterArrayToInt(value, Notification::GetStateFilterMap(), 0); if (GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid for host dependency.")); if (!GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid for service dependency.")); }