mirror of https://github.com/Icinga/icinga2.git
parent
6ef9d3c4db
commit
63a1ff77c3
|
@ -196,6 +196,29 @@ value of arbitrary macro expressions:
|
||||||
return "Some text"
|
return "Some text"
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
The `resolve_arguments` can be used to resolve a command and its arguments much in
|
||||||
|
the same fashion Icinga does this for the `command` and `arguments` attributes for
|
||||||
|
commands. The `by_ssh` command uses this functionality to let users specify a
|
||||||
|
command and arguments that should be executed via SSH:
|
||||||
|
|
||||||
|
arguments = {
|
||||||
|
"-C" = {{
|
||||||
|
var command = macro("$by_ssh_command$")
|
||||||
|
var arguments = macro("$by_ssh_arguments$")
|
||||||
|
|
||||||
|
if (typeof(command) == String && !arguments) {
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
|
||||||
|
var escaped_args = []
|
||||||
|
for (arg in resolve_arguments(command, arguments)) {
|
||||||
|
escaped_args.add(escape_shell_arg(arg))
|
||||||
|
}
|
||||||
|
return escaped_args.join(" ")
|
||||||
|
}}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
Acessing object attributes at runtime inside these functions is described in the
|
Acessing object attributes at runtime inside these functions is described in the
|
||||||
[advanced topics](5-advanced-topics.md#access-object-attributes-at-runtime) chapter.
|
[advanced topics](5-advanced-topics.md#access-object-attributes-at-runtime) chapter.
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,8 @@ Name | Description
|
||||||
----------------|--------------
|
----------------|--------------
|
||||||
by_ssh_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise.
|
by_ssh_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise.
|
||||||
by_ssh_port | **Optional.** The SSH port. Defaults to 22.
|
by_ssh_port | **Optional.** The SSH port. Defaults to 22.
|
||||||
by_ssh_command | **Optional.** The command that should be executed.
|
by_ssh_command | **Required.** The command that should be executed. Can be an array if multiple arguments should be passed to `check_by_ssh`.
|
||||||
|
by_ssh_arguments| **Optional.** A dictionary with arguments for the command. This works exactly like the 'arguments' dictionary for ordinary CheckCommands.
|
||||||
by_ssh_logname | **Optional.** The SSH username.
|
by_ssh_logname | **Optional.** The SSH username.
|
||||||
by_ssh_identity | **Optional.** The SSH identity.
|
by_ssh_identity | **Optional.** The SSH identity.
|
||||||
by_ssh_quiet | **Optional.** Whether to suppress SSH warnings. Defaults to false.
|
by_ssh_quiet | **Optional.** Whether to suppress SSH warnings. Defaults to false.
|
||||||
|
|
|
@ -1265,7 +1265,20 @@ object CheckCommand "by_ssh" {
|
||||||
arguments = {
|
arguments = {
|
||||||
"-H" = "$by_ssh_address$"
|
"-H" = "$by_ssh_address$"
|
||||||
"-p" = "$by_ssh_port$"
|
"-p" = "$by_ssh_port$"
|
||||||
"-C" = "$by_ssh_command$"
|
"-C" = {{
|
||||||
|
var command = macro("$by_ssh_command$")
|
||||||
|
var arguments = macro("$by_ssh_arguments$")
|
||||||
|
|
||||||
|
if (typeof(command) == String && !arguments) {
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
|
||||||
|
var escaped_args = []
|
||||||
|
for (arg in resolve_arguments(command, arguments)) {
|
||||||
|
escaped_args.add(escape_shell_arg(arg))
|
||||||
|
}
|
||||||
|
return escaped_args.join(" ")
|
||||||
|
}}
|
||||||
"-l" = "$by_ssh_logname$"
|
"-l" = "$by_ssh_logname$"
|
||||||
"-i" = "$by_ssh_identity$"
|
"-i" = "$by_ssh_identity$"
|
||||||
"-q" = {
|
"-q" = {
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include "base/context.hpp"
|
#include "base/context.hpp"
|
||||||
#include "base/configobject.hpp"
|
#include "base/configobject.hpp"
|
||||||
#include "base/scriptframe.hpp"
|
#include "base/scriptframe.hpp"
|
||||||
|
#include "base/convert.hpp"
|
||||||
|
#include "base/exception.hpp"
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
@ -36,7 +38,7 @@ using namespace icinga;
|
||||||
Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolvers,
|
Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolvers,
|
||||||
const CheckResult::Ptr& cr, String *missingMacro,
|
const CheckResult::Ptr& cr, String *missingMacro,
|
||||||
const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros,
|
const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros,
|
||||||
bool useResolvedMacros)
|
bool useResolvedMacros, int recursionLevel)
|
||||||
{
|
{
|
||||||
Value result;
|
Value result;
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolv
|
||||||
|
|
||||||
if (str.IsScalar()) {
|
if (str.IsScalar()) {
|
||||||
result = InternalResolveMacros(str, resolvers, cr, missingMacro, escapeFn,
|
result = InternalResolveMacros(str, resolvers, cr, missingMacro, escapeFn,
|
||||||
resolvedMacros, useResolvedMacros);
|
resolvedMacros, useResolvedMacros, recursionLevel + 1);
|
||||||
} else if (str.IsObjectType<Array>()) {
|
} else if (str.IsObjectType<Array>()) {
|
||||||
Array::Ptr resultArr = new Array();
|
Array::Ptr resultArr = new Array();
|
||||||
Array::Ptr arr = str;
|
Array::Ptr arr = str;
|
||||||
|
@ -55,7 +57,7 @@ Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolv
|
||||||
BOOST_FOREACH(const Value& arg, arr) {
|
BOOST_FOREACH(const Value& arg, arr) {
|
||||||
/* Note: don't escape macros here. */
|
/* Note: don't escape macros here. */
|
||||||
Value value = InternalResolveMacros(arg, resolvers, cr, missingMacro,
|
Value value = InternalResolveMacros(arg, resolvers, cr, missingMacro,
|
||||||
EscapeCallback(), resolvedMacros, useResolvedMacros);
|
EscapeCallback(), resolvedMacros, useResolvedMacros, recursionLevel + 1);
|
||||||
|
|
||||||
if (value.IsObjectType<Array>())
|
if (value.IsObjectType<Array>())
|
||||||
resultArr->Add(Utility::Join(value, ';'));
|
resultArr->Add(Utility::Join(value, ';'));
|
||||||
|
@ -73,7 +75,7 @@ Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolv
|
||||||
BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
|
BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
|
||||||
/* Note: don't escape macros here. */
|
/* Note: don't escape macros here. */
|
||||||
resultDict->Set(kv.first, InternalResolveMacros(kv.second, resolvers, cr, missingMacro,
|
resultDict->Set(kv.first, InternalResolveMacros(kv.second, resolvers, cr, missingMacro,
|
||||||
EscapeCallback(), resolvedMacros, useResolvedMacros));
|
EscapeCallback(), resolvedMacros, useResolvedMacros, recursionLevel + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
result = resultDict;
|
result = resultDict;
|
||||||
|
@ -187,6 +189,17 @@ Value MacroProcessor::InternalResolveMacrosShim(const std::vector<Value>& args,
|
||||||
resolvedMacros, useResolvedMacros, recursionLevel);
|
resolvedMacros, useResolvedMacros, recursionLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value MacroProcessor::InternalResolveArgumentsShim(const std::vector<Value>& args, const ResolverList& resolvers,
|
||||||
|
const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros,
|
||||||
|
bool useResolvedMacros, int recursionLevel)
|
||||||
|
{
|
||||||
|
if (args.size() < 2)
|
||||||
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function"));
|
||||||
|
|
||||||
|
return MacroProcessor::ResolveArguments(args[0], args[1], resolvers, cr,
|
||||||
|
resolvedMacros, useResolvedMacros, recursionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
Value MacroProcessor::EvaluateFunction(const Function::Ptr& func, const ResolverList& resolvers,
|
Value MacroProcessor::EvaluateFunction(const Function::Ptr& func, const ResolverList& resolvers,
|
||||||
const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn,
|
const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn,
|
||||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel)
|
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel)
|
||||||
|
@ -200,6 +213,9 @@ Value MacroProcessor::EvaluateFunction(const Function::Ptr& func, const Resolver
|
||||||
resolvers_this->Set("macro", new Function(boost::bind(&MacroProcessor::InternalResolveMacrosShim,
|
resolvers_this->Set("macro", new Function(boost::bind(&MacroProcessor::InternalResolveMacrosShim,
|
||||||
_1, boost::cref(resolvers), cr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros,
|
_1, boost::cref(resolvers), cr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros,
|
||||||
recursionLevel + 1)));
|
recursionLevel + 1)));
|
||||||
|
resolvers_this->Set("resolve_arguments", new Function(boost::bind(&MacroProcessor::InternalResolveArgumentsShim,
|
||||||
|
_1, boost::cref(resolvers), cr, resolvedMacros, useResolvedMacros,
|
||||||
|
recursionLevel + 1)));
|
||||||
|
|
||||||
ScriptFrame frame(resolvers_this);
|
ScriptFrame frame(resolvers_this);
|
||||||
return func->Invoke();
|
return func->Invoke();
|
||||||
|
@ -250,7 +266,7 @@ Value MacroProcessor::InternalResolveMacros(const String& str, const ResolverLis
|
||||||
|
|
||||||
if (resolved_macro.IsObjectType<Function>()) {
|
if (resolved_macro.IsObjectType<Function>()) {
|
||||||
resolved_macro = EvaluateFunction(resolved_macro, resolvers, cr, escapeFn,
|
resolved_macro = EvaluateFunction(resolved_macro, resolvers, cr, escapeFn,
|
||||||
resolvedMacros, useResolvedMacros, recursionLevel);
|
resolvedMacros, useResolvedMacros, recursionLevel + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
@ -334,3 +350,179 @@ bool MacroProcessor::ValidateMacroString(const String& macro)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroProcessor::AddArgumentHelper(const Array::Ptr& args, const String& key, const String& value,
|
||||||
|
bool add_key, bool add_value)
|
||||||
|
{
|
||||||
|
if (add_key)
|
||||||
|
args->Add(key);
|
||||||
|
|
||||||
|
if (add_value)
|
||||||
|
args->Add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value MacroProcessor::EscapeMacroShellArg(const Value& value)
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (value.IsObjectType<Array>()) {
|
||||||
|
Array::Ptr arr = value;
|
||||||
|
|
||||||
|
ObjectLock olock(arr);
|
||||||
|
BOOST_FOREACH(const Value& arg, arr) {
|
||||||
|
if (result.GetLength() > 0)
|
||||||
|
result += " ";
|
||||||
|
|
||||||
|
result += Utility::EscapeShellArg(arg);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
result = Utility::EscapeShellArg(value);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CommandArgument
|
||||||
|
{
|
||||||
|
int Order;
|
||||||
|
bool SkipKey;
|
||||||
|
bool RepeatKey;
|
||||||
|
bool SkipValue;
|
||||||
|
String Key;
|
||||||
|
Value AValue;
|
||||||
|
|
||||||
|
CommandArgument(void)
|
||||||
|
: Order(0), SkipKey(false), RepeatKey(true), SkipValue(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool operator<(const CommandArgument& rhs) const
|
||||||
|
{
|
||||||
|
return Order < rhs.Order;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Value MacroProcessor::ResolveArguments(const Value& command, const Dictionary::Ptr& arguments,
|
||||||
|
const MacroProcessor::ResolverList& resolvers, const CheckResult::Ptr& cr,
|
||||||
|
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel)
|
||||||
|
{
|
||||||
|
Value resolvedCommand;
|
||||||
|
if (!arguments || command.IsObjectType<Array>() || command.IsObjectType<Function>())
|
||||||
|
resolvedCommand = MacroProcessor::ResolveMacros(command, resolvers, cr, NULL,
|
||||||
|
EscapeMacroShellArg, resolvedMacros, useResolvedMacros, recursionLevel + 1);
|
||||||
|
else {
|
||||||
|
Array::Ptr arr = new Array();
|
||||||
|
arr->Add(command);
|
||||||
|
resolvedCommand = arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments) {
|
||||||
|
std::vector<CommandArgument> args;
|
||||||
|
|
||||||
|
ObjectLock olock(arguments);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, arguments) {
|
||||||
|
const Value& arginfo = kv.second;
|
||||||
|
|
||||||
|
CommandArgument arg;
|
||||||
|
arg.Key = kv.first;
|
||||||
|
|
||||||
|
bool required = false;
|
||||||
|
Value argval;
|
||||||
|
|
||||||
|
if (arginfo.IsObjectType<Dictionary>()) {
|
||||||
|
Dictionary::Ptr argdict = arginfo;
|
||||||
|
if (argdict->Contains("key"))
|
||||||
|
arg.Key = argdict->Get("key");
|
||||||
|
argval = argdict->Get("value");
|
||||||
|
if (argdict->Contains("required"))
|
||||||
|
required = argdict->Get("required");
|
||||||
|
arg.SkipKey = argdict->Get("skip_key");
|
||||||
|
if (argdict->Contains("repeat_key"))
|
||||||
|
arg.RepeatKey = argdict->Get("repeat_key");
|
||||||
|
arg.Order = argdict->Get("order");
|
||||||
|
|
||||||
|
Value set_if = argdict->Get("set_if");
|
||||||
|
|
||||||
|
if (!set_if.IsEmpty()) {
|
||||||
|
String missingMacro;
|
||||||
|
Value set_if_resolved = MacroProcessor::ResolveMacros(set_if, resolvers,
|
||||||
|
cr, &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros,
|
||||||
|
useResolvedMacros, recursionLevel + 1);
|
||||||
|
|
||||||
|
if (!missingMacro.IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int value;
|
||||||
|
|
||||||
|
if (set_if_resolved == "true")
|
||||||
|
value = 1;
|
||||||
|
else if (set_if_resolved == "false")
|
||||||
|
value = 0;
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
value = Convert::ToLong(set_if_resolved);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
/* tried to convert a string */
|
||||||
|
Log(LogWarning, "PluginUtility")
|
||||||
|
<< "Error evaluating set_if value '" << set_if_resolved << "': " << ex.what();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
argval = arginfo;
|
||||||
|
|
||||||
|
if (argval.IsEmpty())
|
||||||
|
arg.SkipValue = true;
|
||||||
|
|
||||||
|
String missingMacro;
|
||||||
|
arg.AValue = MacroProcessor::ResolveMacros(argval, resolvers,
|
||||||
|
cr, &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros,
|
||||||
|
useResolvedMacros, recursionLevel + 1);
|
||||||
|
|
||||||
|
if (!missingMacro.IsEmpty()) {
|
||||||
|
if (required) {
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Non-optional macro '" + missingMacro + "' used in argument '" +
|
||||||
|
arg.Key + "' is missing."));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(args.begin(), args.end());
|
||||||
|
|
||||||
|
Array::Ptr command_arr = resolvedCommand;
|
||||||
|
BOOST_FOREACH(const CommandArgument& arg, args) {
|
||||||
|
|
||||||
|
if (arg.AValue.IsObjectType<Dictionary>()) {
|
||||||
|
Log(LogWarning, "PluginUtility", "Tried to use dictionary in argument");
|
||||||
|
continue;
|
||||||
|
} else if (arg.AValue.IsObjectType<Array>()) {
|
||||||
|
bool first = true;
|
||||||
|
Array::Ptr arr = static_cast<Array::Ptr>(arg.AValue);
|
||||||
|
|
||||||
|
ObjectLock olock(arr);
|
||||||
|
BOOST_FOREACH(const Value& value, arr) {
|
||||||
|
bool add_key;
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
add_key = !arg.SkipKey;
|
||||||
|
} else
|
||||||
|
add_key = !arg.SkipKey && arg.RepeatKey;
|
||||||
|
|
||||||
|
AddArgumentHelper(command_arr, arg.Key, value, add_key, !arg.SkipValue);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
AddArgumentHelper(command_arr, arg.Key, arg.AValue, !arg.SkipKey, !arg.SkipValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,11 @@ public:
|
||||||
const CheckResult::Ptr& cr = CheckResult::Ptr(), String *missingMacro = NULL,
|
const CheckResult::Ptr& cr = CheckResult::Ptr(), String *missingMacro = NULL,
|
||||||
const EscapeCallback& escapeFn = EscapeCallback(),
|
const EscapeCallback& escapeFn = EscapeCallback(),
|
||||||
const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(),
|
const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(),
|
||||||
bool useResolvedMacros = false);
|
bool useResolvedMacros = false, int recursionLevel = 0);
|
||||||
|
|
||||||
|
static Value ResolveArguments(const Value& command, const Dictionary::Ptr& arguments,
|
||||||
|
const MacroProcessor::ResolverList& resolvers, const CheckResult::Ptr& cr,
|
||||||
|
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel = 0);
|
||||||
|
|
||||||
static bool ValidateMacroString(const String& macro);
|
static bool ValidateMacroString(const String& macro);
|
||||||
|
|
||||||
|
@ -62,10 +66,17 @@ private:
|
||||||
static Value InternalResolveMacrosShim(const std::vector<Value>& args, const ResolverList& resolvers,
|
static Value InternalResolveMacrosShim(const std::vector<Value>& args, const ResolverList& resolvers,
|
||||||
const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn,
|
const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn,
|
||||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel);
|
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel);
|
||||||
|
static Value InternalResolveArgumentsShim(const std::vector<Value>& args, const ResolverList& resolvers,
|
||||||
|
const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros,
|
||||||
|
bool useResolvedMacros, int recursionLevel);
|
||||||
static Value EvaluateFunction(const Function::Ptr& func, const ResolverList& resolvers,
|
static Value EvaluateFunction(const Function::Ptr& func, const ResolverList& resolvers,
|
||||||
const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn,
|
const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn,
|
||||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel);
|
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel);
|
||||||
|
|
||||||
|
static void AddArgumentHelper(const Array::Ptr& args, const String& key, const String& value,
|
||||||
|
bool add_key, bool add_value);
|
||||||
|
static Value EscapeMacroShellArg(const Value& value);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "base/convert.hpp"
|
#include "base/convert.hpp"
|
||||||
#include "base/process.hpp"
|
#include "base/process.hpp"
|
||||||
#include "base/objectlock.hpp"
|
#include "base/objectlock.hpp"
|
||||||
|
#include "base/exception.hpp"
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
#include <boost/algorithm/string/trim.hpp>
|
#include <boost/algorithm/string/trim.hpp>
|
||||||
|
@ -32,54 +33,6 @@
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
struct CommandArgument
|
|
||||||
{
|
|
||||||
int Order;
|
|
||||||
bool SkipKey;
|
|
||||||
bool RepeatKey;
|
|
||||||
bool SkipValue;
|
|
||||||
String Key;
|
|
||||||
Value AValue;
|
|
||||||
|
|
||||||
CommandArgument(void)
|
|
||||||
: Order(0), SkipKey(false), RepeatKey(true), SkipValue(false)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
bool operator<(const CommandArgument& rhs) const
|
|
||||||
{
|
|
||||||
return Order < rhs.Order;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void PluginUtility::AddArgumentHelper(const Array::Ptr& args, const String& key, const String& value, bool add_key, bool add_value)
|
|
||||||
{
|
|
||||||
if (add_key)
|
|
||||||
args->Add(key);
|
|
||||||
|
|
||||||
if (add_value)
|
|
||||||
args->Add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value PluginUtility::EscapeMacroShellArg(const Value& value)
|
|
||||||
{
|
|
||||||
String result;
|
|
||||||
|
|
||||||
if (value.IsObjectType<Array>()) {
|
|
||||||
Array::Ptr arr = value;
|
|
||||||
|
|
||||||
ObjectLock olock(arr);
|
|
||||||
BOOST_FOREACH(const Value& arg, arr) {
|
|
||||||
if (result.GetLength() > 0)
|
|
||||||
result += " ";
|
|
||||||
|
|
||||||
result += Utility::EscapeShellArg(arg);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
result = Utility::EscapeShellArg(value);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkable::Ptr& checkable,
|
void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkable::Ptr& checkable,
|
||||||
const CheckResult::Ptr& cr, const MacroProcessor::ResolverList& macroResolvers,
|
const CheckResult::Ptr& cr, const MacroProcessor::ResolverList& macroResolvers,
|
||||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros,
|
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros,
|
||||||
|
@ -89,136 +42,26 @@ void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkab
|
||||||
Dictionary::Ptr raw_arguments = commandObj->GetArguments();
|
Dictionary::Ptr raw_arguments = commandObj->GetArguments();
|
||||||
|
|
||||||
Value command;
|
Value command;
|
||||||
if (!raw_arguments || raw_command.IsObjectType<Array>() || raw_command.IsObjectType<Function>())
|
|
||||||
command = MacroProcessor::ResolveMacros(raw_command, macroResolvers, cr, NULL,
|
|
||||||
PluginUtility::EscapeMacroShellArg, resolvedMacros, useResolvedMacros);
|
|
||||||
else {
|
|
||||||
Array::Ptr arr = new Array();
|
|
||||||
arr->Add(raw_command);
|
|
||||||
command = arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (raw_arguments) {
|
try {
|
||||||
std::vector<CommandArgument> args;
|
command = MacroProcessor::ResolveArguments(raw_command, raw_arguments,
|
||||||
|
macroResolvers, cr, resolvedMacros, useResolvedMacros);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
String message = DiagnosticInformation(ex);
|
||||||
|
|
||||||
ObjectLock olock(raw_arguments);
|
Log(LogWarning, "PluginUtility", message);
|
||||||
BOOST_FOREACH(const Dictionary::Pair& kv, raw_arguments) {
|
|
||||||
const Value& arginfo = kv.second;
|
|
||||||
|
|
||||||
CommandArgument arg;
|
if (callback) {
|
||||||
arg.Key = kv.first;
|
ProcessResult pr;
|
||||||
|
pr.PID = -1;
|
||||||
bool required = false;
|
pr.ExecutionStart = Utility::GetTime();
|
||||||
Value argval;
|
pr.ExecutionEnd = pr.ExecutionStart;
|
||||||
|
pr.ExitStatus = 3; /* Unknown */
|
||||||
if (arginfo.IsObjectType<Dictionary>()) {
|
pr.Output = message;
|
||||||
Dictionary::Ptr argdict = arginfo;
|
callback(Empty, pr);
|
||||||
if (argdict->Contains("key"))
|
|
||||||
arg.Key = argdict->Get("key");
|
|
||||||
argval = argdict->Get("value");
|
|
||||||
if (argdict->Contains("required"))
|
|
||||||
required = argdict->Get("required");
|
|
||||||
arg.SkipKey = argdict->Get("skip_key");
|
|
||||||
if (argdict->Contains("repeat_key"))
|
|
||||||
arg.RepeatKey = argdict->Get("repeat_key");
|
|
||||||
arg.Order = argdict->Get("order");
|
|
||||||
|
|
||||||
Value set_if = argdict->Get("set_if");
|
|
||||||
|
|
||||||
if (!set_if.IsEmpty()) {
|
|
||||||
String missingMacro;
|
|
||||||
Value set_if_resolved = MacroProcessor::ResolveMacros(set_if, macroResolvers,
|
|
||||||
cr, &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros,
|
|
||||||
useResolvedMacros);
|
|
||||||
|
|
||||||
if (!missingMacro.IsEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int value;
|
|
||||||
|
|
||||||
if (set_if_resolved == "true")
|
|
||||||
value = 1;
|
|
||||||
else if (set_if_resolved == "false")
|
|
||||||
value = 0;
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
value = Convert::ToLong(set_if_resolved);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
/* tried to convert a string */
|
|
||||||
Log(LogWarning, "PluginUtility")
|
|
||||||
<< "Error evaluating set_if value '" << set_if_resolved << "': " << ex.what();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
argval = arginfo;
|
|
||||||
|
|
||||||
if (argval.IsEmpty())
|
|
||||||
arg.SkipValue = true;
|
|
||||||
|
|
||||||
String missingMacro;
|
|
||||||
arg.AValue = MacroProcessor::ResolveMacros(argval, macroResolvers,
|
|
||||||
cr, &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros,
|
|
||||||
useResolvedMacros);
|
|
||||||
|
|
||||||
if (!missingMacro.IsEmpty()) {
|
|
||||||
if (required) {
|
|
||||||
String message = "Non-optional macro '" + missingMacro + "' used in argument '" +
|
|
||||||
arg.Key + "' is missing while executing command '" + commandObj->GetName() +
|
|
||||||
"' for object '" + checkable->GetName() + "'";
|
|
||||||
Log(LogWarning, "PluginUtility", message);
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
ProcessResult pr;
|
|
||||||
pr.PID = -1;
|
|
||||||
pr.ExecutionStart = Utility::GetTime();
|
|
||||||
pr.ExecutionEnd = pr.ExecutionStart;
|
|
||||||
pr.ExitStatus = 3; /* Unknown */
|
|
||||||
pr.Output = message;
|
|
||||||
callback(Empty, pr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
args.push_back(arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(args.begin(), args.end());
|
return;
|
||||||
|
|
||||||
Array::Ptr command_arr = command;
|
|
||||||
BOOST_FOREACH(const CommandArgument& arg, args) {
|
|
||||||
|
|
||||||
if (arg.AValue.IsObjectType<Dictionary>()) {
|
|
||||||
Log(LogWarning, "PluginUtility", "Tried to use dictionary in argument");
|
|
||||||
continue;
|
|
||||||
} else if (arg.AValue.IsObjectType<Array>()) {
|
|
||||||
bool first = true;
|
|
||||||
Array::Ptr arr = static_cast<Array::Ptr>(arg.AValue);
|
|
||||||
|
|
||||||
ObjectLock olock(arr);
|
|
||||||
BOOST_FOREACH(const Value& value, arr) {
|
|
||||||
bool add_key;
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
first = false;
|
|
||||||
add_key = !arg.SkipKey;
|
|
||||||
} else
|
|
||||||
add_key = !arg.SkipKey && arg.RepeatKey;
|
|
||||||
|
|
||||||
AddArgumentHelper(command_arr, arg.Key, value, add_key, !arg.SkipValue);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
AddArgumentHelper(command_arr, arg.Key, arg.AValue, !arg.SkipKey, !arg.SkipValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr envMacros = new Dictionary();
|
Dictionary::Ptr envMacros = new Dictionary();
|
||||||
|
|
|
@ -52,9 +52,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PluginUtility(void);
|
PluginUtility(void);
|
||||||
|
|
||||||
static void AddArgumentHelper(const Array::Ptr& args, const String& key, const String& value, bool add_key, bool add_value);
|
|
||||||
static Value EscapeMacroShellArg(const Value& value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue