Implemented script tasks.

This commit is contained in:
Gunnar Beutner 2012-07-14 15:59:59 +02:00
parent 6cbccdc91c
commit 30aa16d9dc
23 changed files with 286 additions and 77 deletions

View File

@ -34,6 +34,10 @@ libbase_la_SOURCES = \
process.h \
ringbuffer.cpp \
ringbuffer.h \
scriptfunction.cpp \
scriptfunction.h \
scripttask.cpp \
scripttask.h \
socket.cpp \
socket.h \
streamlogger.cpp \

View File

@ -36,11 +36,11 @@ public:
void Start(void);
void Finish(void);
protected:
virtual void Run(void) = 0;
void Finish(void);
private:
void ForwardCallback(void);

View File

@ -25,6 +25,8 @@
<ClCompile Include="objectset.cpp" />
<ClCompile Include="process.cpp" />
<ClCompile Include="ringbuffer.cpp" />
<ClCompile Include="scriptfunction.cpp" />
<ClCompile Include="scripttask.cpp" />
<ClCompile Include="socket.cpp" />
<ClCompile Include="streamlogger.cpp" />
<ClCompile Include="sysloglogger.cpp" />
@ -46,6 +48,8 @@
<ClInclude Include="configobject.h" />
<ClInclude Include="dictionary.h" />
<ClInclude Include="event.h" />
<ClInclude Include="scriptfunction.h" />
<ClInclude Include="scripttask.h" />
<ClInclude Include="logger.h" />
<ClInclude Include="objectmap.h" />
<ClInclude Include="objectset.h" />

View File

@ -82,6 +82,12 @@
<ClCompile Include="asynctask.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="scriptfunction.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="scripttask.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="application.h">
@ -168,6 +174,12 @@
<ClInclude Include="process.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="scripttask.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="scriptfunction.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Quelldateien">

View File

@ -154,9 +154,9 @@ ConfigObject::Ptr ConfigObject::GetObject(string type, string name)
bool ConfigObject::TypeAndNameGetter(const ConfigObject::Ptr& object, pair<string, string> *key)
{
*key = make_pair(object->GetType(), object->GetName());
*key = make_pair(object->GetType(), object->GetName());
return true;
return true;
}
function<bool (ConfigObject::Ptr)> ConfigObject::MakeTypePredicate(string type)
@ -196,3 +196,22 @@ void ConfigObject::RemoveTag(const string& key)
{
GetTags()->Remove(key);
}
ScriptTask::Ptr ConfigObject::InvokeHook(const string& hook,
const vector<Variant>& arguments, AsyncTask::CompletionCallback callback)
{
Dictionary::Ptr hooks;
string funcName;
if (!GetProperty("hooks", &hooks) || !hooks->Get(hook, &funcName))
return ScriptTask::Ptr();
ScriptFunction::Ptr func = ScriptFunction::GetByName(funcName);
if (!func)
throw invalid_argument("Function '" + funcName + "' does not exist.");
ScriptTask::Ptr task = boost::make_shared<ScriptTask>(func, arguments, callback);
task->Start();
return task;
}

View File

@ -65,6 +65,9 @@ public:
void RemoveTag(const string& key);
ScriptTask::Ptr InvokeHook(const string& hook,
const vector<Variant>& arguments, AsyncTask::CompletionCallback callback);
string GetType(void) const;
string GetName(void) const;
@ -98,7 +101,7 @@ private:
void SetCommitTimestamp(time_t ts);
static bool TypeAndNameGetter(const ConfigObject::Ptr& object, pair<string, string> *key);
static bool TypePredicate(const ConfigObject::Ptr& object, string type);
static bool TypePredicate(const ConfigObject::Ptr& object, string type);
static bool TypeGetter(const ConfigObject::Ptr& object, string *key);
};

View File

@ -167,6 +167,10 @@ using boost::system_time;
#include "tcpclient.h"
#include "tcpserver.h"
#include "tlsclient.h"
#include "asynctask.h"
#include "process.h"
#include "scriptfunction.h"
#include "scripttask.h"
#include "objectset.h"
#include "objectmap.h"
#include "configobject.h"
@ -176,7 +180,5 @@ using boost::system_time;
#include "logger.h"
#include "streamlogger.h"
#include "sysloglogger.h"
#include "asynctask.h"
#include "process.h"
#endif /* I2BASE_H */

