-/******************************************************************************
- * Icinga 2 *
- * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License *
- * as published by the Free Software Foundation; either version 2 *
- * of the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software Foundation *
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
- ******************************************************************************/
+/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "icinga/pluginutility.hpp"
#include "icinga/macroprocessor.hpp"
-#include "icinga/perfdatavalue.hpp"
#include "base/logger.hpp"
#include "base/utility.hpp"
+#include "base/perfdatavalue.hpp"
#include "base/convert.hpp"
#include "base/process.hpp"
#include "base/objectlock.hpp"
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/split.hpp>
+#include "base/exception.hpp"
#include <boost/algorithm/string/trim.hpp>
-#include <boost/foreach.hpp>
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,
- const CheckResult::Ptr& cr, const MacroProcessor::ResolverList& macroResolvers,
- const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros,
- const boost::function<void(const Value& commandLine, const ProcessResult&)>& callback)
+ const CheckResult::Ptr& cr, const MacroProcessor::ResolverList& macroResolvers,
+ const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int timeout,
+ const std::function<void(const Value& commandLine, const ProcessResult&)>& callback)
{
Value raw_command = commandObj->GetCommandLine();
Dictionary::Ptr raw_arguments = commandObj->GetArguments();
Value command;
- if (!raw_arguments || raw_command.IsObjectType<Array>())
- 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) {
- std::vector<CommandArgument> args;
-
- ObjectLock olock(raw_arguments);
- BOOST_FOREACH(const Dictionary::Pair& kv, raw_arguments) {
- const Value& arginfo = kv.second;
-
- CommandArgument arg;
- arg.Key = kv.first;
-
- bool required = false;
- String 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");
-
- String set_if = argdict->Get("set_if");
-
- if (!set_if.IsEmpty()) {
- String missingMacro;
- String 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.ExecutionStart = pr.ExecutionStart;
- pr.ExitStatus = 3; /* Unknown */
- pr.Output = message;
- callback(Empty, pr);
- }
-
- return;
- }
-
- continue;
- }
-
- args.push_back(arg);
+ try {
+ command = MacroProcessor::ResolveArguments(raw_command, raw_arguments,
+ macroResolvers, cr, resolvedMacros, useResolvedMacros);
+ } catch (const std::exception& ex) {
+ String message = DiagnosticInformation(ex);
+
+ 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);
}
- std::sort(args.begin(), args.end());
-
- 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);
- }
+ return;
}
Dictionary::Ptr envMacros = new Dictionary();
if (env) {
ObjectLock olock(env);
- BOOST_FOREACH(const Dictionary::Pair& kv, env) {
+ for (const Dictionary::Pair& kv : env) {
String name = kv.second;
+ String missingMacro;
Value value = MacroProcessor::ResolveMacros(name, macroResolvers, cr,
- NULL, MacroProcessor::EscapeCallback(), resolvedMacros,
- useResolvedMacros);
+ &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros,
+ useResolvedMacros);
+
+#ifdef I2_DEBUG
+ if (!missingMacro.IsEmpty())
+ Log(LogDebug, "PluginUtility")
+ << "Macro '" << name << "' is not defined.";
+#endif /* I2_DEBUG */
if (value.IsObjectType<Array>())
value = Utility::Join(value, ';');
return;
Process::Ptr process = new Process(Process::PrepareCommand(command), envMacros);
- process->SetTimeout(commandObj->GetTimeout());
- process->Run(boost::bind(callback, command, _1));
+
+ process->SetTimeout(timeout);
+ process->SetAdjustPriority(true);
+
+ process->Run(std::bind(callback, command, _1));
}
ServiceState PluginUtility::ExitStatusToState(int exitStatus)
String text;
String perfdata;
- std::vector<String> lines;
- boost::algorithm::split(lines, output, boost::is_any_of("\r\n"));
+ std::vector<String> lines = output.Split("\r\n");
- BOOST_FOREACH (const String& line, lines) {
+ for (const String& line : lines) {
size_t delim = line.FindFirstOf("|");
if (!text.IsEmpty())
Array::Ptr PluginUtility::SplitPerfdata(const String& perfdata)
{
- Array::Ptr result = new Array();
+ ArrayData result;
size_t begin = 0;
String multi_prefix;
else
pdv = label + "=" + value;
- result->Add(pdv);
+ result.emplace_back(std::move(pdv));
if (multi_index != String::NPos)
multi_prefix = label.SubStr(0, multi_index);
begin = spq + 1;
}
- return result;
+ return new Array(std::move(result));
}
String PluginUtility::FormatPerfdata(const Array::Ptr& perfdata)
ObjectLock olock(perfdata);
bool first = true;
- BOOST_FOREACH(const Value& pdv, perfdata) {
+ for (const Value& pdv : perfdata) {
if (!first)
result << " ";
else