mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-25 14:44:32 +02:00
Merge pull request #5264 from Icinga/feature/array-match
Implement new array match functionality fixes #5264 fixes #5263
This commit is contained in:
commit
7130e5e387
@ -16,7 +16,10 @@ Signature:
|
|||||||
|
|
||||||
function regex(pattern, text)
|
function regex(pattern, text)
|
||||||
|
|
||||||
Returns true if the regular expression matches the text, false otherwise.
|
Returns true if the regular expression matches the text, false otherwise. The mode argument is
|
||||||
|
optional and can be either MatchAll (in which case all elements for an array have to match) or MatchAny
|
||||||
|
(in which case at least one element has to match). The default mode is MatchAll.
|
||||||
|
|
||||||
**Tip**: In case you are looking for regular expression tests try [regex101](https://regex101.com).
|
**Tip**: In case you are looking for regular expression tests try [regex101](https://regex101.com).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@ -34,9 +37,11 @@ Example:
|
|||||||
|
|
||||||
Signature:
|
Signature:
|
||||||
|
|
||||||
function match(pattern, text)
|
function match(pattern, text, mode)
|
||||||
|
|
||||||
Returns true if the wildcard (`?*`) pattern matches the text, false otherwise.
|
Returns true if the wildcard (`?*`) pattern matches the text, false otherwise. The mode argument is
|
||||||
|
optional and can be either MatchAll (in which case all elements for an array have to match) or MatchAny
|
||||||
|
(in which case at least one element has to match). The default mode is MatchAll.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -59,7 +64,10 @@ Signature:
|
|||||||
|
|
||||||
Returns true if the CIDR pattern matches the IP address, false otherwise.
|
Returns true if the CIDR pattern matches the IP address, false otherwise.
|
||||||
IPv4 addresses are converted to IPv4-mapped IPv6 addresses before being
|
IPv4 addresses are converted to IPv4-mapped IPv6 addresses before being
|
||||||
matched against the pattern.
|
matched against the pattern. The mode argument is optional and can be
|
||||||
|
either MatchAll (in which case all elements for an array have to match) or MatchAny
|
||||||
|
(in which case at least one element has to match). The default mode is MatchAll.
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -1148,6 +1156,24 @@ Signature:
|
|||||||
Returns a copy of the array containing only the elements for which `func(element)`
|
Returns a copy of the array containing only the elements for which `func(element)`
|
||||||
is true.
|
is true.
|
||||||
|
|
||||||
|
### <a id="array-any"></a> Array#any
|
||||||
|
|
||||||
|
Signature:
|
||||||
|
|
||||||
|
function any(func);
|
||||||
|
|
||||||
|
Returns true if the array contains at least one element for which `func(element)`
|
||||||
|
is true, false otherwise.
|
||||||
|
|
||||||
|
### <a id="array-all"></a> Array#all
|
||||||
|
|
||||||
|
Signature:
|
||||||
|
|
||||||
|
function all(func);
|
||||||
|
|
||||||
|
Returns true if the array contains only elements for which `func(element)`
|
||||||
|
is true, false otherwise.
|
||||||
|
|
||||||
### <a id="array-unique"></a> Array#unique
|
### <a id="array-unique"></a> Array#unique
|
||||||
|
|
||||||
Signature:
|
Signature:
|
||||||
@ -1220,6 +1246,14 @@ Signature:
|
|||||||
|
|
||||||
Returns a list of keys for all items that are currently in the dictionary.
|
Returns a list of keys for all items that are currently in the dictionary.
|
||||||
|
|
||||||
|
### <a id="dictionary-keys"></a> Dictionary#values
|
||||||
|
|
||||||
|
Signature:
|
||||||
|
|
||||||
|
function values();
|
||||||
|
|
||||||
|
Returns a list of values for all items that are currently in the dictionary.
|
||||||
|
|
||||||
## <a id="scriptfunction-type"></a> Function type
|
## <a id="scriptfunction-type"></a> Function type
|
||||||
|
|
||||||
Inherits methods from the [Object type](18-library-reference.md#object-type).
|
Inherits methods from the [Object type](18-library-reference.md#object-type).
|
||||||
|
@ -207,6 +207,43 @@ static Array::Ptr ArrayFilter(const Function::Ptr& function)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ArrayAny(const Function::Ptr& function)
|
||||||
|
{
|
||||||
|
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||||
|
Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
|
||||||
|
|
||||||
|
if (vframe->Sandboxed && !function->IsSideEffectFree())
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
|
||||||
|
|
||||||
|
ObjectLock olock(self);
|
||||||
|
for (const Value& item : self) {
|
||||||
|
std::vector<Value> args;
|
||||||
|
args.push_back(item);
|
||||||
|
if (function->Invoke(args))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ArrayAll(const Function::Ptr& function)
|
||||||
|
{
|
||||||
|
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||||
|
Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
|
||||||
|
|
||||||
|
if (vframe->Sandboxed && !function->IsSideEffectFree())
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
|
||||||
|
|
||||||
|
ObjectLock olock(self);
|
||||||
|
for (const Value& item : self) {
|
||||||
|
std::vector<Value> args;
|
||||||
|
args.push_back(item);
|
||||||
|
if (!function->Invoke(args))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
static Array::Ptr ArrayUnique(void)
|
static Array::Ptr ArrayUnique(void)
|
||||||
{
|
{
|
||||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||||
@ -242,6 +279,8 @@ Object::Ptr Array::GetPrototype(void)
|
|||||||
prototype->Set("map", new Function("Array#map", WrapFunction(ArrayMap), { "func" }, true));
|
prototype->Set("map", new Function("Array#map", WrapFunction(ArrayMap), { "func" }, true));
|
||||||
prototype->Set("reduce", new Function("Array#reduce", WrapFunction(ArrayReduce), { "reduce" }, true));
|
prototype->Set("reduce", new Function("Array#reduce", WrapFunction(ArrayReduce), { "reduce" }, true));
|
||||||
prototype->Set("filter", new Function("Array#filter", WrapFunction(ArrayFilter), { "func" }, true));
|
prototype->Set("filter", new Function("Array#filter", WrapFunction(ArrayFilter), { "func" }, true));
|
||||||
|
prototype->Set("any", new Function("Array#any", WrapFunction(ArrayAny), { "func" }, true));
|
||||||
|
prototype->Set("all", new Function("Array#all", WrapFunction(ArrayAll), { "func" }, true));
|
||||||
prototype->Set("unique", new Function("Array#unique", WrapFunction(ArrayUnique), {}, true));
|
prototype->Set("unique", new Function("Array#unique", WrapFunction(ArrayUnique), {}, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,18 @@ static Array::Ptr DictionaryKeys(void)
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Array::Ptr DictionaryValues(void)
|
||||||
|
{
|
||||||
|
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||||
|
Dictionary::Ptr self = static_cast<Dictionary::Ptr>(vframe->Self);
|
||||||
|
Array::Ptr keys = new Array();
|
||||||
|
ObjectLock olock(self);
|
||||||
|
for (const Dictionary::Pair& kv : self) {
|
||||||
|
keys->Add(kv.second);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
Object::Ptr Dictionary::GetPrototype(void)
|
Object::Ptr Dictionary::GetPrototype(void)
|
||||||
{
|
{
|
||||||
static Dictionary::Ptr prototype;
|
static Dictionary::Ptr prototype;
|
||||||
@ -92,6 +104,7 @@ Object::Ptr Dictionary::GetPrototype(void)
|
|||||||
prototype->Set("contains", new Function("Dictionary#contains", WrapFunction(DictionaryContains), { "key" }, true));
|
prototype->Set("contains", new Function("Dictionary#contains", WrapFunction(DictionaryContains), { "key" }, true));
|
||||||
prototype->Set("shallow_clone", new Function("Dictionary#shallow_clone", WrapFunction(DictionaryShallowClone), {}, true));
|
prototype->Set("shallow_clone", new Function("Dictionary#shallow_clone", WrapFunction(DictionaryShallowClone), {}, true));
|
||||||
prototype->Set("keys", new Function("Dictionary#keys", WrapFunction(DictionaryKeys), {}, true));
|
prototype->Set("keys", new Function("Dictionary#keys", WrapFunction(DictionaryKeys), {}, true));
|
||||||
|
prototype->Set("values", new Function("Dictionary#values", WrapFunction(DictionaryValues), {}, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
return prototype;
|
return prototype;
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "base/configtype.hpp"
|
#include "base/configtype.hpp"
|
||||||
#include "base/application.hpp"
|
#include "base/application.hpp"
|
||||||
#include "base/dependencygraph.hpp"
|
#include "base/dependencygraph.hpp"
|
||||||
|
#include "base/initialize.hpp"
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -36,9 +37,9 @@
|
|||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, regex, &ScriptUtils::Regex, "pattern:text");
|
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, regex, &ScriptUtils::Regex, "pattern:text:mode");
|
||||||
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, match, &Utility::Match, "pattern:text");
|
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, match, &ScriptUtils::Match, "pattern:text:mode");
|
||||||
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, cidr_match, &Utility::CidrMatch, "pattern:ip");
|
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, cidr_match, &ScriptUtils::CidrMatch, "pattern:ip:mode");
|
||||||
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, len, &ScriptUtils::Len, "value");
|
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, len, &ScriptUtils::Len, "value");
|
||||||
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, union, &ScriptUtils::Union, "");
|
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, union, &ScriptUtils::Union, "");
|
||||||
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, intersection, &ScriptUtils::Intersection, "");
|
REGISTER_SAFE_SCRIPTFUNCTION_NS(System, intersection, &ScriptUtils::Intersection, "");
|
||||||
@ -67,6 +68,20 @@ REGISTER_SAFE_SCRIPTFUNCTION_NS(System, escape_create_process_arg, &Utility::Esc
|
|||||||
REGISTER_SCRIPTFUNCTION_NS(System, ptr, &ScriptUtils::Ptr, "object");
|
REGISTER_SCRIPTFUNCTION_NS(System, ptr, &ScriptUtils::Ptr, "object");
|
||||||
REGISTER_SCRIPTFUNCTION_NS(System, sleep, &Utility::Sleep, "interval");
|
REGISTER_SCRIPTFUNCTION_NS(System, sleep, &Utility::Sleep, "interval");
|
||||||
|
|
||||||
|
INITIALIZE_ONCE(&ScriptUtils::StaticInitialize);
|
||||||
|
|
||||||
|
enum MatchType
|
||||||
|
{
|
||||||
|
MatchAll,
|
||||||
|
MatchAny
|
||||||
|
};
|
||||||
|
|
||||||
|
void ScriptUtils::StaticInitialize(void)
|
||||||
|
{
|
||||||
|
ScriptGlobal::Set("MatchAll", MatchAll);
|
||||||
|
ScriptGlobal::Set("MatchAny", MatchAny);
|
||||||
|
}
|
||||||
|
|
||||||
String ScriptUtils::CastString(const Value& value)
|
String ScriptUtils::CastString(const Value& value)
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
@ -81,18 +96,120 @@ bool ScriptUtils::CastBool(const Value& value)
|
|||||||
{
|
{
|
||||||
return value.ToBool();
|
return value.ToBool();
|
||||||
}
|
}
|
||||||
bool ScriptUtils::Regex(const String& pattern, const String& text)
|
|
||||||
|
bool ScriptUtils::Regex(const std::vector<Value>& args)
|
||||||
{
|
{
|
||||||
bool res = false;
|
if (args.size() < 2)
|
||||||
try {
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Regular expression and text must be specified."));
|
||||||
boost::regex expr(pattern.GetData());
|
|
||||||
boost::smatch what;
|
Array::Ptr texts = new Array();
|
||||||
res = boost::regex_search(text.GetData(), what, expr);
|
|
||||||
} catch (boost::exception&) {
|
String pattern = args[0];
|
||||||
res = false; /* exception means something went terribly wrong */
|
Value argTexts = args[1];
|
||||||
|
MatchType mode;
|
||||||
|
|
||||||
|
if (args.size() > 2)
|
||||||
|
mode = static_cast<MatchType>(static_cast<int>(args[2]));
|
||||||
|
else
|
||||||
|
mode = MatchAll;
|
||||||
|
|
||||||
|
if (argTexts.IsObjectType<Array>())
|
||||||
|
texts = argTexts;
|
||||||
|
else {
|
||||||
|
texts = new Array();
|
||||||
|
texts->Add(argTexts);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
ObjectLock olock(texts);
|
||||||
|
for (const String& text : texts) {
|
||||||
|
bool res = false;
|
||||||
|
try {
|
||||||
|
boost::regex expr(pattern.GetData());
|
||||||
|
boost::smatch what;
|
||||||
|
res = boost::regex_search(text.GetData(), what, expr);
|
||||||
|
} catch (boost::exception&) {
|
||||||
|
res = false; /* exception means something went terribly wrong */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == MatchAny && res)
|
||||||
|
return true;
|
||||||
|
else if (mode == MatchAll && !res)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mode == MatchAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptUtils::Match(const std::vector<Value>& args)
|
||||||
|
{
|
||||||
|
if (args.size() < 2)
|
||||||
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Pattern and text must be specified."));
|
||||||
|
|
||||||
|
Array::Ptr texts = new Array();
|
||||||
|
|
||||||
|
String pattern = args[0];
|
||||||
|
Value argTexts = args[1];
|
||||||
|
MatchType mode;
|
||||||
|
|
||||||
|
if (args.size() > 2)
|
||||||
|
mode = static_cast<MatchType>(static_cast<int>(args[2]));
|
||||||
|
else
|
||||||
|
mode = MatchAll;
|
||||||
|
|
||||||
|
if (argTexts.IsObjectType<Array>())
|
||||||
|
texts = argTexts;
|
||||||
|
else {
|
||||||
|
texts = new Array();
|
||||||
|
texts->Add(argTexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectLock olock(texts);
|
||||||
|
for (const String& text : texts) {
|
||||||
|
bool res = Utility::Match(pattern, text);
|
||||||
|
|
||||||
|
if (mode == MatchAny && res)
|
||||||
|
return true;
|
||||||
|
else if (mode == MatchAll && !res)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mode == MatchAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptUtils::CidrMatch(const std::vector<Value>& args)
|
||||||
|
{
|
||||||
|
if (args.size() < 2)
|
||||||
|
BOOST_THROW_EXCEPTION(std::invalid_argument("CIDR and IP address must be specified."));
|
||||||
|
|
||||||
|
Array::Ptr ips = new Array();
|
||||||
|
|
||||||
|
String pattern = args[0];
|
||||||
|
Value argIps = args[1];
|
||||||
|
MatchType mode;
|
||||||
|
|
||||||
|
if (args.size() > 2)
|
||||||
|
mode = static_cast<MatchType>(static_cast<int>(args[2]));
|
||||||
|
else
|
||||||
|
mode = MatchAll;
|
||||||
|
|
||||||
|
if (argIps.IsObjectType<Array>())
|
||||||
|
ips = argIps;
|
||||||
|
else {
|
||||||
|
ips = new Array();
|
||||||
|
ips->Add(argIps);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectLock olock(ips);
|
||||||
|
for (const String& ip : ips) {
|
||||||
|
bool res = Utility::CidrMatch(pattern, ip);
|
||||||
|
|
||||||
|
if (mode == MatchAny && res)
|
||||||
|
return true;
|
||||||
|
else if (mode == MatchAll && !res)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mode == MatchAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ScriptUtils::Len(const Value& value)
|
double ScriptUtils::Len(const Value& value)
|
||||||
|
@ -36,10 +36,13 @@ namespace icinga
|
|||||||
class I2_BASE_API ScriptUtils
|
class I2_BASE_API ScriptUtils
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static void StaticInitialize(void);
|
||||||
static String CastString(const Value& value);
|
static String CastString(const Value& value);
|
||||||
static double CastNumber(const Value& value);
|
static double CastNumber(const Value& value);
|
||||||
static bool CastBool(const Value& value);
|
static bool CastBool(const Value& value);
|
||||||
static bool Regex(const String& pattern, const String& text);
|
static bool Regex(const std::vector<Value>& args);
|
||||||
|
static bool Match(const std::vector<Value>& args);
|
||||||
|
static bool CidrMatch(const std::vector<Value>& args);
|
||||||
static double Len(const Value& value);
|
static double Len(const Value& value);
|
||||||
static Array::Ptr Union(const std::vector<Value>& arguments);
|
static Array::Ptr Union(const std::vector<Value>& arguments);
|
||||||
static Array::Ptr Intersection(const std::vector<Value>& arguments);
|
static Array::Ptr Intersection(const std::vector<Value>& arguments);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user