diff options
Diffstat (limited to '')
-rw-r--r-- | lib/config/applyrule-targeted.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/lib/config/applyrule-targeted.cpp b/lib/config/applyrule-targeted.cpp new file mode 100644 index 0000000..c5bfe20 --- /dev/null +++ b/lib/config/applyrule-targeted.cpp @@ -0,0 +1,266 @@ +/* Icinga 2 | (c) 2022 Icinga GmbH | GPLv2+ */ + +#include "base/string.hpp" +#include "config/applyrule.hpp" +#include "config/expression.hpp" +#include <utility> +#include <vector> + +using namespace icinga; + +/** + * @returns All ApplyRules targeting only specific parent objects including the given host. (See AddTargetedRule().) + */ +const std::set<ApplyRule::Ptr>& 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<ApplyRule::Ptr> noRules; + return noRules; +} + +/** + * @returns All ApplyRules targeting only specific parent objects including the given service. (See AddTargetedRule().) + */ +const std::set<ApplyRule::Ptr>& 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<ApplyRule::Ptr> 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<const String *> 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<std::pair<const String *, const String *>> 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<const String *>& hosts, const Dictionary::Ptr& constants) +{ + auto lor (dynamic_cast<LogicalOrExpression*>(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<std::pair<const String *, const String *>>& services, const Dictionary::Ptr& constants) +{ + auto lor (dynamic_cast<LogicalOrExpression*>(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<const String *, const String *> ApplyRule::GetTargetService(Expression* assignFilter, const Dictionary::Ptr& constants) +{ + auto land (dynamic_cast<LogicalAndExpression*>(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<EqualExpression*>(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<IndexerExpression*>(exp)); + + if (!ixr) { + return false; + } + + auto var (dynamic_cast<VariableExpression*>(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<String>() : 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<LiteralExpression*>(exp)); + + if (lit) { + return &lit->GetValue(); + } + + if (constants) { + auto var (dynamic_cast<VariableExpression*>(exp)); + + if (var) { + return constants->GetRef(var->GetVariable()); + } + } + + return nullptr; +} |