/* Icinga 2 | (c) 2022 Icinga GmbH | GPLv2+ */ #include "base/string.hpp" #include "config/applyrule.hpp" #include "config/expression.hpp" #include #include using namespace icinga; /** * @returns All ApplyRules targeting only specific parent objects including the given host. (See AddTargetedRule().) */ const std::set& ApplyRule::GetTargetedHostRules(const Type::Ptr& sourceType, const String& host) { auto perSourceType (m_Rules.find(sourceType.get())); if (perSourceType != m_Rules.end()) { auto perHost (perSourceType->second.Targeted.find(host)); if (perHost != perSourceType->second.Targeted.end()) { return perHost->second.ForHost; } } static const std::set noRules; return noRules; } /** * @returns All ApplyRules targeting only specific parent objects including the given service. (See AddTargetedRule().) */ const std::set& ApplyRule::GetTargetedServiceRules(const Type::Ptr& sourceType, const String& host, const String& service) { auto perSourceType (m_Rules.find(sourceType.get())); if (perSourceType != m_Rules.end()) { auto perHost (perSourceType->second.Targeted.find(host)); if (perHost != perSourceType->second.Targeted.end()) { auto perService (perHost->second.ForServices.find(service)); if (perService != perHost->second.ForServices.end()) { return perService->second; } } } static const std::set noRules; return noRules; } /** * If the given ApplyRule targets only specific parent objects, add it to the respective "index". * * - The above means for apply T "N" to Host: assign where host.name == "H" [ || host.name == "h" ... ] * - For apply T "N" to Service it means: assign where host.name == "H" && service.name == "S" [ || host.name == "h" && service.name == "s" ... ] * * The order of operands of || && == doesn't matter. * * @returns Whether the rule has been added to the "index". */ bool ApplyRule::AddTargetedRule(const ApplyRule::Ptr& rule, const String& targetType, ApplyRule::PerSourceType& rules) { if (targetType == "Host") { std::vector hosts; if (GetTargetHosts(rule->m_Filter.get(), hosts)) { for (auto host : hosts) { rules.Targeted[*host].ForHost.emplace(rule); } return true; } } else if (targetType == "Service") { std::vector> services; if (GetTargetServices(rule->m_Filter.get(), services)) { for (auto service : services) { rules.Targeted[*service.first].ForServices[*service.second].emplace(rule); } return true; } } return false; } /** * If the given assign filter is like the following, extract the host names ("H", "h", ...) into the vector: * * host.name == "H" [ || host.name == "h" ... ] * * The order of operands of || == doesn't matter. * * @returns Whether the given assign filter is like above. */ bool ApplyRule::GetTargetHosts(Expression* assignFilter, std::vector& hosts, const Dictionary::Ptr& constants) { auto lor (dynamic_cast(assignFilter)); if (lor) { return GetTargetHosts(lor->GetOperand1().get(), hosts, constants) && GetTargetHosts(lor->GetOperand2().get(), hosts, constants); } auto name (GetComparedName(assignFilter, "host", constants)); if (name) { hosts.emplace_back(name); return true; } return false; } /** * If the given assign filter is like the following, extract the host+service names ("H"+"S", "h"+"s", ...) into the vector: * * host.name == "H" && service.name == "S" [ || host.name == "h" && service.name == "s" ... ] * * The order of operands of || && == doesn't matter. * * @returns Whether the given assign filter is like above. */ bool ApplyRule::GetTargetServices(Expression* assignFilter, std::vector>& services, const Dictionary::Ptr& constants) { auto lor (dynamic_cast(assignFilter)); if (lor) { return GetTargetServices(lor->GetOperand1().get(), services, constants) && GetTargetServices(lor->GetOperand2().get(), services, constants); } auto service (GetTargetService(assignFilter, constants)); if (service.first) { services.emplace_back(service); return true; } return false; } /** * If the given filter is like the following, extract the host+service names ("H"+"S"): * * host.name == "H" && service.name == "S" * * The order of operands of && == doesn't matter. * * @returns {host, service} on success and {nullptr, nullptr} on failure. */ std::pair ApplyRule::GetTargetService(Expression* assignFilter, const Dictionary::Ptr& constants) { auto land (dynamic_cast(assignFilter)); if (!land) { return {nullptr, nullptr}; } auto op1 (land->GetOperand1().get()); auto op2 (land->GetOperand2().get()); auto host (GetComparedName(op1, "host", constants)); if (!host) { std::swap(op1, op2); host = GetComparedName(op1, "host", constants); } if (host) { auto service (GetComparedName(op2, "service", constants)); if (service) { return {host, service}; } } return {nullptr, nullptr}; } /** * If the given filter is like the following, extract the object name ("N"): * * $lcType$.name == "N" * * The order of operands of == doesn't matter. * * @returns The object name on success and nullptr on failure. */ const String * ApplyRule::GetComparedName(Expression* assignFilter, const char * lcType, const Dictionary::Ptr& constants) { auto eq (dynamic_cast(assignFilter)); if (!eq) { return nullptr; } auto op1 (eq->GetOperand1().get()); auto op2 (eq->GetOperand2().get()); if (IsNameIndexer(op1, lcType, constants)) { return GetConstString(op2, constants); } if (IsNameIndexer(op2, lcType, constants)) { return GetConstString(op1, constants); } return nullptr; } /** * @returns Whether the given expression is like $lcType$.name. */ bool ApplyRule::IsNameIndexer(Expression* exp, const char * lcType, const Dictionary::Ptr& constants) { auto ixr (dynamic_cast(exp)); if (!ixr) { return false; } auto var (dynamic_cast(ixr->GetOperand1().get())); if (!var || var->GetVariable() != lcType) { return false; } auto val (GetConstString(ixr->GetOperand2().get(), constants)); return val && *val == "name"; } /** * @returns If the given expression is a constant string, its address. nullptr on failure. */ const String * ApplyRule::GetConstString(Expression* exp, const Dictionary::Ptr& constants) { auto cnst (GetConst(exp, constants)); return cnst && cnst->IsString() ? &cnst->Get() : nullptr; } /** * @returns If the given expression is a constant, its address. nullptr on failure. */ const Value * ApplyRule::GetConst(Expression* exp, const Dictionary::Ptr& constants) { auto lit (dynamic_cast(exp)); if (lit) { return &lit->GetValue(); } if (constants) { auto var (dynamic_cast(exp)); if (var) { return constants->GetRef(var->GetVariable()); } } return nullptr; }