1
0
mirror of https://github.com/Icinga/icinga2.git synced 2025-04-08 17:05:25 +02:00

Implemented environment-based macros.

This commit is contained in:
Gunnar Beutner 2013-02-09 23:02:33 +01:00
parent f8851aa79d
commit ee37e0cace
10 changed files with 160 additions and 44 deletions

@ -32,6 +32,8 @@ AC_LANG_CPLUSPLUS
AC_PROG_CC
AC_LANG_C
AC_FUNC_VFORK
LT_INIT([dlopen disable-static win32-dll])
LT_CONFIG_LTDL_DIR([third-party/ltdl])
LTDL_INIT

@ -43,3 +43,7 @@ String Convert::ToString(long val)
return cs.str();
}
String Convert::ToString(const Value& val)
{
return static_cast<String>(val);
}

@ -35,6 +35,7 @@ public:
static double ToDouble(const String& val);
static bool ToBool(const String& val);
static String ToString(long val);
static String ToString(const Value& val);
private:
Convert(void);

@ -255,4 +255,3 @@ cJSON *Dictionary::ToJson(void) const
return json;
}

@ -19,10 +19,6 @@
#include "i2-base.h"
#ifndef _MSC_VER
# include "popen_noshell.h"
#endif /* _MSC_VER */
using namespace icinga;
bool Process::m_ThreadCreated = false;
@ -30,8 +26,9 @@ boost::mutex Process::m_Mutex;
deque<Process::Ptr> Process::m_Tasks;
condition_variable Process::m_TasksCV;
Process::Process(const String& command)
: AsyncTask<Process, ProcessResult>(), m_Command(command), m_UsePopen(false)
Process::Process(const String& command, const Dictionary::Ptr& environment)
: AsyncTask<Process, ProcessResult>(), m_Command(command),
m_Environment(environment), m_FP(NULL)
{
assert(Application::IsMainThread());
@ -130,29 +127,127 @@ void Process::WorkerThreadProc(void)
}
}
void Process::Spawn(const String& command, const Dictionary::Ptr& env)
{
vector<String> args;
args.push_back("sh");
args.push_back("-c");
args.push_back(command);
return Spawn(args, env);
}
void Process::Spawn(const vector<String>& args, const Dictionary::Ptr& extraEnv)
{
assert(m_FP == NULL);
#ifdef _MSC_VER
#error "TODO: implement"
#else /* _MSC_VER */
int fds[2];
if (pipe(fds) < 0)
BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno));
char **argv = new char *[args.size() + 1];
for (int i = 0; i < args.size(); i++)
argv[i] = strdup(args[i].CStr());
argv[args.size()] = NULL;
int envc = 0;
/* count existing environment variables */
while (environ[envc] != NULL)
envc++;
char **envp = new char *[envc + (extraEnv ? extraEnv->GetLength() : 0) + 1];
for (int i = 0; i < envc; i++)
envp[i] = environ[i];
if (extraEnv) {
String key;
Value value;
int index = envc;
BOOST_FOREACH(tie(key, value), extraEnv) {
String kv = key + "=" + Convert::ToString(value);
envp[index] = strdup(kv.CStr());
index++;
}
}
envp[envc + (extraEnv ? extraEnv->GetLength() : 0)] = NULL;
#ifdef HAVE_VFORK
m_Pid = vfork();
#else /* HAVE_VFORK */
m_Pid = fork();
#endif /* HAVE_VFORK */
if (m_Pid < 0)
BOOST_THROW_EXCEPTION(PosixException("fork() failed.", errno));
if (m_Pid == 0) {
/* child */
if (dup2(fds[1], STDOUT_FILENO) < 0 || dup2(fds[1], STDERR_FILENO) < 0) {
perror("dup2() failed.");
_exit(128);
}
(void) close(fds[1]);
if (execvpe(argv[0], argv, envp) < 0) {
perror("execvpe() failed.");
_exit(128);
}
_exit(128);
} else {
for (int i = 0; i < args.size(); i++)
free(argv[i]);
delete [] argv;
if (extraEnv) {
for (int i = envc; i < envc + extraEnv->GetLength(); i++)
free(envp[i]);
}
delete [] envp;
/* parent */
(void) close(fds[1]);
m_FP = fdopen(fds[0], "r");
if (m_FP == NULL)
BOOST_THROW_EXCEPTION(PosixException("fdopen() failed.", errno));
}
#endif /* _MSC_VER */
}
int Process::WaitPid(void)
{
#ifdef _MSC_VER
return _pclose(m_FP);
#else /* _MSC_VER */
fclose(m_FP);
int status;
if (waitpid(m_Pid, &status, 0) != m_Pid)
BOOST_THROW_EXCEPTION(PosixException("waitpid() failed.", errno));
return status;
#endif /* _MSC_VER */
}
void Process::InitTask(void)
{
m_Result.ExecutionStart = Utility::GetTime();
#ifdef _MSC_VER
m_FP = _popen(m_Command.CStr(), "r");
#else /* _MSC_VER */
if (!m_UsePopen) {
m_PCloseArg = new popen_noshell_pass_to_pclose;
m_FP = popen_noshell_compat(m_Command.CStr(), "r",
(popen_noshell_pass_to_pclose *)m_PCloseArg);
if (m_FP == NULL)
m_UsePopen = true;
}
if (m_UsePopen)
m_FP = popen(m_Command.CStr(), "r");
#endif /* _MSC_VER */
if (m_FP == NULL)
BOOST_THROW_EXCEPTION(runtime_error("Could not create process."));
Spawn(m_Command, m_Environment);
}
bool Process::RunTask(void)
@ -169,18 +264,8 @@ bool Process::RunTask(void)
String output = m_OutputStream.str();
int status, exitcode;
#ifdef _MSC_VER
status = _pclose(m_FP);
#else /* _MSC_VER */
if (m_UsePopen) {
status = pclose(m_FP);
} else {
status = pclose_noshell((popen_noshell_pass_to_pclose *)m_PCloseArg);
delete (popen_noshell_pass_to_pclose *)m_PCloseArg;
}
#endif /* _MSC_VER */
m_Result.ExecutionEnd = Utility::GetTime();
status = WaitPid();
#ifndef _MSC_VER
if (WIFEXITED(status)) {
@ -206,6 +291,7 @@ bool Process::RunTask(void)
}
#endif /* _MSC_VER */
m_Result.ExecutionEnd = Utility::GetTime();
m_Result.ExitStatus = exitcode;
m_Result.Output = output;

