From 30aa16d9dc5ff96c73b04181d23e80621e27ecd1 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 14 Jul 2012 15:59:59 +0200 Subject: [PATCH] Implemented script tasks. --- base/Makefile.am | 4 ++ base/asynctask.h | 4 +- base/base.vcxproj | 4 ++ base/base.vcxproj.filters | 12 +++++ base/configobject.cpp | 23 +++++++++- base/configobject.h | 5 +- base/i2-base.h | 6 ++- base/scriptfunction.cpp | 36 +++++++++++++++ base/scriptfunction.h | 52 +++++++++++++++++++++ base/scripttask.cpp | 22 +++++++++ base/scripttask.h | 48 +++++++++++++++++++ cib/cib.vcxproj | 2 - cib/cib.vcxproj.filters | 6 --- cib/configobjectadapter.cpp | 6 +++ cib/configobjectadapter.h | 3 ++ cib/nagioschecktask.cpp | 61 +++++++++++++------------ cib/nagioschecktask.h | 17 ++----- cib/service.cpp | 9 +--- cib/service.h | 1 - components/checker/checkercomponent.cpp | 30 ++++++++---- components/checker/checkercomponent.h | 2 +- icinga-app/icinga-standalone.conf | 4 +- icinga/icingaapplication.cpp | 6 +++ 23 files changed, 286 insertions(+), 77 deletions(-) create mode 100644 base/scriptfunction.cpp create mode 100644 base/scriptfunction.h create mode 100644 base/scripttask.cpp create mode 100644 base/scripttask.h diff --git a/base/Makefile.am b/base/Makefile.am index dbf52b8fc..56bebb664 100644 --- a/base/Makefile.am +++ b/base/Makefile.am @@ -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 \ diff --git a/base/asynctask.h b/base/asynctask.h index d98dfd012..762c037c3 100644 --- a/base/asynctask.h +++ b/base/asynctask.h @@ -36,11 +36,11 @@ public: void Start(void); + void Finish(void); + protected: virtual void Run(void) = 0; - void Finish(void); - private: void ForwardCallback(void); diff --git a/base/base.vcxproj b/base/base.vcxproj index 3365e7e91..35d0bffc3 100644 --- a/base/base.vcxproj +++ b/base/base.vcxproj @@ -25,6 +25,8 @@ + + @@ -46,6 +48,8 @@ + + diff --git a/base/base.vcxproj.filters b/base/base.vcxproj.filters index 9e59fd00e..b033e23c3 100644 --- a/base/base.vcxproj.filters +++ b/base/base.vcxproj.filters @@ -82,6 +82,12 @@ Quelldateien + + Quelldateien + + + Quelldateien + @@ -168,6 +174,12 @@ Headerdateien + + Headerdateien + + + Headerdateien + diff --git a/base/configobject.cpp b/base/configobject.cpp index c80c09c08..14c526ba6 100644 --- a/base/configobject.cpp +++ b/base/configobject.cpp @@ -154,9 +154,9 @@ ConfigObject::Ptr ConfigObject::GetObject(string type, string name) bool ConfigObject::TypeAndNameGetter(const ConfigObject::Ptr& object, pair *key) { - *key = make_pair(object->GetType(), object->GetName()); + *key = make_pair(object->GetType(), object->GetName()); - return true; + return true; } function 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& 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(func, arguments, callback); + task->Start(); + + return task; +} diff --git a/base/configobject.h b/base/configobject.h index 6fbb1427c..293feda81 100644 --- a/base/configobject.h +++ b/base/configobject.h @@ -65,6 +65,9 @@ public: void RemoveTag(const string& key); + ScriptTask::Ptr InvokeHook(const string& hook, + const vector& 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 *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); }; diff --git a/base/i2-base.h b/base/i2-base.h index edc81aab0..5d875aeff 100644 --- a/base/i2-base.h +++ b/base/i2-base.h @@ -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 */ diff --git a/base/scriptfunction.cpp b/base/scriptfunction.cpp new file mode 100644 index 000000000..683736c86 --- /dev/null +++ b/base/scriptfunction.cpp @@ -0,0 +1,36 @@ +#include "i2-base.h" + +using namespace icinga; + +map 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::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& arguments) +{ + m_Callback(task, arguments); +} diff --git a/base/scriptfunction.h b/base/scriptfunction.h new file mode 100644 index 000000000..985922b76 --- /dev/null +++ b/base/scriptfunction.h @@ -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 Ptr; + typedef weak_ptr WeakPtr; + + typedef function&, const vector& 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& task, const vector& arguments); + +private: + Callback m_Callback; + + static map m_Functions; +}; + +} + +#endif /* SCRIPTFUNCTION_H */ \ No newline at end of file diff --git a/base/scripttask.cpp b/base/scripttask.cpp new file mode 100644 index 000000000..be1bd0f58 --- /dev/null +++ b/base/scripttask.cpp @@ -0,0 +1,22 @@ +#include "i2-base.h" + +using namespace icinga; + +ScriptTask::ScriptTask(const ScriptFunction::Ptr& function, const vector& 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; +} \ No newline at end of file diff --git a/base/scripttask.h b/base/scripttask.h new file mode 100644 index 000000000..20dbbc822 --- /dev/null +++ b/base/scripttask.h @@ -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 Ptr; + typedef weak_ptr WeakPtr; + + ScriptTask(const ScriptFunction::Ptr& function, const vector& arguments, CompletionCallback callback); + + void SetResult(const Variant& result); + Variant GetResult(void); + +protected: + virtual void Run(void); + +private: + ScriptFunction::Ptr m_Function; + vector m_Arguments; + Variant m_Result; +}; + +} + +#endif /* SCRIPTTASK_H */ diff --git a/cib/cib.vcxproj b/cib/cib.vcxproj index d0bce3a36..6e9dea9e0 100644 --- a/cib/cib.vcxproj +++ b/cib/cib.vcxproj @@ -81,7 +81,6 @@ - @@ -95,7 +94,6 @@ - diff --git a/cib/cib.vcxproj.filters b/cib/cib.vcxproj.filters index 0f8679232..cbd13955a 100644 --- a/cib/cib.vcxproj.filters +++ b/cib/cib.vcxproj.filters @@ -14,9 +14,6 @@ Headerdateien - - Headerdateien - Headerdateien @@ -52,9 +49,6 @@ Quelldateien - - Quelldateien - Quelldateien diff --git a/cib/configobjectadapter.cpp b/cib/configobjectadapter.cpp index 4185552b8..eec2c19e7 100644 --- a/cib/configobjectadapter.cpp +++ b/cib/configobjectadapter.cpp @@ -45,3 +45,9 @@ void ConfigObjectAdapter::RemoveTag(const string& key) { m_ConfigObject->RemoveTag(key); } + +ScriptTask::Ptr ConfigObjectAdapter::InvokeHook(const string& hook, + const vector& arguments, AsyncTask::CompletionCallback callback) +{ + return m_ConfigObject->InvokeHook(hook, arguments, callback); +} \ No newline at end of file diff --git a/cib/configobjectadapter.h b/cib/configobjectadapter.h index 6036a4464..c4ff5dd18 100644 --- a/cib/configobjectadapter.h +++ b/cib/configobjectadapter.h @@ -57,6 +57,9 @@ public: void RemoveTag(const string& key); + ScriptTask::Ptr InvokeHook(const string& hook, + const vector& arguments, AsyncTask::CompletionCallback callback); + private: ConfigObject::Ptr m_ConfigObject; }; diff --git a/cib/nagioschecktask.cpp b/cib/nagioschecktask.cpp index f2077cacf..74b154a61 100644 --- a/cib/nagioschecktask.cpp +++ b/cib/nagioschecktask.cpp @@ -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& arguments) { + if (arguments.size() < 1) + throw invalid_argument("Missing argument: Service must be specified."); + + Variant vservice = arguments[0]; + if (!vservice.IsObjectType()) + throw invalid_argument("Argument must be a config object."); + + Service service = static_cast(vservice); + string checkCommand = service.GetCheckCommand(); vector 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(m_Command, boost::bind(&NagiosCheckTask::ProcessFinishedHandler, static_cast(GetSelf()))); - m_Process->Start(); + Process::Ptr process = boost::make_shared(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(aprocess); + + result.SetExecutionStart(process->GetExecutionStart()); + result.SetExecutionEnd(process->GetExecutionEnd()); - string output = m_Process->GetOutput(); - long exitcode = m_Process->GetExitStatus(); - m_Process.reset(); + 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(service, completionCallback); + result.SetOutput(text); + result.SetPerformanceDataRaw(perfdata); } void NagiosCheckTask::Register(void) { - CheckTask::RegisterType("nagios", NagiosCheckTask::CreateTask); + ScriptFunction::Ptr func = boost::make_shared(&NagiosCheckTask::ScriptFunc); + ScriptFunction::Register("builtin::NagiosCheck", func); } diff --git a/cib/nagioschecktask.h b/cib/nagioschecktask.h index 1a3e4a581..f24242514 100644 --- a/cib/nagioschecktask.h +++ b/cib/nagioschecktask.h @@ -23,25 +23,16 @@ namespace icinga { -class I2_CIB_API NagiosCheckTask : public CheckTask +class I2_CIB_API NagiosCheckTask { public: - typedef shared_ptr Ptr; - typedef weak_ptr 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& 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); }; } diff --git a/cib/service.cpp b/cib/service.cpp index b15d28f90..8092e024c 100644 --- a/cib/service.cpp +++ b/cib/service.cpp @@ -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; } diff --git a/cib/service.h b/cib/service.h index 3232bb557..9c9d650d3 100644 --- a/cib/service.h +++ b/cib/service.h @@ -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; diff --git a/components/checker/checkercomponent.cpp b/components/checker/checkercomponent.cpp index b24fedba9..d4b88ea4a 100644 --- a/components/checker/checkercomponent.cpp +++ b/components/checker/checkercomponent.cpp @@ -76,10 +76,16 @@ void CheckerComponent::CheckTimerHandler(void) Logger::Write(LogDebug, "checker", "Executing service check for '" + service.GetName() + "'"); + vector 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(atask); - Service service = task->GetService(); + ScriptTask::Ptr task = static_pointer_cast(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()) + return; + + CheckResult result = static_cast(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"); diff --git a/components/checker/checkercomponent.h b/components/checker/checkercomponent.h index 3700d4e31..fa26863a0 100644 --- a/components/checker/checkercomponent.h +++ b/components/checker/checkercomponent.h @@ -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); diff --git a/icinga-app/icinga-standalone.conf b/icinga-app/icinga-standalone.conf index 46316c2e1..87ff4dbf9 100644 --- a/icinga-app/icinga-standalone.conf +++ b/icinga-app/icinga-standalone.conf @@ -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" diff --git a/icinga/icingaapplication.cpp b/icinga/icingaapplication.cpp index 3ca027a84..53e202faf 100644 --- a/icinga/icingaapplication.cpp +++ b/icinga/icingaapplication.cpp @@ -34,6 +34,12 @@ IcingaApplication::IcingaApplication(void) : m_PidPath(DefaultPidPath) { } +void TestScriptFunc(const ScriptTask::Ptr& task, const vector& arguments) +{ + std::cout << "Got " << arguments.size() << " arguments." << std::endl; + task->Finish(); +} + /** * The entry point for the Icinga application. * -- 2.40.0