2022-10-18 16:48:58 +02:00
|
|
|
/* 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().)
|
|
|
|
*/
|
2022-11-04 10:15:22 +01:00
|
|
|
const std::set<ApplyRule::Ptr>& ApplyRule::GetTargetedHostRules(const Type::Ptr& sourceType, const String& host)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
auto perSourceType (m_Rules.find(sourceType.get()));
|
|
|
|
|
|
|
|
if (perSourceType != m_Rules.end()) {
|
2022-10-28 12:41:21 +02:00
|
|
|
auto perHost (perSourceType->second.Targeted.find(host));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
2022-10-28 12:41:21 +02:00
|
|
|
if (perHost != perSourceType->second.Targeted.end()) {
|
|
|
|
return perHost->second.ForHost;
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-04 10:15:22 +01:00
|
|
|
static const std::set<ApplyRule::Ptr> noRules;
|
2022-10-18 16:48:58 +02:00
|
|
|
return noRules;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns All ApplyRules targeting only specific parent objects including the given service. (See AddTargetedRule().)
|
|
|
|
*/
|
2022-11-04 10:15:22 +01:00
|
|
|
const std::set<ApplyRule::Ptr>& ApplyRule::GetTargetedServiceRules(const Type::Ptr& sourceType, const String& host, const String& service)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
auto perSourceType (m_Rules.find(sourceType.get()));
|
|
|
|
|
|
|
|
if (perSourceType != m_Rules.end()) {
|
2022-10-28 12:41:21 +02:00
|
|
|
auto perHost (perSourceType->second.Targeted.find(host));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
2022-10-28 12:41:21 +02:00
|
|
|
if (perHost != perSourceType->second.Targeted.end()) {
|
|
|
|
auto perService (perHost->second.ForServices.find(service));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
2022-10-28 12:41:21 +02:00
|
|
|
if (perService != perHost->second.ForServices.end()) {
|
|
|
|
return perService->second;
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-04 10:15:22 +01:00
|
|
|
static const std::set<ApplyRule::Ptr> noRules;
|
2022-10-18 16:48:58 +02:00
|
|
|
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".
|
|
|
|
*/
|
2022-10-28 12:41:21 +02:00
|
|
|
bool ApplyRule::AddTargetedRule(const ApplyRule::Ptr& rule, const String& targetType, ApplyRule::PerSourceType& rules)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
if (targetType == "Host") {
|
|
|
|
std::vector<const String *> hosts;
|
|
|
|
|
2022-10-27 16:54:09 +02:00
|
|
|
if (GetTargetHosts(rule->m_Filter.get(), hosts)) {
|
2022-10-18 16:48:58 +02:00
|
|
|
for (auto host : hosts) {
|
2022-11-04 10:15:22 +01:00
|
|
|
rules.Targeted[*host].ForHost.emplace(rule);
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (targetType == "Service") {
|
|
|
|
std::vector<std::pair<const String *, const String *>> services;
|
|
|
|
|
2022-10-27 16:54:09 +02:00
|
|
|
if (GetTargetServices(rule->m_Filter.get(), services)) {
|
2022-10-18 16:48:58 +02:00
|
|
|
for (auto service : services) {
|
2022-11-04 10:15:22 +01:00
|
|
|
rules.Targeted[*service.first].ForServices[*service.second].emplace(rule);
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2023-11-21 14:36:32 +01:00
|
|
|
bool ApplyRule::GetTargetHosts(Expression* assignFilter, std::vector<const String *>& hosts, const Dictionary::Ptr& constants)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
auto lor (dynamic_cast<LogicalOrExpression*>(assignFilter));
|
|
|
|
|
|
|
|
if (lor) {
|
2023-11-21 14:36:32 +01:00
|
|
|
return GetTargetHosts(lor->GetOperand1().get(), hosts, constants)
|
|
|
|
&& GetTargetHosts(lor->GetOperand2().get(), hosts, constants);
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
auto name (GetComparedName(assignFilter, "host", constants));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2023-11-21 14:36:32 +01:00
|
|
|
bool ApplyRule::GetTargetServices(Expression* assignFilter, std::vector<std::pair<const String *, const String *>>& services, const Dictionary::Ptr& constants)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
auto lor (dynamic_cast<LogicalOrExpression*>(assignFilter));
|
|
|
|
|
|
|
|
if (lor) {
|
2023-11-21 14:36:32 +01:00
|
|
|
return GetTargetServices(lor->GetOperand1().get(), services, constants)
|
|
|
|
&& GetTargetServices(lor->GetOperand2().get(), services, constants);
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
auto service (GetTargetService(assignFilter, constants));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2023-11-21 14:36:32 +01:00
|
|
|
std::pair<const String *, const String *> ApplyRule::GetTargetService(Expression* assignFilter, const Dictionary::Ptr& constants)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
auto land (dynamic_cast<LogicalAndExpression*>(assignFilter));
|
|
|
|
|
|
|
|
if (!land) {
|
|
|
|
return {nullptr, nullptr};
|
|
|
|
}
|
|
|
|
|
|
|
|
auto op1 (land->GetOperand1().get());
|
|
|
|
auto op2 (land->GetOperand2().get());
|
2023-11-21 14:36:32 +01:00
|
|
|
auto host (GetComparedName(op1, "host", constants));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
|
|
|
if (!host) {
|
|
|
|
std::swap(op1, op2);
|
2023-11-21 14:36:32 +01:00
|
|
|
host = GetComparedName(op1, "host", constants);
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (host) {
|
2023-11-21 14:36:32 +01:00
|
|
|
auto service (GetComparedName(op2, "service", constants));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2023-11-21 14:36:32 +01:00
|
|
|
const String * ApplyRule::GetComparedName(Expression* assignFilter, const char * lcType, const Dictionary::Ptr& constants)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
auto eq (dynamic_cast<EqualExpression*>(assignFilter));
|
|
|
|
|
|
|
|
if (!eq) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto op1 (eq->GetOperand1().get());
|
|
|
|
auto op2 (eq->GetOperand2().get());
|
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
if (IsNameIndexer(op1, lcType, constants)) {
|
|
|
|
return GetConstString(op2, constants);
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
if (IsNameIndexer(op2, lcType, constants)) {
|
|
|
|
return GetConstString(op1, constants);
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns Whether the given expression is like $lcType$.name.
|
|
|
|
*/
|
2023-11-21 14:36:32 +01:00
|
|
|
bool ApplyRule::IsNameIndexer(Expression* exp, const char * lcType, const Dictionary::Ptr& constants)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
auto val (GetConstString(ixr->GetOperand2().get(), constants));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
|
|
|
return val && *val == "name";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-11-21 14:36:32 +01:00
|
|
|
* @returns If the given expression is a constant string, its address. nullptr on failure.
|
2022-10-18 16:48:58 +02:00
|
|
|
*/
|
2023-11-21 14:36:32 +01:00
|
|
|
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)
|
2022-10-18 16:48:58 +02:00
|
|
|
{
|
|
|
|
auto lit (dynamic_cast<LiteralExpression*>(exp));
|
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
if (lit) {
|
|
|
|
return &lit->GetValue();
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
if (constants) {
|
|
|
|
auto var (dynamic_cast<VariableExpression*>(exp));
|
2022-10-18 16:48:58 +02:00
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
if (var) {
|
|
|
|
return constants->GetRef(var->GetVariable());
|
|
|
|
}
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|
|
|
|
|
2023-11-21 14:36:32 +01:00
|
|
|
return nullptr;
|
2022-10-18 16:48:58 +02:00
|
|
|
}
|