@ -50,19 +50,20 @@ public:
static const deque<Process::Ptr>::size_type MaxTasksPerThread = 512;
Process(const String& command);
Process(const String& command, const Dictionary::Ptr& environment = Dictionary::Ptr());
private:
static bool m_ThreadCreated;
String m_Command;
Dictionary::Ptr m_Environment;
#ifndef _WIN32
pid_t m_Pid;
#endif /* _WIN32 */
FILE *m_FP;
stringstream m_OutputStream;
bool m_UsePopen;
#ifndef _MSC_VER
void *m_PCloseArg;
#endif /* _MSC_VER */
ProcessResult m_Result;
@ -78,6 +79,10 @@ private:
bool RunTask(void);
int GetFD(void) const;
void Spawn(const String& command, const Dictionary::Ptr& extraEnv);
void Spawn(const vector<String>& args, const Dictionary::Ptr& extraEnv);
int WaitPid(void);
};
}

@ -56,3 +56,21 @@ String MacroProcessor::ResolveMacros(const String& str, const vector<Dictionary:
return result;
}
Dictionary::Ptr MacroProcessor::MakeEnvironment(const vector<Dictionary::Ptr>& dicts)
{
Dictionary::Ptr result = boost::make_shared<Dictionary>();
BOOST_REVERSE_FOREACH(const Dictionary::Ptr& dict, dicts) {
String key;
Value value;
BOOST_FOREACH(tie(key, value), dict) {
if (!value.IsScalar())
continue;
result->Set(key, value);
}
}
return result;
}

@ -32,6 +32,7 @@ class I2_ICINGA_API MacroProcessor
{
public:
static String ResolveMacros(const String& str, const vector<Dictionary::Ptr>& macroDicts);
static Dictionary::Ptr MakeEnvironment(const vector<Dictionary::Ptr>& macroDicts);
};
}

@ -48,7 +48,7 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value
macroDicts.push_back(IcingaApplication::GetInstance()->GetMacros());
String command = MacroProcessor::ResolveMacros(checkCommand, macroDicts);
Process::Ptr process = boost::make_shared<Process>(command);
Process::Ptr process = boost::make_shared<Process>(command, MacroProcessor::MakeEnvironment(macroDicts));
PluginCheckTask ct(task, process);

@ -53,7 +53,7 @@ void PluginNotificationTask::ScriptFunc(const ScriptTask::Ptr& task, const vecto
macroDicts.push_back(IcingaApplication::GetInstance()->GetMacros());
String command = MacroProcessor::ResolveMacros(notificationCommand, macroDicts);
Process::Ptr process = boost::make_shared<Process>(command);
Process::Ptr process = boost::make_shared<Process>(command, MacroProcessor::MakeEnvironment(macroDicts));
PluginNotificationTask ct(task, process, notification->GetService()->GetName(), command);