36
base/scriptfunction.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "i2-base.h"
using namespace icinga;
map<string, ScriptFunction::Ptr> ScriptFunction::m_Functions;
ScriptFunction::ScriptFunction(const Callback& function)
: m_Callback(function)
{ }
void ScriptFunction::Register(const string& name, const ScriptFunction::Ptr& function)
{
m_Functions[name] = function;
}
void ScriptFunction::Unregister(const string& name)
{
m_Functions.erase(name);
}
ScriptFunction::Ptr ScriptFunction::GetByName(const string& name)
{
map<string, ScriptFunction::Ptr>::iterator it;
it = m_Functions.find(name);
if (it == m_Functions.end())
return ScriptFunction::Ptr();
return it->second;
}
void ScriptFunction::Invoke(const ScriptTask::Ptr& task, const vector<Variant>& arguments)
{
m_Callback(task, arguments);
}

52
base/scriptfunction.h Normal file
View File

@ -0,0 +1,52 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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. *
******************************************************************************/
#ifndef SCRIPTFUNCTION_H
#define SCRIPTFUNCTION_H
namespace icinga
{
class ScriptTask;
class I2_BASE_API ScriptFunction : public Object
{
public:
typedef shared_ptr<ScriptFunction> Ptr;
typedef weak_ptr<ScriptFunction> WeakPtr;
typedef function<void (const shared_ptr<ScriptTask>&, const vector<Variant>& arguments)> Callback;
ScriptFunction(const Callback& function);
static void Register(const string& name, const ScriptFunction::Ptr& function);
static void Unregister(const string& name);
static ScriptFunction::Ptr GetByName(const string& name);
void Invoke(const shared_ptr<ScriptTask>& task, const vector<Variant>& arguments);
private:
Callback m_Callback;
static map<string, ScriptFunction::Ptr> m_Functions;
};
}
#endif /* SCRIPTFUNCTION_H */

22
base/scripttask.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "i2-base.h"
using namespace icinga;
ScriptTask::ScriptTask(const ScriptFunction::Ptr& function, const vector<Variant>& arguments, CompletionCallback callback)
: AsyncTask(callback), m_Function(function), m_Arguments(arguments)
{ }
void ScriptTask::Run(void)
{
m_Function->Invoke(GetSelf(), m_Arguments);
}
void ScriptTask::SetResult(const Variant& result)
{
m_Result = result;
}
Variant ScriptTask::GetResult(void)
{
return m_Result;
}

48
base/scripttask.h Normal file
View File

@ -0,0 +1,48 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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. *
******************************************************************************/
#ifndef SCRIPTTASK_H
#define SCRIPTTASK_H
namespace icinga
{
class I2_BASE_API ScriptTask : public AsyncTask
{
public:
typedef shared_ptr<ScriptTask> Ptr;
typedef weak_ptr<ScriptTask> WeakPtr;
ScriptTask(const ScriptFunction::Ptr& function, const vector<Variant>& arguments, CompletionCallback callback);
void SetResult(const Variant& result);
Variant GetResult(void);
protected:
virtual void Run(void);
private:
ScriptFunction::Ptr m_Function;
vector<Variant> m_Arguments;
Variant m_Result;
};
}
#endif /* SCRIPTTASK_H */

View File

@ -81,7 +81,6 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="checkresult.h" />
<ClInclude Include="checktask.h" />
<ClInclude Include="cib.h" />
<ClInclude Include="configobjectadapter.h" />
<ClInclude Include="host.h" />
@ -95,7 +94,6 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="checkresult.cpp" />
<ClCompile Include="checktask.cpp" />
<ClCompile Include="cib.cpp" />
<ClCompile Include="configobjectadapter.cpp" />
<ClCompile Include="host.cpp" />

View File

@ -14,9 +14,6 @@
<ClInclude Include="checkresult.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="checktask.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="cib.h">
<Filter>Headerdateien</Filter>
</ClInclude>
@ -52,9 +49,6 @@
<ClCompile Include="checkresult.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="checktask.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="cib.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>

View File

@ -45,3 +45,9 @@ void ConfigObjectAdapter::RemoveTag(const string& key)
{
m_ConfigObject->RemoveTag(key);
}
ScriptTask::Ptr ConfigObjectAdapter::InvokeHook(const string& hook,
const vector<Variant>& arguments, AsyncTask::CompletionCallback callback)
{
return m_ConfigObject->InvokeHook(hook, arguments, callback);
}

View File

@ -57,6 +57,9 @@ public:
void RemoveTag(const string& key);
ScriptTask::Ptr InvokeHook(const string& hook,
const vector<Variant>& arguments, AsyncTask::CompletionCallback callback);
private:
ConfigObject::Ptr m_ConfigObject;
};

View File

