mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-14 09:14:29 +02:00
Add macro config validator for command args, env, custom attr, perfdata templates
fixes #7311
This commit is contained in:
parent
477f7a713c
commit
8ca57cba03
@ -1256,3 +1256,23 @@ String Utility::UnescapeString(const String& s)
|
|||||||
|
|
||||||
return result.str();
|
return result.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Utility::ValidateMacroString(const String& macro)
|
||||||
|
{
|
||||||
|
if (macro.IsEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
size_t pos_first, pos_second, offset;
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
while((pos_first = macro.FindFirstOf("$", offset)) != String::NPos) {
|
||||||
|
pos_second = macro.FindFirstOf("$", pos_first + 1);
|
||||||
|
|
||||||
|
if (pos_second == String::NPos)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
offset = pos_second + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -118,6 +118,8 @@ public:
|
|||||||
static String EscapeString(const String& s, const String& chars);
|
static String EscapeString(const String& s, const String& chars);
|
||||||
static String UnescapeString(const String& s);
|
static String UnescapeString(const String& s);
|
||||||
|
|
||||||
|
static bool ValidateMacroString(const String& macro);
|
||||||
|
|
||||||
static void SetThreadName(const String& name, bool os = true);
|
static void SetThreadName(const String& name, bool os = true);
|
||||||
static String GetThreadName(void);
|
static String GetThreadName(void);
|
||||||
|
|
||||||
|
@ -20,11 +20,15 @@
|
|||||||
#include "icinga/command.hpp"
|
#include "icinga/command.hpp"
|
||||||
#include "base/function.hpp"
|
#include "base/function.hpp"
|
||||||
#include "base/exception.hpp"
|
#include "base/exception.hpp"
|
||||||
|
#include "base/objectlock.hpp"
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
REGISTER_TYPE(Command);
|
REGISTER_TYPE(Command);
|
||||||
REGISTER_SCRIPTFUNCTION(ValidateCommandAttributes, &Command::ValidateAttributes);
|
REGISTER_SCRIPTFUNCTION(ValidateCommandAttributes, &Command::ValidateAttributes);
|
||||||
|
REGISTER_SCRIPTFUNCTION(ValidateCommandArguments, &Command::ValidateArguments);
|
||||||
|
REGISTER_SCRIPTFUNCTION(ValidateEnvironmentVariables, &Command::ValidateEnvironmentVariables);
|
||||||
|
|
||||||
int Command::GetModifiedAttributes(void) const
|
int Command::GetModifiedAttributes(void) const
|
||||||
{
|
{
|
||||||
@ -52,3 +56,55 @@ void Command::ValidateAttributes(const String& location, const Command::Ptr& obj
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Command::ValidateArguments(const String& location, const Command::Ptr& object)
|
||||||
|
{
|
||||||
|
Dictionary::Ptr arguments = object->GetArguments();
|
||||||
|
|
||||||
|
if (!arguments)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ObjectLock olock(arguments);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, arguments) {
|
||||||
|
const Value& arginfo = kv.second;
|
||||||
|
Value argval;
|
||||||
|
|
||||||
|
if (arginfo.IsObjectType<Dictionary>()) {
|
||||||
|
Dictionary::Ptr argdict = arginfo;
|
||||||
|
|
||||||
|
if (argdict->Contains("value"))
|
||||||
|
argval = argdict->Get("value");
|
||||||
|
} else
|
||||||
|
argval = arginfo;
|
||||||
|
|
||||||
|
if (argval.IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String argstr = argval;
|
||||||
|
|
||||||
|
if(!Utility::ValidateMacroString(argstr)) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + argstr + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Command::ValidateEnvironmentVariables(const String& location, const Command::Ptr& object)
|
||||||
|
{
|
||||||
|
Dictionary::Ptr env = object->GetEnv();
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ObjectLock olock(env);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, env) {
|
||||||
|
const Value& envval = kv.second;
|
||||||
|
|
||||||
|
if (!envval.IsString() || envval.IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!Utility::ValidateMacroString(envval)) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + envval + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -40,6 +40,8 @@ public:
|
|||||||
//virtual Dictionary::Ptr Execute(const Object::Ptr& context) = 0;
|
//virtual Dictionary::Ptr Execute(const Object::Ptr& context) = 0;
|
||||||
|
|
||||||
static void ValidateAttributes(const String& location, const Command::Ptr& object);
|
static void ValidateAttributes(const String& location, const Command::Ptr& object);
|
||||||
|
static void ValidateArguments(const String& location, const Command::Ptr& object);
|
||||||
|
static void ValidateEnvironmentVariables(const String& location, const Command::Ptr& object);
|
||||||
|
|
||||||
int GetModifiedAttributes(void) const;
|
int GetModifiedAttributes(void) const;
|
||||||
void SetModifiedAttributes(int flags, const MessageOrigin& origin = MessageOrigin());
|
void SetModifiedAttributes(int flags, const MessageOrigin& origin = MessageOrigin());
|
||||||
|
@ -19,10 +19,15 @@
|
|||||||
|
|
||||||
#include "icinga/customvarobject.hpp"
|
#include "icinga/customvarobject.hpp"
|
||||||
#include "base/logger.hpp"
|
#include "base/logger.hpp"
|
||||||
|
#include "base/function.hpp"
|
||||||
|
#include "base/exception.hpp"
|
||||||
|
#include "base/objectlock.hpp"
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
REGISTER_TYPE(CustomVarObject);
|
REGISTER_TYPE(CustomVarObject);
|
||||||
|
REGISTER_SCRIPTFUNCTION(ValidateCustomAttributes, &CustomVarObject::ValidateCustomAttributes);
|
||||||
|
|
||||||
boost::signals2::signal<void (const CustomVarObject::Ptr&, const Dictionary::Ptr& vars, const MessageOrigin&)> CustomVarObject::OnVarsChanged;
|
boost::signals2::signal<void (const CustomVarObject::Ptr&, const Dictionary::Ptr& vars, const MessageOrigin&)> CustomVarObject::OnVarsChanged;
|
||||||
|
|
||||||
@ -61,3 +66,57 @@ bool CustomVarObject::IsVarOverridden(const String& name) const
|
|||||||
|
|
||||||
return vars_override->Contains(name);
|
return vars_override->Contains(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CustomVarObject::ValidateCustomAttributes(const String& location, const CustomVarObject::Ptr& object)
|
||||||
|
{
|
||||||
|
Dictionary::Ptr vars = object->GetVars();
|
||||||
|
|
||||||
|
if (!vars)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* string, array, dictionary */
|
||||||
|
ObjectLock olock(vars);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, vars) {
|
||||||
|
const Value& varval = kv.second;
|
||||||
|
|
||||||
|
if (varval.IsObjectType<Dictionary>()) {
|
||||||
|
/* only one dictonary level */
|
||||||
|
Dictionary::Ptr varval_dict = varval;
|
||||||
|
|
||||||
|
ObjectLock xlock(varval_dict);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv_var, varval_dict) {
|
||||||
|
if(kv_var.second.IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!Utility::ValidateMacroString(kv_var.second)) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + kv_var.second + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (varval.IsObjectType<Array>()) {
|
||||||
|
/* check all array entries */
|
||||||
|
Array::Ptr varval_arr = varval;
|
||||||
|
|
||||||
|
ObjectLock ylock (varval_arr);
|
||||||
|
BOOST_FOREACH(const Value& arrval, varval_arr) {
|
||||||
|
if (arrval.IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!Utility::ValidateMacroString(arrval)) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + arrval + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (varval.IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String varstr = varval;
|
||||||
|
|
||||||
|
if(!Utility::ValidateMacroString(varstr)) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + varstr + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -61,6 +61,8 @@ public:
|
|||||||
|
|
||||||
static boost::signals2::signal<void (const CustomVarObject::Ptr&, const Dictionary::Ptr& vars, const MessageOrigin&)> OnVarsChanged;
|
static boost::signals2::signal<void (const CustomVarObject::Ptr&, const Dictionary::Ptr& vars, const MessageOrigin&)> OnVarsChanged;
|
||||||
|
|
||||||
|
static void ValidateCustomAttributes(const String& location, const CustomVarObject::Ptr& object);
|
||||||
|
|
||||||
Dictionary::Ptr GetVars(void) const;
|
Dictionary::Ptr GetVars(void) const;
|
||||||
void SetVars(const Dictionary::Ptr& vars, const MessageOrigin& origin = MessageOrigin());
|
void SetVars(const Dictionary::Ptr& vars, const MessageOrigin& origin = MessageOrigin());
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
%type CustomVarObject {
|
%type CustomVarObject {
|
||||||
|
%validator "ValidateCustomAttributes",
|
||||||
%attribute %dictionary "vars",
|
%attribute %dictionary "vars",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,6 +194,8 @@
|
|||||||
|
|
||||||
%type Command %inherits CustomVarObject {
|
%type Command %inherits CustomVarObject {
|
||||||
%validator "ValidateCommandAttributes",
|
%validator "ValidateCommandAttributes",
|
||||||
|
%validator "ValidateCommandArguments",
|
||||||
|
%validator "ValidateEnvironmentVariables",
|
||||||
|
|
||||||
%require "execute",
|
%require "execute",
|
||||||
%attribute %function "execute",
|
%attribute %function "execute",
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
REGISTER_TYPE(GraphiteWriter);
|
REGISTER_TYPE(GraphiteWriter);
|
||||||
|
REGISTER_SCRIPTFUNCTION(ValidateNameTemplates, &GraphiteWriter::ValidateNameTemplates);
|
||||||
|
|
||||||
REGISTER_STATSFUNCTION(GraphiteWriterStats, &GraphiteWriter::StatsFunc);
|
REGISTER_STATSFUNCTION(GraphiteWriterStats, &GraphiteWriter::StatsFunc);
|
||||||
|
|
||||||
@ -146,7 +147,7 @@ void GraphiteWriter::SendPerfdata(const String& prefix, const CheckResult::Ptr&
|
|||||||
ObjectLock olock(perfdata);
|
ObjectLock olock(perfdata);
|
||||||
BOOST_FOREACH(const Value& val, perfdata) {
|
BOOST_FOREACH(const Value& val, perfdata) {
|
||||||
PerfdataValue::Ptr pdv;
|
PerfdataValue::Ptr pdv;
|
||||||
|
|
||||||
if (val.IsObjectType<PerfdataValue>())
|
if (val.IsObjectType<PerfdataValue>())
|
||||||
pdv = val;
|
pdv = val;
|
||||||
else {
|
else {
|
||||||
@ -158,7 +159,7 @@ void GraphiteWriter::SendPerfdata(const String& prefix, const CheckResult::Ptr&
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String escaped_key = EscapeMetric(pdv->GetLabel());
|
String escaped_key = EscapeMetric(pdv->GetLabel());
|
||||||
boost::algorithm::replace_all(escaped_key, "::", ".");
|
boost::algorithm::replace_all(escaped_key, "::", ".");
|
||||||
|
|
||||||
@ -230,3 +231,15 @@ Value GraphiteWriter::EscapeMacroMetric(const Value& value)
|
|||||||
} else
|
} else
|
||||||
return EscapeMetric(value);
|
return EscapeMetric(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphiteWriter::ValidateNameTemplates(const String& location, const GraphiteWriter::Ptr& object)
|
||||||
|
{
|
||||||
|
if(!Utility::ValidateMacroString(object->GetHostNameTemplate())) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + object->GetHostNameTemplate() + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
if (!Utility::ValidateMacroString(object->GetServiceNameTemplate())) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + object->GetServiceNameTemplate() + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,6 +43,8 @@ public:
|
|||||||
|
|
||||||
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
|
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
|
||||||
|
|
||||||
|
static void ValidateNameTemplates(const String& location, const GraphiteWriter::Ptr& object);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Start(void);
|
virtual void Start(void);
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
%type PerfdataWriter {
|
%type PerfdataWriter {
|
||||||
|
%validator "ValidateFormatTemplates",
|
||||||
|
|
||||||
%attribute %string "host_perfdata_path",
|
%attribute %string "host_perfdata_path",
|
||||||
%attribute %string "service_perfdata_path",
|
%attribute %string "service_perfdata_path",
|
||||||
%attribute %string "host_temp_path",
|
%attribute %string "host_temp_path",
|
||||||
@ -28,6 +30,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
%type GraphiteWriter {
|
%type GraphiteWriter {
|
||||||
|
%validator "ValidateNameTemplates",
|
||||||
|
|
||||||
%attribute %string "host",
|
%attribute %string "host",
|
||||||
%attribute %string "port",
|
%attribute %string "port",
|
||||||
%attribute %string "host_name_template",
|
%attribute %string "host_name_template",
|
||||||
@ -44,4 +48,3 @@
|
|||||||
%attribute %string "host",
|
%attribute %string "host",
|
||||||
%attribute %string "port",
|
%attribute %string "port",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,12 +27,14 @@
|
|||||||
#include "base/convert.hpp"
|
#include "base/convert.hpp"
|
||||||
#include "base/utility.hpp"
|
#include "base/utility.hpp"
|
||||||
#include "base/context.hpp"
|
#include "base/context.hpp"
|
||||||
|
#include "base/exception.hpp"
|
||||||
#include "base/application.hpp"
|
#include "base/application.hpp"
|
||||||
#include "base/statsfunction.hpp"
|
#include "base/statsfunction.hpp"
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
REGISTER_TYPE(PerfdataWriter);
|
REGISTER_TYPE(PerfdataWriter);
|
||||||
|
REGISTER_SCRIPTFUNCTION(ValidateFormatTemplates, &PerfdataWriter::ValidateFormatTemplates);
|
||||||
|
|
||||||
REGISTER_STATSFUNCTION(PerfdataWriterStats, &PerfdataWriter::StatsFunc);
|
REGISTER_STATSFUNCTION(PerfdataWriterStats, &PerfdataWriter::StatsFunc);
|
||||||
|
|
||||||
@ -138,3 +140,14 @@ void PerfdataWriter::RotationTimerHandler(void)
|
|||||||
RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath());
|
RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PerfdataWriter::ValidateFormatTemplates(const String& location, const PerfdataWriter::Ptr& object)
|
||||||
|
{
|
||||||
|
if(!Utility::ValidateMacroString(object->GetHostFormatTemplate())) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + object->GetHostFormatTemplate() + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
if (!Utility::ValidateMacroString(object->GetServiceFormatTemplate())) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
|
||||||
|
location + ": Closing $ not found in macro format string '" + object->GetHostFormatTemplate() + "'.", object->GetDebugInfo()));
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,8 @@ public:
|
|||||||
|
|
||||||
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
|
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
|
||||||
|
|
||||||
|
static void ValidateFormatTemplates(const String& location, const PerfdataWriter::Ptr& object);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Start(void);
|
virtual void Start(void);
|
||||||
|
|
||||||
|
@ -51,6 +51,17 @@ BOOST_AUTO_TEST_CASE(simple)
|
|||||||
Array::Ptr result = MacroProcessor::ResolveMacros("$testD$", resolvers);
|
Array::Ptr result = MacroProcessor::ResolveMacros("$testD$", resolvers);
|
||||||
BOOST_CHECK(result->GetLength() == 2);
|
BOOST_CHECK(result->GetLength() == 2);
|
||||||
|
|
||||||
|
/* verify the config validator macro checks */
|
||||||
|
BOOST_CHECK(Utility::ValidateMacroString("$host.address") == false);
|
||||||
|
BOOST_CHECK(Utility::ValidateMacroString("host.vars.test$") == false);
|
||||||
|
|
||||||
|
BOOST_CHECK(Utility::ValidateMacroString("host.vars.test$") == false);
|
||||||
|
BOOST_CHECK(Utility::ValidateMacroString("$template::test$abc$") == false);
|
||||||
|
|
||||||
|
BOOST_CHECK(Utility::ValidateMacroString("$$test $host.vars.test$") == true);
|
||||||
|
|
||||||
|
BOOST_CHECK(Utility::ValidateMacroString("test $host.vars.test$") == true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user