]> granicus.if.org Git - icinga2/commitdiff
Add 'mode' argument for match, regex and cidr_match 5264/head
authorGunnar Beutner <gunnar.beutner@icinga.com>
Mon, 15 May 2017 14:02:20 +0000 (16:02 +0200)
committerGunnar Beutner <gunnar.beutner@icinga.com>
Tue, 16 May 2017 11:22:10 +0000 (13:22 +0200)
doc/18-library-reference.md
lib/base/scriptutils.cpp
lib/base/scriptutils.hpp

index 2dd41d69f7b68c3d49fba2d4f36f45de0f61b20b..4c82ab4c1611fff0fd33fa9155b298b251c5144a 100644 (file)
@@ -16,7 +16,10 @@ Signature:
 
     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).
 
 Example:
@@ -34,9 +37,11 @@ Example:
 
 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:
 
@@ -59,7 +64,10 @@ Signature:
 
 Returns true if the CIDR pattern matches the IP address, false otherwise.
 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:
 
index 9cbdc1c5f2e9bf5bffc9273a753c177358827dcb..ef70eccbf8ba62997e06d5865d2a1c2d99f0ec56 100644 (file)
@@ -27,6 +27,7 @@
 #include "base/configtype.hpp"
 #include "base/application.hpp"
 #include "base/dependencygraph.hpp"
+#include "base/initialize.hpp"
 #include <boost/regex.hpp>
 #include <algorithm>
 #include <set>
@@ -36,9 +37,9 @@
 
 using namespace icinga;
 
-REGISTER_SAFE_SCRIPTFUNCTION_NS(System, regex, &ScriptUtils::Regex, "pattern:text");
-REGISTER_SAFE_SCRIPTFUNCTION_NS(System, match, &Utility::Match, "pattern:text");
-REGISTER_SAFE_SCRIPTFUNCTION_NS(System, cidr_match, &Utility::CidrMatch, "pattern:ip");
+REGISTER_SAFE_SCRIPTFUNCTION_NS(System, regex, &ScriptUtils::Regex, "pattern:text:mode");
+REGISTER_SAFE_SCRIPTFUNCTION_NS(System, match, &ScriptUtils::Match, "pattern:text:mode");
+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, union, &ScriptUtils::Union, "");
 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, 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)
 {
        return value;
@@ -81,18 +96,120 @@ bool ScriptUtils::CastBool(const Value& value)
 {
        return value.ToBool();
 }
-bool ScriptUtils::Regex(const String& pattern, const String& text)
+
+bool ScriptUtils::Regex(const std::vector<Value>& args)
+{
+       if (args.size() < 2)
+               BOOST_THROW_EXCEPTION(std::invalid_argument("Regular expression 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 = 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)
 {
-       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 (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 res;
+       return mode == MatchAll;
 }
 
 double ScriptUtils::Len(const Value& value)
index fd4333241b68748b949f6947f040b082d011e5a7..e605be5faa4f46b30956009a4b5d25a7f7bb5a31 100644 (file)
@@ -36,10 +36,13 @@ namespace icinga
 class I2_BASE_API ScriptUtils
 {
 public:
+       static void StaticInitialize(void);
        static String CastString(const Value& value);
        static double CastNumber(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 Array::Ptr Union(const std::vector<Value>& arguments);
        static Array::Ptr Intersection(const std::vector<Value>& arguments);