@ -21,39 +21,47 @@
using namespace icinga;
NagiosCheckTask::NagiosCheckTask(const Service& service, const CompletionCallback& completionCallback)
: CheckTask(service, completionCallback)
void NagiosCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Variant>& arguments)
{
if (arguments.size() < 1)
throw invalid_argument("Missing argument: Service must be specified.");
Variant vservice = arguments[0];
if (!vservice.IsObjectType<ConfigObject>())
throw invalid_argument("Argument must be a config object.");
Service service = static_cast<ConfigObject::Ptr>(vservice);
string checkCommand = service.GetCheckCommand();
vector<Dictionary::Ptr> macroDicts;
macroDicts.push_back(service.GetMacros());
macroDicts.push_back(service.GetHost().GetMacros());
macroDicts.push_back(IcingaApplication::GetInstance()->GetMacros());
m_Command = MacroProcessor::ResolveMacros(checkCommand, macroDicts);
}
string command = MacroProcessor::ResolveMacros(checkCommand, macroDicts);
CheckResult result;
void NagiosCheckTask::Run(void)
{
time_t now;
time(&now);
GetResult().SetScheduleStart(now);
result.SetScheduleStart(now);
m_Process = boost::make_shared<Process>(m_Command, boost::bind(&NagiosCheckTask::ProcessFinishedHandler, static_cast<NagiosCheckTask::Ptr>(GetSelf())));
m_Process->Start();
Process::Ptr process = boost::make_shared<Process>(command, boost::bind(&NagiosCheckTask::ProcessFinishedHandler, task, _1, result));
process->Start();
}
void NagiosCheckTask::ProcessFinishedHandler(void)
void NagiosCheckTask::ProcessFinishedHandler(const ScriptTask::Ptr& task, const AsyncTask::Ptr& aprocess, CheckResult result)
{
GetResult().SetExecutionStart(m_Process->GetExecutionStart());
GetResult().SetExecutionEnd(m_Process->GetExecutionEnd());
Process::Ptr process = static_pointer_cast<Process>(aprocess);
string output = m_Process->GetOutput();
long exitcode = m_Process->GetExitStatus();
m_Process.reset();
result.SetExecutionStart(process->GetExecutionStart());
result.SetExecutionEnd(process->GetExecutionEnd());
string output = process->GetOutput();
long exitcode = process->GetExitStatus();
boost::algorithm::trim(output);
ProcessCheckOutput(output);
ProcessCheckOutput(result, output);
ServiceState state;
@ -72,16 +80,17 @@ void NagiosCheckTask::ProcessFinishedHandler(void)
break;
}
GetResult().SetState(state);
result.SetState(state);
time_t now;
time(&now);
GetResult().SetScheduleEnd(now);
result.SetScheduleEnd(now);
Finish();
task->SetResult(result.GetDictionary());
task->Finish();
}
void NagiosCheckTask::ProcessCheckOutput(const string& output)
void NagiosCheckTask::ProcessCheckOutput(CheckResult& result, const string& output)
{
string text;
string perfdata;
@ -110,16 +119,12 @@ void NagiosCheckTask::ProcessCheckOutput(const string& output)
}
}
GetResult().SetOutput(text);
GetResult().SetPerformanceDataRaw(perfdata);
}
CheckTask::Ptr NagiosCheckTask::CreateTask(const Service& service, const CompletionCallback& completionCallback)
{
return boost::make_shared<NagiosCheckTask>(service, completionCallback);
result.SetOutput(text);
result.SetPerformanceDataRaw(perfdata);
}
void NagiosCheckTask::Register(void)
{
CheckTask::RegisterType("nagios", NagiosCheckTask::CreateTask);
ScriptFunction::Ptr func = boost::make_shared<ScriptFunction>(&NagiosCheckTask::ScriptFunc);
ScriptFunction::Register("builtin::NagiosCheck", func);
}

View File

@ -23,25 +23,16 @@
namespace icinga
{
class I2_CIB_API NagiosCheckTask : public CheckTask
class I2_CIB_API NagiosCheckTask
{
public:
typedef shared_ptr<NagiosCheckTask> Ptr;
typedef weak_ptr<NagiosCheckTask> WeakPtr;
NagiosCheckTask(const Service& service, const CompletionCallback& completionCallback);
static CheckTask::Ptr CreateTask(const Service& service, const CompletionCallback& completionCallback);
static void ScriptFunc(const ScriptTask::Ptr& task, const vector<Variant>& arguments);
static void Register(void);
private:
string m_Command;
Process::Ptr m_Process;
virtual void Run(void);
void ProcessFinishedHandler(void);
void ProcessCheckOutput(const string& output);
static void ProcessFinishedHandler(const ScriptTask::Ptr& task, const AsyncTask::Ptr& aprocess, CheckResult result);
static void ProcessCheckOutput(CheckResult& result, const string& output);
};
}

