Add macro config validator for command args, env, custom attr, perfdata templates

fixes #7311
This commit is contained in:
Michael Friedrich 2015-02-11 13:12:08 +01:00
parent 477f7a713c
commit 8ca57cba03
13 changed files with 191 additions and 3 deletions

View File

@ -1256,3 +1256,23 @@ String Utility::UnescapeString(const String& s)
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;
}

View File

@ -118,6 +118,8 @@ public:
static String EscapeString(const String& s, const String& chars);
static String UnescapeString(const String& s);
static bool ValidateMacroString(const String& macro);
static void SetThreadName(const String& name, bool os = true);
static String GetThreadName(void);

View File

@ -20,11 +20,15 @@
#include "icinga/command.hpp"
#include "base/function.hpp"
#include "base/exception.hpp"
#include "base/objectlock.hpp"
#include <boost/foreach.hpp>
using namespace icinga;
REGISTER_TYPE(Command);
REGISTER_SCRIPTFUNCTION(ValidateCommandAttributes, &Command::ValidateAttributes);
REGISTER_SCRIPTFUNCTION(ValidateCommandArguments, &Command::ValidateArguments);
REGISTER_SCRIPTFUNCTION(ValidateEnvironmentVariables, &Command::ValidateEnvironmentVariables);
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()));
}
}
}

View File

@ -40,6 +40,8 @@ public:
//virtual Dictionary::Ptr Execute(const Object::Ptr& context) = 0;
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;
void SetModifiedAttributes(int flags, const MessageOrigin& origin = MessageOrigin());

View File

@ -19,10 +19,15 @@
#include "icinga/customvarobject.hpp"
#include "base/logger.hpp"
#include "base/function.hpp"
#include "base/exception.hpp"
#include "base/objectlock.hpp"
#include <boost/foreach.hpp>
using namespace icinga;
REGISTER_TYPE(CustomVarObject);
REGISTER_SCRIPTFUNCTION(ValidateCustomAttributes, &CustomVarObject::ValidateCustomAttributes);
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);
}
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()));
}
}
}
}

View File

@ -61,6 +61,8 @@ public:
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;
void SetVars(const Dictionary::Ptr& vars, const MessageOrigin& origin = MessageOrigin());

View File

@ -26,6 +26,7 @@
}
%type CustomVarObject {
%validator "ValidateCustomAttributes",
%attribute %dictionary "vars",
}
@ -193,6 +194,8 @@
%type Command %inherits CustomVarObject {
%validator "ValidateCommandAttributes",
%validator "ValidateCommandArguments",
%validator "ValidateEnvironmentVariables",
%require "execute",
%attribute %function "execute",

View File

@ -43,6 +43,7 @@
using namespace icinga;
REGISTER_TYPE(GraphiteWriter);
REGISTER_SCRIPTFUNCTION(ValidateNameTemplates, &GraphiteWriter::ValidateNameTemplates);
REGISTER_STATSFUNCTION(GraphiteWriterStats, &GraphiteWriter::StatsFunc);
@ -146,7 +147,7 @@ void GraphiteWriter::SendPerfdata(const String& prefix, const CheckResult::Ptr&
ObjectLock olock(perfdata);
BOOST_FOREACH(const Value& val, perfdata) {
PerfdataValue::Ptr pdv;
if (val.IsObjectType<PerfdataValue>())
pdv = val;
else {
@ -158,7 +159,7 @@ void GraphiteWriter::SendPerfdata(const String& prefix, const CheckResult::Ptr&
continue;
}
}
String escaped_key = EscapeMetric(pdv->GetLabel());
boost::algorithm::replace_all(escaped_key, "::", ".");
@ -230,3 +231,15 @@ Value GraphiteWriter::EscapeMacroMetric(const Value& value)
} else
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()));
}
}

View File

@ -43,6 +43,8 @@ public:
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
static void ValidateNameTemplates(const String& location, const GraphiteWriter::Ptr& object);
protected:
virtual void Start(void);

View File

@ -18,6 +18,8 @@
******************************************************************************/
%type PerfdataWriter {
%validator "ValidateFormatTemplates",
%attribute %string "host_perfdata_path",
%attribute %string "service_perfdata_path",
%attribute %string "host_temp_path",
@ -28,6 +30,8 @@
}
%type GraphiteWriter {
%validator "ValidateNameTemplates",
%attribute %string "host",
%attribute %string "port",
%attribute %string "host_name_template",
@ -44,4 +48,3 @@
%attribute %string "host",
%attribute %string "port",
}

View File

@ -27,12 +27,14 @@
#include "base/convert.hpp"
#include "base/utility.hpp"
#include "base/context.hpp"
#include "base/exception.hpp"
#include "base/application.hpp"
#include "base/statsfunction.hpp"
using namespace icinga;
REGISTER_TYPE(PerfdataWriter);
REGISTER_SCRIPTFUNCTION(ValidateFormatTemplates, &PerfdataWriter::ValidateFormatTemplates);
REGISTER_STATSFUNCTION(PerfdataWriterStats, &PerfdataWriter::StatsFunc);
@ -138,3 +140,14 @@ void PerfdataWriter::RotationTimerHandler(void)
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()));
}
}

View File

@ -42,6 +42,8 @@ public:
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
static void ValidateFormatTemplates(const String& location, const PerfdataWriter::Ptr& object);
protected:
virtual void Start(void);

View File

@ -51,6 +51,17 @@ BOOST_AUTO_TEST_CASE(simple)
Array::Ptr result = MacroProcessor::ResolveMacros("$testD$", resolvers);
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()