From: Gunnar Beutner Date: Thu, 13 Nov 2014 10:23:57 +0000 (+0100) Subject: Implement support for executing remote commands X-Git-Tag: v2.2.0~37 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7321e45abc49be2942379739ec273657c16e4c37;p=icinga2 Implement support for executing remote commands fixes #7559 --- diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index 77c4495c7..b907ca000 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -76,7 +76,7 @@ bool DynamicObject::IsPaused(void) const return GetPaused(); } -void DynamicObject::SetExtension(const String& key, const Object::Ptr& object) +void DynamicObject::SetExtension(const String& key, const Value& value) { Dictionary::Ptr extensions = GetExtensions(); @@ -85,15 +85,15 @@ void DynamicObject::SetExtension(const String& key, const Object::Ptr& object) SetExtensions(extensions); } - extensions->Set(key, object); + extensions->Set(key, value); } -Object::Ptr DynamicObject::GetExtension(const String& key) +Value DynamicObject::GetExtension(const String& key) { Dictionary::Ptr extensions = GetExtensions(); if (!extensions) - return Object::Ptr(); + return Empty; return extensions->Get(key); } diff --git a/lib/base/dynamicobject.hpp b/lib/base/dynamicobject.hpp index 46e3a24d6..bcae37a20 100644 --- a/lib/base/dynamicobject.hpp +++ b/lib/base/dynamicobject.hpp @@ -60,8 +60,8 @@ public: bool IsActive(void) const; bool IsPaused(void) const; - void SetExtension(const String& key, const Object::Ptr& object); - Object::Ptr GetExtension(const String& key); + void SetExtension(const String& key, const Value& value); + Value GetExtension(const String& key); void ClearExtension(const String& key); void Register(void); diff --git a/lib/base/scriptfunctionwrapper.hpp b/lib/base/scriptfunctionwrapper.hpp index 4f8002de2..e0b08be41 100644 --- a/lib/base/scriptfunctionwrapper.hpp +++ b/lib/base/scriptfunctionwrapper.hpp @@ -268,6 +268,96 @@ boost::function& arguments)> WrapScriptFunction( return boost::bind(&ScriptFunctionWrapperR, function, _1); } +template +Value ScriptFunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5, T6), const std::vector& arguments) +{ + if (arguments.size() < 7) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); + + function(static_cast(arguments[0]), + static_cast(arguments[1]), + static_cast(arguments[2]), + static_cast(arguments[3]), + static_cast(arguments[4]), + static_cast(arguments[5]), + static_cast(arguments[6])); + + return Empty; +} + +template +boost::function& arguments)> WrapScriptFunction(void (*function)(T0, T1, T2, T3, T4, T5, T6)) +{ + return boost::bind(&ScriptFunctionWrapperV, function, _1); +} + +template +Value ScriptFunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5, T6), const std::vector& arguments) +{ + if (arguments.size() < 7) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); + + return function(static_cast(arguments[0]), + static_cast(arguments[1]), + static_cast(arguments[2]), + static_cast(arguments[3]), + static_cast(arguments[4]), + static_cast(arguments[5]), + static_cast(arguments[6])); +} + +template +boost::function& arguments)> WrapScriptFunction(TR (*function)(T0, T1, T2, T3, T4, T5, T6)) +{ + return boost::bind(&ScriptFunctionWrapperR, function, _1); +} + +template +Value ScriptFunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5, T6, T7), const std::vector& arguments) +{ + if (arguments.size() < 8) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); + + function(static_cast(arguments[0]), + static_cast(arguments[1]), + static_cast(arguments[2]), + static_cast(arguments[3]), + static_cast(arguments[4]), + static_cast(arguments[5]), + static_cast(arguments[6]), + static_cast(arguments[7])); + + return Empty; +} + +template +boost::function& arguments)> WrapScriptFunction(void (*function)(T0, T1, T2, T3, T4, T5, T6, T7)) +{ + return boost::bind(&ScriptFunctionWrapperV, function, _1); +} + +template +Value ScriptFunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5, T6, T7), const std::vector& arguments) +{ + if (arguments.size() < 8) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); + + return function(static_cast(arguments[0]), + static_cast(arguments[1]), + static_cast(arguments[2]), + static_cast(arguments[3]), + static_cast(arguments[4]), + static_cast(arguments[5]), + static_cast(arguments[6]), + static_cast(arguments[7])); +} + +template +boost::function& arguments)> WrapScriptFunction(TR (*function)(T0, T1, T2, T3, T4, T5, T6, T7)) +{ + return boost::bind(&ScriptFunctionWrapperR, function, _1); +} + template boost::function& arguments)> WrapScriptFunction(TR (*function)(const std::vector&)) { diff --git a/lib/base/threadpool.cpp b/lib/base/threadpool.cpp index 3ffae3a93..b9771c406 100644 --- a/lib/base/threadpool.cpp +++ b/lib/base/threadpool.cpp @@ -48,7 +48,7 @@ void ThreadPool::Start(void) for (size_t i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) m_Queues[i].SpawnWorker(m_ThreadGroup); - m_MgmtThread = boost::move(boost::thread(boost::bind(&ThreadPool::ManagerThreadProc, this))); + m_MgmtThread = boost::thread(boost::bind(&ThreadPool::ManagerThreadProc, this)); } void ThreadPool::Stop(void) diff --git a/lib/cli/nodewizardcommand.cpp b/lib/cli/nodewizardcommand.cpp index 2612cf78a..ffc9b1c01 100644 --- a/lib/cli/nodewizardcommand.cpp +++ b/lib/cli/nodewizardcommand.cpp @@ -76,8 +76,6 @@ int NodeWizardCommand::Run(const boost::program_options::variables_map& vm, cons << "\n" << "We'll guide you through all required configuration details.\n" << "\n" - << "If you have questions, please consult the documentation at http://docs.icinga.org\n" - << "or join the community support channels at https://support.icinga.org\n" << "\n\n" << ConsoleColorTag(Console_Normal); //TODO: Add sort of bash completion to path input? @@ -315,7 +313,7 @@ wizard_master_host: wizard_ticket: std::cout << ConsoleColorTag(Console_Bold) << "Please specify the request ticket generated on your Icinga 2 master." << ConsoleColorTag(Console_Normal) << "\n" - << " (Hint: '# icinga2 pki ticket --cn " << cn << "'):\n"; + << " (Hint: '# icinga2 pki ticket --cn '" << cn << "'): "; std::getline(std::cin, answer); boost::algorithm::to_lower(answer); @@ -621,8 +619,5 @@ wizard_ticket: std::cout << "Now restart your Icinga 2 daemon to finish the installation!\n\n"; - std::cout << "If you encounter problems or bugs, please do not hesitate to\n" - << "get in touch with the community at https://support.icinga.org" << std::endl; - return 0; } diff --git a/lib/db_ido/dbobject.cpp b/lib/db_ido/dbobject.cpp index 28fbf8aee..c24f1559b 100644 --- a/lib/db_ido/dbobject.cpp +++ b/lib/db_ido/dbobject.cpp @@ -293,7 +293,7 @@ void DbObject::OnStatusUpdate(void) DbObject::Ptr DbObject::GetOrCreateByObject(const DynamicObject::Ptr& object) { - DbObject::Ptr dbobj = static_pointer_cast(object->GetExtension("DbObject")); + DbObject::Ptr dbobj = object->GetExtension("DbObject"); if (dbobj) return dbobj; diff --git a/lib/hello/CMakeLists.txt b/lib/hello/CMakeLists.txt index ce92e30f0..2a11666c5 100644 --- a/lib/hello/CMakeLists.txt +++ b/lib/hello/CMakeLists.txt @@ -29,7 +29,7 @@ endif() add_library(hello SHARED ${hello_SOURCES}) -target_link_libraries(hello ${Boost_LIBRARIES} base config) +target_link_libraries(hello ${Boost_LIBRARIES} base config icinga) set_target_properties ( hello PROPERTIES @@ -42,5 +42,3 @@ install( RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) - - diff --git a/lib/hello/hello.cpp b/lib/hello/hello.cpp index bd9d0597f..601380373 100644 --- a/lib/hello/hello.cpp +++ b/lib/hello/hello.cpp @@ -18,8 +18,13 @@ ******************************************************************************/ #include "hello/hello.hpp" +#include "icinga/host.hpp" +#include "icinga/checkcommand.hpp" #include "base/dynamictype.hpp" #include "base/logger.hpp" +#include "base/json.hpp" +#include "base/serializer.hpp" +#include using namespace icinga; @@ -34,5 +39,35 @@ int Hello::Main(void) { Log(LogInformation, "Hello", "Hello World!"); + Host::Ptr host = Host::GetByName("test"); + CheckCommand::Ptr command = host->GetCheckCommand(); + + Dictionary::Ptr macros = new Dictionary(); + + command->Execute(host, CheckResult::Ptr(), macros); + + std::cout << JsonEncode(macros) << std::endl; + + Host::Ptr host2 = new Host(); + Dictionary::Ptr attrs = new Dictionary(); + + attrs->Set("__name", "keks"); + attrs->Set("type", "Host"); + attrs->Set("check_command", "http"); + attrs->Set("command_endpoint", "test"); + + Deserialize(host2, attrs, false, FAConfig); + + host2->SetExtension("agent_service_name", "foobar"); + + static_pointer_cast(host2)->OnStateLoaded(); + static_pointer_cast(host2)->OnConfigLoaded(); + + std::cout << host2->GetName() << std::endl; + + host2->ExecuteCheck(macros, true); + + Utility::Sleep(30); + return 0; } diff --git a/lib/icinga/apievents.cpp b/lib/icinga/apievents.cpp index dc354199a..fdcd43418 100644 --- a/lib/icinga/apievents.cpp +++ b/lib/icinga/apievents.cpp @@ -63,6 +63,7 @@ REGISTER_APIFUNCTION(RemoveDowntime, event, &ApiEvents::DowntimeRemovedAPIHandle REGISTER_APIFUNCTION(SetAcknowledgement, event, &ApiEvents::AcknowledgementSetAPIHandler); REGISTER_APIFUNCTION(ClearAcknowledgement, event, &ApiEvents::AcknowledgementClearedAPIHandler); REGISTER_APIFUNCTION(UpdateRepository, event, &ApiEvents::UpdateRepositoryAPIHandler); +REGISTER_APIFUNCTION(ExecuteCommand, event, &ApiEvents::ExecuteCommandAPIHandler); static Timer::Ptr l_RepositoryTimer; @@ -100,13 +101,8 @@ void ApiEvents::StaticInitialize(void) l_RepositoryTimer->Reschedule(0); } -void ApiEvents::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MessageOrigin& origin) +Dictionary::Ptr ApiEvents::MakeCheckResultMessage(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { - ApiListener::Ptr listener = ApiListener::GetInstance(); - - if (!listener) - return; - Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::CheckResult"); @@ -119,16 +115,35 @@ void ApiEvents::CheckResultHandler(const Checkable::Ptr& checkable, const CheckR params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); + else { + Value agent_service_name = checkable->GetExtension("agent_service_name"); + + if (!agent_service_name.IsEmpty()) + params->Set("service", agent_service_name); + } params->Set("cr", Serialize(cr)); message->Set("params", params); + return message; +} + +void ApiEvents::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MessageOrigin& origin) +{ + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (!listener) + return; + + Dictionary::Ptr message = MakeCheckResultMessage(checkable, cr); listener->RelayMessage(origin, checkable, message, true); } Value ApiEvents::CheckResultAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params) { - if (!origin.FromClient->GetEndpoint()) + Endpoint::Ptr endpoint = origin.FromClient->GetEndpoint(); + + if (!endpoint) return Empty; if (!params) @@ -175,7 +190,7 @@ Value ApiEvents::CheckResultAPIHandler(const MessageOrigin& origin, const Dictio if (!checkable) return Empty; - if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable)) + if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable) && endpoint != checkable->GetCommandEndpoint()) return Empty; checkable->ProcessCheckResult(cr, origin); @@ -1493,6 +1508,73 @@ Value ApiEvents::AcknowledgementClearedAPIHandler(const MessageOrigin& origin, c return Empty; } +Value ApiEvents::ExecuteCommandAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params) +{ + Endpoint::Ptr endpoint = origin.FromClient->GetEndpoint(); + + if (!endpoint || (origin.FromZone && !Zone::GetLocalZone()->IsChildOf(origin.FromZone))) + return Empty; + + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (!listener) { + Log(LogCritical, "ApiListener", "No instance available."); + return Empty; + } + + if (!listener->GetAcceptCommands()) { + Log(LogWarning, "ApiListener") + << "Ignoring command. '" << listener->GetName() << "' does not accept commands."; + return Empty; + } + + Host::Ptr host = new Host(); + Dictionary::Ptr attrs = new Dictionary(); + + attrs->Set("__name", params->Get("host")); + attrs->Set("type", "Host"); + + String command = params->Get("command"); + String command_type = params->Get("command_type"); + + if (command_type == "check_command") { + if (!CheckCommand::GetByName(command)) { + CheckResult::Ptr cr = new CheckResult(); + cr->SetState(ServiceUnknown); + cr->SetOutput("Check command '" + command + "' does not exist."); + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); + listener->SyncSendMessage(endpoint, message); + return Empty; + } + } else if (command_type == "event_command") { + if (!EventCommand::GetByName(command)) + return Empty; + } else + return Empty; + + attrs->Set(command_type, params->Get("command")); + attrs->Set("command_endpoint", endpoint->GetName()); + + Deserialize(host, attrs, false, FAConfig); + + if (params->Contains("service")) + host->SetExtension("agent_service_name", params->Get("service")); + + host->SetExtension("agent_check", true); + + static_pointer_cast(host)->OnStateLoaded(); + static_pointer_cast(host)->OnConfigLoaded(); + + Dictionary::Ptr macros = params->Get("macros"); + + if (command_type == "check_command") + host->ExecuteCheck(macros, true); + else if (command_type == "event_command") + host->ExecuteEventHandler(macros, true); + + return Empty; +} + void ApiEvents::RepositoryTimerHandler(void) { ApiListener::Ptr listener = ApiListener::GetInstance(); diff --git a/lib/icinga/apievents.hpp b/lib/icinga/apievents.hpp index 2eb0078de..e76cea5c1 100644 --- a/lib/icinga/apievents.hpp +++ b/lib/icinga/apievents.hpp @@ -109,9 +109,13 @@ public: static void AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin& origin); static Value AcknowledgementClearedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params); + static Value ExecuteCommandAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params); + static String GetRepositoryDir(void); static void RepositoryTimerHandler(void); static Value UpdateRepositoryAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params); + + static Dictionary::Ptr MakeCheckResultMessage(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); }; } diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index 77c4cd465..f3d90493d 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -23,7 +23,9 @@ #include "icinga/checkcommand.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/cib.hpp" +#include "icinga/apievents.hpp" #include "remote/messageorigin.hpp" +#include "remote/apilistener.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/convert.hpp" @@ -255,6 +257,19 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig if (origin.IsLocal()) cr->SetCheckSource(IcingaApplication::GetInstance()->GetNodeName()); + Endpoint::Ptr command_endpoint = GetCommandEndpoint(); + + if (command_endpoint && GetExtension("agent_check")) { + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (listener) { + Dictionary::Ptr message = ApiEvents::MakeCheckResultMessage(this, cr); + listener->SyncSendMessage(command_endpoint, message); + } + + return; + } + bool reachable = IsReachable(); bool notification_reachable = IsReachable(DependencyNotification); @@ -470,7 +485,7 @@ bool Checkable::IsCheckPending(void) const return m_CheckRunning; } -void Checkable::ExecuteCheck(void) +void Checkable::ExecuteCheck(const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CONTEXT("Executing check for object '" + GetName() + "'"); @@ -503,7 +518,52 @@ void Checkable::ExecuteCheck(void) result->SetScheduleStart(scheduled_start); result->SetExecutionStart(before_check); - GetCheckCommand()->Execute(this, result); + Dictionary::Ptr macros; + Endpoint::Ptr endpoint = GetCommandEndpoint(); + + if (endpoint && !useResolvedMacros) + macros = new Dictionary(); + else + macros = resolvedMacros; + + GetCheckCommand()->Execute(this, result, macros, useResolvedMacros); + + if (endpoint && !useResolvedMacros) { + if (endpoint->IsConnected()) { + Dictionary::Ptr message = new Dictionary(); + message->Set("jsonrpc", "2.0"); + message->Set("method", "event::ExecuteCommand"); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(this); + + Dictionary::Ptr params = new Dictionary(); + message->Set("params", params); + params->Set("command_type", "check_command"); + params->Set("command", GetCheckCommand()->GetName()); + params->Set("host", host->GetName()); + + if (service) + params->Set("service", service->GetShortName()); + + params->Set("macros", macros); + + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (listener) + listener->SyncSendMessage(endpoint, message); + } else if (Application::GetInstance()->GetStartTime() < Utility::GetTime() - 30) { + result->SetState(ServiceUnknown); + result->SetOutput("Remote Icinga instance '" + endpoint->GetName() + "' is not connected."); + ProcessCheckResult(result); + } + + { + ObjectLock olock(this); + m_CheckRunning = false; + } + } } void Checkable::UpdateStatistics(const CheckResult::Ptr& cr, CheckableType type) diff --git a/lib/icinga/checkable-event.cpp b/lib/icinga/checkable-event.cpp index 86e450ddf..ee3acf136 100644 --- a/lib/icinga/checkable-event.cpp +++ b/lib/icinga/checkable-event.cpp @@ -20,6 +20,8 @@ #include "icinga/checkable.hpp" #include "icinga/eventcommand.hpp" #include "icinga/icingaapplication.hpp" +#include "icinga/service.hpp" +#include "remote/apilistener.hpp" #include "base/logger.hpp" #include "base/context.hpp" @@ -63,7 +65,7 @@ void Checkable::SetEventCommand(const EventCommand::Ptr& command, const MessageO OnEventCommandChanged(this, command, origin); } -void Checkable::ExecuteEventHandler(void) +void Checkable::ExecuteEventHandler(const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CONTEXT("Executing event handler for object '" + GetName() + "'"); @@ -78,7 +80,43 @@ void Checkable::ExecuteEventHandler(void) Log(LogNotice, "Checkable") << "Executing event handler '" << ec->GetName() << "' for service '" << GetName() << "'"; - ec->Execute(this); + Dictionary::Ptr macros; + Endpoint::Ptr endpoint = GetCommandEndpoint(); + + if (endpoint && !useResolvedMacros) + macros = new Dictionary(); + else + macros = resolvedMacros; + + ec->Execute(this, macros, useResolvedMacros); + + if (endpoint) { + Dictionary::Ptr message = new Dictionary(); + message->Set("jsonrpc", "2.0"); + message->Set("method", "event::ExecuteCommand"); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(this); + + Dictionary::Ptr params = new Dictionary(); + message->Set("params", params); + params->Set("command_type", "event_command"); + params->Set("command", GetEventCommand()->GetName()); + params->Set("host", host->GetName()); + + if (service) + params->Set("service", service->GetShortName()); + + params->Set("macros", macros); + + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (listener) + listener->SyncSendMessage(endpoint, message); + + return; + } OnEventCommandExecuted(this); } diff --git a/lib/icinga/checkable.cpp b/lib/icinga/checkable.cpp index 76a064911..737b5e1f1 100644 --- a/lib/icinga/checkable.cpp +++ b/lib/icinga/checkable.cpp @@ -258,3 +258,8 @@ void Checkable::SetModifiedAttributes(int flags, const MessageOrigin& origin) OnVarsChanged(this, GetVars(), origin); } } + +Endpoint::Ptr Checkable::GetCommandEndpoint(void) const +{ + return Endpoint::GetByName(GetCommandEndpointRaw()); +} diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index 99d6c90d6..5f414539c 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -26,6 +26,7 @@ #include "icinga/notification.hpp" #include "icinga/comment.hpp" #include "icinga/downtime.hpp" +#include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" namespace icinga @@ -134,12 +135,15 @@ public: static void UpdateStatistics(const CheckResult::Ptr& cr, CheckableType type); - void ExecuteCheck(void); + void ExecuteCheck(const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), + bool useResolvedMacros = false); void ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin& origin = MessageOrigin()); int GetModifiedAttributes(void) const; void SetModifiedAttributes(int flags, const MessageOrigin& origin = MessageOrigin()); + Endpoint::Ptr GetCommandEndpoint(void) const; + bool IsCheckPending(void) const; static double CalculateExecutionTime(const CheckResult::Ptr& cr); @@ -241,7 +245,8 @@ public: void ResetNotificationNumbers(void); /* Event Handler */ - void ExecuteEventHandler(void); + void ExecuteEventHandler(const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), + bool useResolvedMacros = false); intrusive_ptr GetEventCommand(void) const; void SetEventCommand(const intrusive_ptr& command, const MessageOrigin& origin = MessageOrigin()); diff --git a/lib/icinga/checkable.ti b/lib/icinga/checkable.ti index 65d420094..fbac2687d 100644 --- a/lib/icinga/checkable.ti +++ b/lib/icinga/checkable.ti @@ -146,6 +146,8 @@ abstract class Checkable : CustomVarObject [state] Value override_check_command; [state] Value override_max_check_attempts; [state] Value override_check_period; + + [config] String command_endpoint (CommandEndpointRaw); }; } diff --git a/lib/icinga/checkcommand.cpp b/lib/icinga/checkcommand.cpp index ff7728f06..2ad18c14c 100644 --- a/lib/icinga/checkcommand.cpp +++ b/lib/icinga/checkcommand.cpp @@ -24,10 +24,13 @@ using namespace icinga; REGISTER_TYPE(CheckCommand); -void CheckCommand::Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) +void CheckCommand::Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { std::vector arguments; arguments.push_back(checkable); arguments.push_back(cr); + arguments.push_back(resolvedMacros); + arguments.push_back(useResolvedMacros); InvokeMethod("execute", arguments); } diff --git a/lib/icinga/checkcommand.hpp b/lib/icinga/checkcommand.hpp index dde46ec58..f6349a3cc 100644 --- a/lib/icinga/checkcommand.hpp +++ b/lib/icinga/checkcommand.hpp @@ -37,7 +37,9 @@ public: DECLARE_OBJECT(CheckCommand); DECLARE_OBJECTNAME(CheckCommand); - virtual void Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); + virtual void Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), + bool useResolvedMacros = false); }; } diff --git a/lib/icinga/eventcommand.cpp b/lib/icinga/eventcommand.cpp index 2a0b92e7b..3ad50a992 100644 --- a/lib/icinga/eventcommand.cpp +++ b/lib/icinga/eventcommand.cpp @@ -23,9 +23,12 @@ using namespace icinga; REGISTER_TYPE(EventCommand); -void EventCommand::Execute(const Checkable::Ptr& checkable) +void EventCommand::Execute(const Checkable::Ptr& checkable, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { std::vector arguments; arguments.push_back(checkable); + arguments.push_back(resolvedMacros); + arguments.push_back(useResolvedMacros); InvokeMethod("execute", arguments); } diff --git a/lib/icinga/eventcommand.hpp b/lib/icinga/eventcommand.hpp index 605477526..d9b4c569c 100644 --- a/lib/icinga/eventcommand.hpp +++ b/lib/icinga/eventcommand.hpp @@ -37,7 +37,9 @@ public: DECLARE_OBJECT(EventCommand); DECLARE_OBJECTNAME(EventCommand); - virtual void Execute(const Checkable::Ptr& checkable); + virtual void Execute(const Checkable::Ptr& checkable, + const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), + bool useResolvedMacros = false); }; } diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf index de9861f6c..4c8d06772 100644 --- a/lib/icinga/icinga-type.conf +++ b/lib/icinga/icinga-type.conf @@ -54,6 +54,8 @@ %attribute %string "action_url", %attribute %string "icon_image", %attribute %string "icon_image_alt", + + %attribute %name(Endpoint) "command_endpoint", } %type Host %inherits Checkable { @@ -134,6 +136,8 @@ %attribute %array "states" { %attribute %number "*" }, + + %attribute %name(Endpoint) "command_endpoint", } %type User { diff --git a/lib/icinga/macroprocessor.cpp b/lib/icinga/macroprocessor.cpp index 05ce4a429..d47cec010 100644 --- a/lib/icinga/macroprocessor.cpp +++ b/lib/icinga/macroprocessor.cpp @@ -34,7 +34,8 @@ using namespace icinga; Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolvers, const CheckResult::Ptr& cr, String *missingMacro, - const MacroProcessor::EscapeCallback& escapeFn) + const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, + bool useResolvedMacros) { Value result; @@ -42,7 +43,8 @@ Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolv return Empty; if (str.IsScalar()) { - result = InternalResolveMacros(str, resolvers, cr, missingMacro, escapeFn); + result = InternalResolveMacros(str, resolvers, cr, missingMacro, escapeFn, + resolvedMacros, useResolvedMacros); } else if (str.IsObjectType()) { Array::Ptr resultArr = new Array(); Array::Ptr arr = str; @@ -51,7 +53,8 @@ Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolv BOOST_FOREACH(const Value& arg, arr) { /* Note: don't escape macros here. */ - resultArr->Add(InternalResolveMacros(arg, resolvers, cr, missingMacro, EscapeCallback())); + resultArr->Add(InternalResolveMacros(arg, resolvers, cr, missingMacro, + EscapeCallback(), resolvedMacros, useResolvedMacros)); } result = resultArr; @@ -160,7 +163,8 @@ bool MacroProcessor::ResolveMacro(const String& macro, const ResolverList& resol String MacroProcessor::InternalResolveMacros(const String& str, const ResolverList& resolvers, const CheckResult::Ptr& cr, String *missingMacro, - const MacroProcessor::EscapeCallback& escapeFn, int recursionLevel) + const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, + bool useResolvedMacros, int recursionLevel) { CONTEXT("Resolving macros for string '" + str + "'"); @@ -181,7 +185,16 @@ String MacroProcessor::InternalResolveMacros(const String& str, const ResolverLi String resolved_macro; bool recursive_macro; - bool found = ResolveMacro(name, resolvers, cr, &resolved_macro, &recursive_macro); + bool found; + + if (useResolvedMacros) { + recursive_macro = false; + found = resolvedMacros->Contains(name); + + if (found) + resolved_macro = resolvedMacros->Get(name); + } else + found = ResolveMacro(name, resolvers, cr, &resolved_macro, &recursive_macro); /* $$ is an escape sequence for $. */ if (name.IsEmpty()) { @@ -200,7 +213,11 @@ String MacroProcessor::InternalResolveMacros(const String& str, const ResolverLi /* recursively resolve macros in the macro if it was a user macro */ if (recursive_macro) resolved_macro = InternalResolveMacros(resolved_macro, - resolvers, cr, missingMacro, EscapeCallback(), recursionLevel + 1); + resolvers, cr, missingMacro, EscapeCallback(), Dictionary::Ptr(), + false, recursionLevel + 1); + + if (!useResolvedMacros && found && resolvedMacros) + resolvedMacros->Set(name, resolved_macro); if (escapeFn) resolved_macro = escapeFn(resolved_macro); diff --git a/lib/icinga/macroprocessor.hpp b/lib/icinga/macroprocessor.hpp index 4fb27a9db..a7e0b0f9c 100644 --- a/lib/icinga/macroprocessor.hpp +++ b/lib/icinga/macroprocessor.hpp @@ -43,7 +43,9 @@ public: static Value ResolveMacros(const Value& str, const ResolverList& resolvers, const CheckResult::Ptr& cr = CheckResult::Ptr(), String *missingMacro = NULL, - const EscapeCallback& escapeFn = EscapeCallback()); + const EscapeCallback& escapeFn = EscapeCallback(), + const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), + bool useResolvedMacros = false); private: MacroProcessor(void); @@ -53,6 +55,7 @@ private: static String InternalResolveMacros(const String& str, const ResolverList& resolvers, const CheckResult::Ptr& cr, String *missingMacro, const EscapeCallback& escapeFn, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel = 0); }; diff --git a/lib/icinga/notification.cpp b/lib/icinga/notification.cpp index a5c561aeb..930cdde02 100644 --- a/lib/icinga/notification.cpp +++ b/lib/icinga/notification.cpp @@ -519,3 +519,9 @@ void Notification::ValidateFilters(const String& location, const Dictionary::Ptr location + ": Type filter is invalid."); } } + +Endpoint::Ptr Notification::GetCommandEndpoint(void) const +{ + return Endpoint::GetByName(GetCommandEndpointRaw()); +} + diff --git a/lib/icinga/notification.hpp b/lib/icinga/notification.hpp index 64cd8f7ab..a10f181d9 100644 --- a/lib/icinga/notification.hpp +++ b/lib/icinga/notification.hpp @@ -26,6 +26,7 @@ #include "icinga/usergroup.hpp" #include "icinga/timeperiod.hpp" #include "icinga/checkresult.hpp" +#include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" #include "base/array.hpp" @@ -98,6 +99,7 @@ public: bool CheckNotificationUserFilters(NotificationType type, const User::Ptr& user, bool force); void ResetNotifiedUsers(void); + Endpoint::Ptr GetCommandEndpoint(void) const; static String NotificationTypeToString(NotificationType type); diff --git a/lib/icinga/notification.ti b/lib/icinga/notification.ti index dfe6be4be..c0e3591b2 100644 --- a/lib/icinga/notification.ti +++ b/lib/icinga/notification.ti @@ -51,6 +51,8 @@ class Notification : CustomVarObject < NotificationNameComposer [state, set_protected] double next_notification (NextNotificationRaw); [state, set_protected] Value notification_number; [state] double last_problem_notification; + + [config] String command_endpoint (CommandEndpointRaw); }; } diff --git a/lib/icinga/notificationcommand.cpp b/lib/icinga/notificationcommand.cpp index ab00c30a6..c84aa2986 100644 --- a/lib/icinga/notificationcommand.cpp +++ b/lib/icinga/notificationcommand.cpp @@ -24,8 +24,9 @@ using namespace icinga; REGISTER_TYPE(NotificationCommand); Dictionary::Ptr NotificationCommand::Execute(const Notification::Ptr& notification, - const User::Ptr& user, const CheckResult::Ptr& cr, const NotificationType& type, - const String& author, const String& comment) + const User::Ptr& user, const CheckResult::Ptr& cr, const NotificationType& type, + const String& author, const String& comment, const Dictionary::Ptr& resolvedMacros, + bool useResolvedMacros) { std::vector arguments; arguments.push_back(notification); @@ -34,5 +35,7 @@ Dictionary::Ptr NotificationCommand::Execute(const Notification::Ptr& notificati arguments.push_back(type); arguments.push_back(author); arguments.push_back(comment); + arguments.push_back(resolvedMacros); + arguments.push_back(useResolvedMacros); return InvokeMethod("execute", arguments); } diff --git a/lib/icinga/notificationcommand.hpp b/lib/icinga/notificationcommand.hpp index be8d069ff..98a106e88 100644 --- a/lib/icinga/notificationcommand.hpp +++ b/lib/icinga/notificationcommand.hpp @@ -41,7 +41,9 @@ public: virtual Dictionary::Ptr Execute(const intrusive_ptr& notification, const User::Ptr& user, const CheckResult::Ptr& cr, const NotificationType& type, - const String& author, const String& comment); + const String& author, const String& comment, + const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), + bool useResolvedMacros = false); }; } diff --git a/lib/icinga/pluginutility.cpp b/lib/icinga/pluginutility.cpp index 87f95cb48..736d7f465 100644 --- a/lib/icinga/pluginutility.cpp +++ b/lib/icinga/pluginutility.cpp @@ -52,6 +52,7 @@ struct CommandArgument 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& callback) { Value raw_command = commandObj->GetCommandLine(); @@ -59,7 +60,8 @@ void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkab Value command; if (!raw_arguments || raw_command.IsObjectType()) - command = MacroProcessor::ResolveMacros(raw_command, macroResolvers, cr, NULL, Utility::EscapeShellArg); + command = MacroProcessor::ResolveMacros(raw_command, macroResolvers, cr, NULL, + Utility::EscapeShellArg, resolvedMacros, useResolvedMacros); else { Array::Ptr arr = new Array(); arr->Add(raw_command); @@ -92,7 +94,8 @@ void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkab if (!set_if.IsEmpty()) { String missingMacro; String set_if_resolved = MacroProcessor::ResolveMacros(set_if, macroResolvers, - cr, &missingMacro); + cr, &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros, + useResolvedMacros); if (!missingMacro.IsEmpty()) continue; @@ -116,7 +119,8 @@ void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkab String missingMacro; arg.Value = MacroProcessor::ResolveMacros(argval, macroResolvers, - cr, &missingMacro); + cr, &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros, + useResolvedMacros); if (!missingMacro.IsEmpty()) { if (required) { @@ -165,12 +169,17 @@ void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkab BOOST_FOREACH(const Dictionary::Pair& kv, env) { String name = kv.second; - Value value = MacroProcessor::ResolveMacros(name, macroResolvers, cr); + Value value = MacroProcessor::ResolveMacros(name, macroResolvers, cr, + NULL, MacroProcessor::EscapeCallback(), resolvedMacros, + useResolvedMacros); envMacros->Set(kv.first, value); } } + if (resolvedMacros && !useResolvedMacros) + return; + Process::Ptr process = new Process(Process::PrepareCommand(command), envMacros); process->SetTimeout(commandObj->GetTimeout()); process->Run(boost::bind(callback, command, _1)); diff --git a/lib/icinga/pluginutility.hpp b/lib/icinga/pluginutility.hpp index 309aaa26f..2039f1237 100644 --- a/lib/icinga/pluginutility.hpp +++ b/lib/icinga/pluginutility.hpp @@ -41,6 +41,7 @@ class I2_ICINGA_API PluginUtility public: static void 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& callback = boost::function()); static ServiceState ExitStatusToState(int exitStatus); diff --git a/lib/methods/clrchecktask.cpp b/lib/methods/clrchecktask.cpp index 1c9eeaa5e..af0fd3c98 100644 --- a/lib/methods/clrchecktask.cpp +++ b/lib/methods/clrchecktask.cpp @@ -86,7 +86,7 @@ static variant_t InvokeClrMethod(const variant_t& vtObject, const String& method { CLSID clsid; HRESULT hr = CLSIDFromProgID(L"System.Collections.Hashtable", &clsid); - + mscorlib::IDictionaryPtr pHashtable; CoCreateInstance(clsid, NULL, CLSCTX_ALL, __uuidof(mscorlib::IDictionary), (void **)&pHashtable); @@ -95,7 +95,7 @@ static variant_t InvokeClrMethod(const variant_t& vtObject, const String& method String value = kv.second; pHashtable->Add(kv.first.CStr(), value.CStr()); } - + mscorlib::_ObjectPtr pObject; vtObject.pdispVal->QueryInterface(__uuidof(mscorlib::_Object), (void**)&pObject); mscorlib::_TypePtr pType = pObject->GetType(); @@ -145,7 +145,8 @@ static void FillCheckResult(const CheckResult::Ptr& cr, variant_t vtResult) cr->SetPerformanceData(PluginUtility::SplitPerfdata(static_cast(sPerformanceData))); } -void ClrCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) +void ClrCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); Value raw_command = commandObj->GetCommandLine(); diff --git a/lib/methods/clrchecktask.hpp b/lib/methods/clrchecktask.hpp index 5448030c6..f43f2f005 100644 --- a/lib/methods/clrchecktask.hpp +++ b/lib/methods/clrchecktask.hpp @@ -35,13 +35,11 @@ namespace icinga class I2_METHODS_API ClrCheckTask { public: - static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr); + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ClrCheckTask(void); - - static void ProcessFinishedHandler(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const ProcessResult& pr); - }; } diff --git a/lib/methods/clusterchecktask.cpp b/lib/methods/clusterchecktask.cpp index efbe4ad08..f7e665fb9 100644 --- a/lib/methods/clusterchecktask.cpp +++ b/lib/methods/clusterchecktask.cpp @@ -36,7 +36,8 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(ClusterCheck, &ClusterCheckTask::ScriptFunc); -void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) +void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { ApiListener::Ptr listener = ApiListener::GetInstance(); diff --git a/lib/methods/clusterchecktask.hpp b/lib/methods/clusterchecktask.hpp index e6902bfbf..d8f0a6203 100644 --- a/lib/methods/clusterchecktask.hpp +++ b/lib/methods/clusterchecktask.hpp @@ -33,7 +33,8 @@ namespace icinga class ClusterCheckTask { public: - static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr); + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ClusterCheckTask(void); diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp index b7442ac67..96ee98727 100644 --- a/lib/methods/clusterzonechecktask.cpp +++ b/lib/methods/clusterzonechecktask.cpp @@ -30,7 +30,8 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(ClusterZoneCheck, &ClusterZoneCheckTask::ScriptFunc); -void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) +void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { ApiListener::Ptr listener = ApiListener::GetInstance(); @@ -92,4 +93,3 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che checkable->ProcessCheckResult(cr); } - diff --git a/lib/methods/clusterzonechecktask.hpp b/lib/methods/clusterzonechecktask.hpp index dd96717b0..513bfdf18 100644 --- a/lib/methods/clusterzonechecktask.hpp +++ b/lib/methods/clusterzonechecktask.hpp @@ -33,7 +33,8 @@ namespace icinga class ClusterZoneCheckTask { public: - static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr); + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ClusterZoneCheckTask(void); diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp index 3cf69fb0d..400d05f1e 100644 --- a/lib/methods/icingachecktask.cpp +++ b/lib/methods/icingachecktask.cpp @@ -32,7 +32,8 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(IcingaCheck, &IcingaCheckTask::ScriptFunc); -void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr) +void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { double interval = Utility::GetTime() - Application::GetStartTime(); @@ -99,4 +100,3 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResul service->ProcessCheckResult(cr); } - diff --git a/lib/methods/icingachecktask.hpp b/lib/methods/icingachecktask.hpp index b3c1d2bcf..53e76d501 100644 --- a/lib/methods/icingachecktask.hpp +++ b/lib/methods/icingachecktask.hpp @@ -34,7 +34,8 @@ namespace icinga class I2_METHODS_API IcingaCheckTask { public: - static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr); + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: IcingaCheckTask(void); diff --git a/lib/methods/nullchecktask.cpp b/lib/methods/nullchecktask.cpp index 2c52a9457..efb4795d3 100644 --- a/lib/methods/nullchecktask.cpp +++ b/lib/methods/nullchecktask.cpp @@ -31,7 +31,8 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(NullCheck, &NullCheckTask::ScriptFunc); -void NullCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr) +void NullCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { String output = "Hello from "; output += Utility::GetFQDN(); @@ -45,4 +46,3 @@ void NullCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult: service->ProcessCheckResult(cr); } - diff --git a/lib/methods/nullchecktask.hpp b/lib/methods/nullchecktask.hpp index 6587e71e2..4ce7b7635 100644 --- a/lib/methods/nullchecktask.hpp +++ b/lib/methods/nullchecktask.hpp @@ -35,7 +35,8 @@ namespace icinga class I2_METHODS_API NullCheckTask { public: - static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr); + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: NullCheckTask(void); diff --git a/lib/methods/nulleventtask.cpp b/lib/methods/nulleventtask.cpp index 88c0670db..4332a67d1 100644 --- a/lib/methods/nulleventtask.cpp +++ b/lib/methods/nulleventtask.cpp @@ -25,5 +25,5 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(NullEvent, &NullEventTask::ScriptFunc); -void NullEventTask::ScriptFunc(const Checkable::Ptr&) +void NullEventTask::ScriptFunc(const Checkable::Ptr&, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { } diff --git a/lib/methods/nulleventtask.hpp b/lib/methods/nulleventtask.hpp index cc9320104..3025661fe 100644 --- a/lib/methods/nulleventtask.hpp +++ b/lib/methods/nulleventtask.hpp @@ -35,7 +35,8 @@ namespace icinga class I2_METHODS_API NullEventTask { public: - static void ScriptFunc(const Checkable::Ptr& service); + static void ScriptFunc(const Checkable::Ptr& service, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: NullEventTask(void); diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp index dd7d6f526..b45dcf72c 100644 --- a/lib/methods/pluginchecktask.cpp +++ b/lib/methods/pluginchecktask.cpp @@ -36,7 +36,8 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(PluginCheck, &PluginCheckTask::ScriptFunc); -void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) +void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); @@ -51,7 +52,9 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); - PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), resolvers, boost::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2)); + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), + resolvers, resolvedMacros, useResolvedMacros, + boost::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2)); } void PluginCheckTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) diff --git a/lib/methods/pluginchecktask.hpp b/lib/methods/pluginchecktask.hpp index 526c49251..619467bdd 100644 --- a/lib/methods/pluginchecktask.hpp +++ b/lib/methods/pluginchecktask.hpp @@ -35,7 +35,8 @@ namespace icinga class I2_METHODS_API PluginCheckTask { public: - static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr); + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: PluginCheckTask(void); diff --git a/lib/methods/plugineventtask.cpp b/lib/methods/plugineventtask.cpp index 5686edd93..e976b0018 100644 --- a/lib/methods/plugineventtask.cpp +++ b/lib/methods/plugineventtask.cpp @@ -34,7 +34,8 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(PluginEvent, &PluginEventTask::ScriptFunc); -void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable) +void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { EventCommand::Ptr commandObj = checkable->GetEventCommand(); @@ -49,7 +50,9 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable) resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); - PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), resolvers, boost::bind(&PluginEventTask::ProcessFinishedHandler, checkable, _1, _2)); + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), + resolvers, resolvedMacros, useResolvedMacros, + boost::bind(&PluginEventTask::ProcessFinishedHandler, checkable, _1, _2)); } void PluginEventTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr) diff --git a/lib/methods/plugineventtask.hpp b/lib/methods/plugineventtask.hpp index 755fc9d1c..9d536937a 100644 --- a/lib/methods/plugineventtask.hpp +++ b/lib/methods/plugineventtask.hpp @@ -35,7 +35,8 @@ namespace icinga class I2_METHODS_API PluginEventTask { public: - static void ScriptFunc(const Checkable::Ptr& service); + static void ScriptFunc(const Checkable::Ptr& service, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: PluginEventTask(void); diff --git a/lib/methods/pluginnotificationtask.cpp b/lib/methods/pluginnotificationtask.cpp index ec192436a..39fb67879 100644 --- a/lib/methods/pluginnotificationtask.cpp +++ b/lib/methods/pluginnotificationtask.cpp @@ -35,8 +35,10 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(PluginNotification, &PluginNotificationTask::ScriptFunc); -void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, const User::Ptr& user, const CheckResult::Ptr& cr, int itype, - const String& author, const String& comment) +void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, + const User::Ptr& user, const CheckResult::Ptr& cr, int itype, + const String& author, const String& comment, const Dictionary::Ptr& resolvedMacros, + bool useResolvedMacros) { NotificationCommand::Ptr commandObj = notification->GetCommand(); @@ -63,7 +65,9 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, c resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); - PluginUtility::ExecuteCommand(commandObj, checkable, cr, resolvers, boost::bind(&PluginNotificationTask::ProcessFinishedHandler, checkable, _1, _2)); + PluginUtility::ExecuteCommand(commandObj, checkable, cr, resolvers, + resolvedMacros, useResolvedMacros, + boost::bind(&PluginNotificationTask::ProcessFinishedHandler, checkable, _1, _2)); } void PluginNotificationTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr) diff --git a/lib/methods/pluginnotificationtask.hpp b/lib/methods/pluginnotificationtask.hpp index f96dff84d..5547a7960 100644 --- a/lib/methods/pluginnotificationtask.hpp +++ b/lib/methods/pluginnotificationtask.hpp @@ -38,7 +38,8 @@ class I2_METHODS_API PluginNotificationTask public: static void ScriptFunc(const Notification::Ptr& notification, const User::Ptr& user, const CheckResult::Ptr& cr, int itype, - const String& author, const String& comment); + const String& author, const String& comment, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: PluginNotificationTask(void); diff --git a/lib/methods/randomchecktask.cpp b/lib/methods/randomchecktask.cpp index 47a930a1a..1b8eaca37 100644 --- a/lib/methods/randomchecktask.cpp +++ b/lib/methods/randomchecktask.cpp @@ -31,7 +31,8 @@ using namespace icinga; REGISTER_SCRIPTFUNCTION(RandomCheck, &RandomCheckTask::ScriptFunc); -void RandomCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr) +void RandomCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { String output = "Hello from "; output += Utility::GetFQDN(); @@ -45,4 +46,3 @@ void RandomCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResul service->ProcessCheckResult(cr); } - diff --git a/lib/methods/randomchecktask.hpp b/lib/methods/randomchecktask.hpp index d026bf7fe..8e14ed8dd 100644 --- a/lib/methods/randomchecktask.hpp +++ b/lib/methods/randomchecktask.hpp @@ -34,7 +34,8 @@ namespace icinga class RandomCheckTask { public: - static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr); + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: RandomCheckTask(void); diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index 5fb31b647..e8578b0d7 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -304,7 +304,7 @@ void ApiListener::NewClientHandler(const Socket::Ptr& client, ConnectionRole rol bool verify_ok = tlsStream->IsVerifyOK(); Log(LogInformation, "ApiListener") - << "New client connection for identity '" << identity << "'" << (verify_ok ? "" : " (unauthenticated"); + << "New client connection for identity '" << identity << "'" << (verify_ok ? "" : " (unauthenticated)"); Endpoint::Ptr endpoint; @@ -483,6 +483,20 @@ void ApiListener::PersistMessage(const Dictionary::Ptr& message, const DynamicOb } } +void ApiListener::SyncSendMessage(const Endpoint::Ptr& endpoint, const Dictionary::Ptr& message) +{ + ObjectLock olock(endpoint); + + if (!endpoint->GetSyncing()) { + Log(LogNotice, "ApiListener") + << "Sending message to '" << endpoint->GetName() << "'"; + + BOOST_FOREACH(const ApiClient::Ptr& client, endpoint->GetClients()) + client->SendMessage(message); + } +} + + void ApiListener::SyncRelayMessage(const MessageOrigin& origin, const DynamicObject::Ptr& secobj, const Dictionary::Ptr& message, bool log) { double ts = Utility::GetTime(); @@ -548,17 +562,7 @@ void ApiListener::SyncRelayMessage(const MessageOrigin& origin, const DynamicObj finishedZones.insert(target_zone); - { - ObjectLock olock(endpoint); - - if (!endpoint->GetSyncing()) { - Log(LogNotice, "ApiListener") - << "Sending message to '" << endpoint->GetName() << "'"; - - BOOST_FOREACH(const ApiClient::Ptr& client, endpoint->GetClients()) - client->SendMessage(message); - } - } + SyncSendMessage(endpoint, message); } BOOST_FOREACH(const Endpoint::Ptr& endpoint, skippedEndpoints) @@ -750,6 +754,7 @@ Value ApiListener::StatsFunc(Dictionary::Ptr& status, Array::Ptr& perfdata) stats = listener->GetStatus(); + ObjectLock olock(stats.second); BOOST_FOREACH(const Dictionary::Pair& kv, stats.second) perfdata->Add("'api_" + kv.first + "'=" + Convert::ToString(kv.second)); diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp index de1d8a7ab..5299ed4a0 100644 --- a/lib/remote/apilistener.hpp +++ b/lib/remote/apilistener.hpp @@ -56,6 +56,7 @@ public: static String GetApiDir(void); + void SyncSendMessage(const Endpoint::Ptr& endpoint, const Dictionary::Ptr& message); void RelayMessage(const MessageOrigin& origin, const DynamicObject::Ptr& secobj, const Dictionary::Ptr& message, bool log); static Value StatsFunc(Dictionary::Ptr& status, Array::Ptr& perfdata); diff --git a/lib/remote/apilistener.ti b/lib/remote/apilistener.ti index 886ee1366..3e3e29b0d 100644 --- a/lib/remote/apilistener.ti +++ b/lib/remote/apilistener.ti @@ -36,6 +36,7 @@ class ApiListener : DynamicObject }; [config] bool accept_config; + [config] bool accept_commands; [config] String ticket_salt; diff --git a/lib/remote/remote-type.conf b/lib/remote/remote-type.conf index ae1b97fa1..df2331f7d 100644 --- a/lib/remote/remote-type.conf +++ b/lib/remote/remote-type.conf @@ -33,6 +33,7 @@ %attribute %string "bind_port", %attribute %number "accept_config", + %attribute %number "accept_commands", %attribute %string "ticket_salt" }