View File

@ -68,13 +68,6 @@ Dictionary::Ptr Service::GetMacros(void) const
return macros;
}
string Service::GetCheckType(void) const
{
string value = "nagios";
GetProperty("check_type", &value);
return value;
}
string Service::GetCheckCommand(void) const
{
string value;
@ -416,5 +409,5 @@ Dictionary::Ptr Service::ResolveDependencies(Host host, const Dictionary::Ptr& d
result->Set(name, name);
}
return result;
return result;
}

View File

@ -52,7 +52,6 @@ public:
string GetAlias(void) const;
Host GetHost(void) const;
Dictionary::Ptr GetMacros(void) const;
string GetCheckType(void) const;
string GetCheckCommand(void) const;
long GetMaxCheckAttempts(void) const;
long GetCheckInterval(void) const;

View File

@ -76,10 +76,16 @@ void CheckerComponent::CheckTimerHandler(void)
Logger::Write(LogDebug, "checker", "Executing service check for '" + service.GetName() + "'");
vector<Variant> arguments;
arguments.push_back(service.GetConfigObject());
ScriptTask::Ptr task;
task = service.InvokeHook("check", arguments, boost::bind(&CheckerComponent::CheckCompletedHandler, this, service, _1));
assert(task); /* TODO: gracefully handle missing hooks */
m_PendingServices.insert(service.GetConfigObject());
CheckTask::Ptr task = CheckTask::CreateTask(service, boost::bind(&CheckerComponent::CheckCompletedHandler, this, _1));
task->Start();
/*CheckTask::Ptr task = CheckTask::CreateTask(service, boost::bind(&CheckerComponent::CheckCompletedHandler, this, _1));
task->Start();*/
service.SetTag("current_task", task);
@ -93,10 +99,9 @@ void CheckerComponent::CheckTimerHandler(void)
Logger::Write(LogInformation, "checker", msgbuf.str());
}
void CheckerComponent::CheckCompletedHandler(const AsyncTask::Ptr& atask)
void CheckerComponent::CheckCompletedHandler(Service& service, const AsyncTask::Ptr& atask)
{
CheckTask::Ptr task = static_pointer_cast<CheckTask>(atask);
Service service = task->GetService();
ScriptTask::Ptr task = static_pointer_cast<ScriptTask>(atask);
service.RemoveTag("current_task");
@ -105,7 +110,16 @@ void CheckerComponent::CheckCompletedHandler(const AsyncTask::Ptr& atask)
if (m_PendingServices.find(service.GetConfigObject()) == m_PendingServices.end())
return;
CheckResult result = task->GetResult();
/* remove the service from the list of pending services */
m_PendingServices.erase(service.GetConfigObject());
m_Services.push(service);
Variant vresult = task->GetResult();
if (!vresult.IsObjectType<Dictionary>())
return;
CheckResult result = static_cast<Dictionary::Ptr>(vresult);
Logger::Write(LogDebug, "checker", "Got result for service '" + service.GetName() + "'");
long execution_time = result.GetExecutionEnd() - result.GetExecutionStart();
@ -117,10 +131,6 @@ void CheckerComponent::CheckCompletedHandler(const AsyncTask::Ptr& atask)
/* figure out when the next check is for this service */
service.UpdateNextCheck();
/* remove the service from the list of pending services */
m_PendingServices.erase(service.GetConfigObject());
m_Services.push(service);
RequestMessage rm;
rm.SetMethod("checker::CheckResult");

View File

@ -60,7 +60,7 @@ private:
void CheckTimerHandler(void);
void ResultTimerHandler(void);
void CheckCompletedHandler(const AsyncTask::Ptr& task);
void CheckCompletedHandler(Service& service, const AsyncTask::Ptr& atask);
void AdjustCheckTimer(void);

View File

@ -40,7 +40,9 @@ object host "localhost" {
}
abstract object service "nagios-service" {
check_type = "nagios",
hooks = {
check = "builtin::NagiosCheck"
},
macros = {
plugindir = "/usr/local/icinga/libexec"

View File

@ -34,6 +34,12 @@ IcingaApplication::IcingaApplication(void)
: m_PidPath(DefaultPidPath)
{ }
void TestScriptFunc(const ScriptTask::Ptr& task, const vector<Variant>& arguments)
{
std::cout << "Got " << arguments.size() << " arguments." << std::endl;
task->Finish();
}
/**
* The entry point for the Icinga application.
*