Implement support for executing remote commands

fixes #7559
This commit is contained in:
Gunnar Beutner 2014-11-13 11:23:57 +01:00
parent 5e1099394a
commit 7321e45abc
53 changed files with 494 additions and 94 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -268,6 +268,96 @@ boost::function<Value (const std::vector<Value>& arguments)> WrapScriptFunction(
return boost::bind(&ScriptFunctionWrapperR<TR, T0, T1, T2, T3, T4, T5>, function, _1);
}
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
Value ScriptFunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5, T6), const std::vector<Value>& arguments)
{
if (arguments.size() < 7)
BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function."));
function(static_cast<T0>(arguments[0]),
static_cast<T1>(arguments[1]),
static_cast<T2>(arguments[2]),
static_cast<T3>(arguments[3]),
static_cast<T4>(arguments[4]),
static_cast<T5>(arguments[5]),
static_cast<T6>(arguments[6]));
return Empty;
}
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
boost::function<Value (const std::vector<Value>& arguments)> WrapScriptFunction(void (*function)(T0, T1, T2, T3, T4, T5, T6))
{
return boost::bind(&ScriptFunctionWrapperV<T0, T1, T2, T3, T4, T5, T6>, function, _1);
}
template<typename TR, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
Value ScriptFunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5, T6), const std::vector<Value>& arguments)
{
if (arguments.size() < 7)
BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function."));
return function(static_cast<T0>(arguments[0]),
static_cast<T1>(arguments[1]),
static_cast<T2>(arguments[2]),
static_cast<T3>(arguments[3]),
static_cast<T4>(arguments[4]),
static_cast<T5>(arguments[5]),
static_cast<T6>(arguments[6]));
}
template<typename TR, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
boost::function<Value (const std::vector<Value>& arguments)> WrapScriptFunction(TR (*function)(T0, T1, T2, T3, T4, T5, T6))
{
return boost::bind(&ScriptFunctionWrapperR<TR, T0, T1, T2, T3, T4, T5, T6>, function, _1);
}
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
Value ScriptFunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5, T6, T7), const std::vector<Value>& arguments)
{
if (arguments.size() < 8)
BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function."));
function(static_cast<T0>(arguments[0]),
static_cast<T1>(arguments[1]),
static_cast<T2>(arguments[2]),
static_cast<T3>(arguments[3]),
static_cast<T4>(arguments[4]),
static_cast<T5>(arguments[5]),
static_cast<T6>(arguments[6]),
static_cast<T7>(arguments[7]));
return Empty;
}
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
boost::function<Value (const std::vector<Value>& arguments)> WrapScriptFunction(void (*function)(T0, T1, T2, T3, T4, T5, T6, T7))
{
return boost::bind(&ScriptFunctionWrapperV<T0, T1, T2, T3, T4, T5, T6, T7>, function, _1);
}
template<typename TR, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
Value ScriptFunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5, T6, T7), const std::vector<Value>& arguments)
{
if (arguments.size() < 8)
BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function."));
return function(static_cast<T0>(arguments[0]),
static_cast<T1>(arguments[1]),
static_cast<T2>(arguments[2]),
static_cast<T3>(arguments[3]),
static_cast<T4>(arguments[4]),
static_cast<T5>(arguments[5]),
static_cast<T6>(arguments[6]),
static_cast<T7>(arguments[7]));
}
template<typename TR, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
boost::function<Value (const std::vector<Value>& arguments)> WrapScriptFunction(TR (*function)(T0, T1, T2, T3, T4, T5, T6, T7))
{
return boost::bind(&ScriptFunctionWrapperR<TR, T0, T1, T2, T3, T4, T5, T6, T7>, function, _1);
}
template<typename TR>
boost::function<TR (const std::vector<Value>& arguments)> WrapScriptFunction(TR (*function)(const std::vector<Value>&))
{

View File

@ -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)

View File

@ -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;
}

View File

@ -293,7 +293,7 @@ void DbObject::OnStatusUpdate(void)
DbObject::Ptr DbObject::GetOrCreateByObject(const DynamicObject::Ptr& object)
{
DbObject::Ptr dbobj = static_pointer_cast<DbObject>(object->GetExtension("DbObject"));
DbObject::Ptr dbobj = object->GetExtension("DbObject");
if (dbobj)
return dbobj;

View File

@ -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
)

View File

@ -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 <iostream>
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<DynamicObject>(host2)->OnStateLoaded();
static_pointer_cast<DynamicObject>(host2)->OnConfigLoaded();
std::cout << host2->GetName() << std::endl;
host2->ExecuteCheck(macros, true);
Utility::Sleep(30);
return 0;
}

View File

@ -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<DynamicObject>(host)->OnStateLoaded();
static_pointer_cast<DynamicObject>(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();

View File

@ -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);
};
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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<EventCommand> GetEventCommand(void) const;
void SetEventCommand(const intrusive_ptr<EventCommand>& command, const MessageOrigin& origin = MessageOrigin());

View File

@ -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);
};
}

View File

@ -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<Value> arguments;
arguments.push_back(checkable);
arguments.push_back(cr);
arguments.push_back(resolvedMacros);
arguments.push_back(useResolvedMacros);
InvokeMethod("execute", arguments);
}

View File

@ -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);
};
}

View File

@ -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<Value> arguments;
arguments.push_back(checkable);
arguments.push_back(resolvedMacros);
arguments.push_back(useResolvedMacros);
InvokeMethod("execute", arguments);
}

View File

@ -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);
};
}

View File

@ -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 {

View File

@ -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>()) {
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);

View File

@ -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);
};

View File

@ -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());
}

View File

@ -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);

View File

@ -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);
};
}

View File

@ -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<Value> 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);
}

View File

@ -41,7 +41,9 @@ public:
virtual Dictionary::Ptr Execute(const intrusive_ptr<Notification>& 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);
};
}

View File

@ -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<void(const Value& commandLine, const ProcessResult&)>& 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<Array>())
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));

View File

@ -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<void(const Value& commandLine, const ProcessResult&)>& callback = boost::function<void(const Value& commandLine, const ProcessResult&)>());
static ServiceState ExitStatusToState(int exitStatus);

View File

@ -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<const char *>(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();

View File

@ -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);
};
}

View File

@ -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();

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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)
{ }

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -36,6 +36,7 @@ class ApiListener : DynamicObject
};
[config] bool accept_config;
[config] bool accept_commands;
[config] String ticket_salt;

View File

@ -33,6 +33,7 @@
%attribute %string "bind_port",
%attribute %number "accept_config",
%attribute %number "accept_commands",
%attribute %string "ticket_salt"
}