diff --git a/lib/db_ido/idochecktask.cpp b/lib/db_ido/idochecktask.cpp index 22febdaf5..aaff48f7b 100644 --- a/lib/db_ido/idochecktask.cpp +++ b/lib/db_ido/idochecktask.cpp @@ -29,6 +29,7 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) resolvers.emplace_back("override", MacroResolver::OverrideMacros); diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 73a28d950..2a19605ca 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -567,6 +567,7 @@ Value ApiActions::GetSingleObjectByNameUsingPermissions(const String& type, cons qd.Permission = "objects/query/" + type; std::vector objs; + try { objs = FilterUtility::GetFilterTargets(qd, queryParams, user); } catch (const std::exception& ex) { @@ -580,15 +581,16 @@ Value ApiActions::GetSingleObjectByNameUsingPermissions(const String& type, cons return objs.at(0); }; -Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, - const Dictionary::Ptr& params) +Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { ApiListener::Ptr listener = ApiListener::GetInstance(); + if (!listener) BOOST_THROW_EXCEPTION(std::invalid_argument("No ApiListener instance configured.")); /* Get command_type */ String command_type = "EventCommand"; + if (params->Contains("command_type")) command_type = HttpUtility::GetLastParameter(params, "command_type"); @@ -597,6 +599,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, return ApiActions::CreateResult(400, "Invalid command_type '" + command_type + "'."); Checkable::Ptr checkable = dynamic_pointer_cast(object); + if (!checkable) return ApiActions::CreateResult(404, "Can't start a command execution for a non-existent object."); @@ -605,6 +608,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, return ApiActions::CreateResult(400, "Parameter ttl is required."); double ttl = HttpUtility::GetLastParameter(params, "ttl"); + if (ttl <= 0) return ApiActions::CreateResult(400, "Parameter ttl must be greater than 0."); @@ -615,22 +619,25 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, tie(host, service) = GetHostService(checkable); String endpoint = "$command_endpoint$"; + if (params->Contains("endpoint")) endpoint = HttpUtility::GetLastParameter(params, "endpoint"); MacroProcessor::ResolverList resolvers; Value macros; + if (params->Contains("macros")) { macros = HttpUtility::GetLastParameter(params, "macros"); if (macros.IsObjectType()) { resolvers.emplace_back("override", macros); - } - else + } else { return ApiActions::CreateResult(400, "Parameter macros must be a dictionary."); + } } if (service) resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); @@ -644,11 +651,13 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, /* Get endpoint */ Endpoint::Ptr endpointPtr = GetSingleObjectByNameUsingPermissions(Endpoint::GetTypeName(), resolved_endpoint, ActionsHandler::AuthenticatedApiUser); + if (!endpointPtr) return ApiActions::CreateResult(404, "Can't find a valid endpoint for '" + resolved_endpoint + "'."); /* Get command */ String command; + if (!params->Contains("command")) { if (command_type == "CheckCommand" ) { command = "$check_command$"; @@ -668,6 +677,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, ); CheckResult::Ptr cr = checkable->GetLastCheckResult(); + if (!cr) cr = new CheckResult(); @@ -684,6 +694,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, if (command_type == "CheckCommand") { CheckCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(CheckCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser); + if (!cmd) return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'."); else { @@ -695,6 +706,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, } } else if (command_type == "EventCommand") { EventCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(EventCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser); + if (!cmd) return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'."); else { @@ -706,11 +718,13 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, } } else if (command_type == "NotificationCommand") { NotificationCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(NotificationCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser); + if (!cmd) return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'."); else { /* Get user */ String user_string = ""; + if (params->Contains("user")) user_string = HttpUtility::GetLastParameter(params, "user"); @@ -721,12 +735,15 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, ); User::Ptr user = GetSingleObjectByNameUsingPermissions(User::GetTypeName(), resolved_user, ActionsHandler::AuthenticatedApiUser); + if (!user) return ApiActions::CreateResult(404, "Can't find a valid user for '" + resolved_user + "'."); + execParams->Set("user", user->GetName()); /* Get notification */ String notification_string = ""; + if (params->Contains("notification")) notification_string = HttpUtility::GetLastParameter(params, "notification"); @@ -737,8 +754,10 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, ); Notification::Ptr notification = GetSingleObjectByNameUsingPermissions(Notification::GetTypeName(), resolved_notification, ActionsHandler::AuthenticatedApiUser); + if (!notification) return ApiActions::CreateResult(404, "Can't find a valid notification for '" + resolved_notification + "'."); + execParams->Set("notification", notification->GetName()); NotificationCommand::ExecuteOverride = cmd; @@ -762,8 +781,10 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, pending_execution->Set("pending", true); pending_execution->Set("deadline", deadline); Dictionary::Ptr executions = checkable->GetExecutions(); + if (!executions) executions = new Dictionary(); + executions->Set(uuid, pending_execution); checkable->SetExecutions(executions); @@ -772,8 +793,10 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, executionsToBroadcast->Set(uuid, pending_execution); Dictionary::Ptr updateParams = new Dictionary(); updateParams->Set("host", host->GetName()); + if (service) updateParams->Set("service", service->GetShortName()); + updateParams->Set("executions", executionsToBroadcast); Dictionary::Ptr updateMessage = new Dictionary(); @@ -791,8 +814,10 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, execParams->Set("command_type", "event_command"); else if (command_type == "NotificationCommand") execParams->Set("command_type", "notification_command"); + execParams->Set("command", resolved_command); execParams->Set("host", host->GetName()); + if (service) execParams->Set("service", service->GetShortName()); @@ -810,6 +835,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, /* Execute command */ bool local = endpointPtr == Endpoint::GetLocalEndpoint(); + if (local) { ClusterEvents::ExecuteCommandAPIHandler(origin, execParams); } else { diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 943a3c2d7..468b0814e 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -78,12 +78,15 @@ void ClusterEvents::EnqueueCheck(const MessageOrigin::Ptr& origin, const Diction static void SendEventExecuteCommand(const Dictionary::Ptr& params, long exitStatus, const String& output, double start, double end, const ApiListener::Ptr& listener, const MessageOrigin::Ptr& origin, - const Endpoint::Ptr& sourceEndpoint) { + const Endpoint::Ptr& sourceEndpoint) +{ Dictionary::Ptr executedParams = new Dictionary(); executedParams->Set("execution", params->Get("source")); executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", exitStatus); executedParams->Set("output", output); executedParams->Set("start", start); @@ -104,6 +107,7 @@ static void SendEventExecuteCommand(const Dictionary::Ptr& params, long exitStat void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr sourceEndpoint; + if (origin->FromClient) { sourceEndpoint = origin->FromClient->GetEndpoint(); } else if (origin->IsLocal()){ @@ -131,11 +135,13 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons String uuid = params->Get("source"); String checkableName = params->Get("host"); + if (params->Contains("service")) checkableName += "!" + params->Get("service"); /* Check deadline */ double deadline = params->Get("deadline"); + if (Utility::GetTime() > deadline) { Log(LogNotice, "ApiListener") << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkableName @@ -233,6 +239,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons Dictionary::Ptr message = MakeCheckResultMessage(host, cr); listener->SyncSendMessage(sourceEndpoint, message); } + return; } } else if (command_type == "event_command") { @@ -244,6 +251,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons double now = Utility::GetTime(); SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); } + return; } } else if (command_type == "notification_command") { @@ -255,6 +263,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons double now = Utility::GetTime(); SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); } + return; } } diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 2602184db..e8f9bde2a 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -732,13 +732,14 @@ Value ClusterEvents::AcknowledgementClearedAPIHandler(const MessageOrigin::Ptr& Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { ApiListener::Ptr listener = ApiListener::GetInstance(); + if (!listener) return Empty; if (params->Contains("endpoint")) { Endpoint::Ptr execEndpoint = Endpoint::GetByName(params->Get("endpoint")); - if (execEndpoint != Endpoint::GetLocalEndpoint()) { + if (execEndpoint != Endpoint::GetLocalEndpoint()) { Zone::Ptr endpointZone = execEndpoint->GetZone(); Zone::Ptr localZone = Zone::GetLocalZone(); @@ -758,8 +759,10 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin, Dictionary::Ptr executedParams = new Dictionary(); executedParams->Set("execution", params->Get("source")); executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", 126); executedParams->Set("output", "Endpoint '" + childEndpoint->GetName() + "' doesn't support executing arbitrary commands."); @@ -1114,13 +1117,15 @@ Value ClusterEvents::NotificationSentToAllUsersAPIHandler(const MessageOrigin::P Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { ApiListener::Ptr listener = ApiListener::GetInstance(); + if (!listener) return Empty; Endpoint::Ptr endpoint; + if (origin->FromClient) { endpoint = origin->FromClient->GetEndpoint(); - } else if (origin->IsLocal()){ + } else if (origin->IsLocal()) { endpoint = Endpoint::GetLocalEndpoint(); } @@ -1133,6 +1138,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, } Host::Ptr host = Host::GetByName(params->Get("host")); + if (!host) return Empty; @@ -1161,9 +1167,11 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, << "' from '" << origin->FromClient->GetIdentity() << "': Execution UUID missing."; return Empty; } + String uuid = params->Get("execution"); Dictionary::Ptr executions = checkable->GetExecutions(); + if (!executions) { Log(LogNotice, "ClusterEvents") << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() @@ -1172,6 +1180,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, } Dictionary::Ptr execution = executions->Get(uuid); + if (!execution) { Log(LogNotice, "ClusterEvents") << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() @@ -1198,8 +1207,10 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, executionsToBroadcast->Set(uuid, execution); Dictionary::Ptr updateParams = new Dictionary(); updateParams->Set("host", host->GetName()); + if (params->Contains("service")) updateParams->Set("service", params->Get("service")); + updateParams->Set("executions", executionsToBroadcast); Dictionary::Ptr updateMessage = new Dictionary(); @@ -1215,6 +1226,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, Value ClusterEvents::UpdateExecutionsAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); + if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'update executions API handler' message from '" << origin->FromClient->GetIdentity() @@ -1224,6 +1236,7 @@ Value ClusterEvents::UpdateExecutionsAPIHandler(const MessageOrigin::Ptr& origin } Host::Ptr host = Host::GetByName(params->Get("host")); + if (!host) return Empty; @@ -1247,13 +1260,16 @@ Value ClusterEvents::UpdateExecutionsAPIHandler(const MessageOrigin::Ptr& origin } Dictionary::Ptr executions = checkable->GetExecutions(); + if (!executions) executions = new Dictionary(); + Dictionary::Ptr newExecutions = params->Get("executions"); newExecutions->CopyTo(executions); checkable->SetExecutions(executions); ApiListener::Ptr listener = ApiListener::GetInstance(); + if (!listener) return Empty; diff --git a/lib/methods/clusterchecktask.cpp b/lib/methods/clusterchecktask.cpp index eef3900ea..6ce28cac4 100644 --- a/lib/methods/clusterchecktask.cpp +++ b/lib/methods/clusterchecktask.cpp @@ -34,6 +34,7 @@ void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRe ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) { String output = "No API listener is configured for this instance."; + if (Checkable::ExecuteCommandProcessFinishedHandler) { double now = Utility::GetTime(); ProcessResult pr; @@ -48,6 +49,7 @@ void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRe cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); } + return; } diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp index 0d5889a40..c5b6bbbf3 100644 --- a/lib/methods/clusterzonechecktask.cpp +++ b/lib/methods/clusterzonechecktask.cpp @@ -44,6 +44,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che cr->SetState(state); checkable->ProcessCheckResult(cr); } + return; } @@ -54,6 +55,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) resolvers.emplace_back("override", MacroResolver::OverrideMacros); @@ -98,6 +100,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che cr->SetState(state); checkable->ProcessCheckResult(cr); } + return; } @@ -159,6 +162,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che ServiceState state; String output; + if (connected) { state = ServiceOK; output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag); diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp index 45c773fcb..561415c64 100644 --- a/lib/methods/dummychecktask.cpp +++ b/lib/methods/dummychecktask.cpp @@ -29,6 +29,7 @@ void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) resolvers.emplace_back("override", MacroResolver::OverrideMacros); diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp index d697b6925..40795495d 100644 --- a/lib/methods/icingachecktask.cpp +++ b/lib/methods/icingachecktask.cpp @@ -33,6 +33,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) resolvers.emplace_back("override", MacroResolver::OverrideMacros); @@ -189,6 +190,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes } String commandName = command->GetName(); + if (Checkable::ExecuteCommandProcessFinishedHandler) { double now = Utility::GetTime(); ProcessResult pr; diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp index 83d36c96d..488c2185e 100644 --- a/lib/methods/pluginchecktask.cpp +++ b/lib/methods/pluginchecktask.cpp @@ -29,6 +29,7 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) resolvers.emplace_back("override", MacroResolver::OverrideMacros); @@ -43,13 +44,14 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes if (!checkable->GetCheckTimeout().IsEmpty()) timeout = checkable->GetCheckTimeout(); - std::function callback; + if (Checkable::ExecuteCommandProcessFinishedHandler) { callback = Checkable::ExecuteCommandProcessFinishedHandler; } else { callback = std::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2); } + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), resolvers, resolvedMacros, useResolvedMacros, timeout, callback); diff --git a/lib/methods/plugineventtask.cpp b/lib/methods/plugineventtask.cpp index 9c4401303..7a96901ff 100644 --- a/lib/methods/plugineventtask.cpp +++ b/lib/methods/plugineventtask.cpp @@ -28,6 +28,7 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable, tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) resolvers.emplace_back("override", MacroResolver::OverrideMacros); @@ -38,13 +39,14 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable, resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); int timeout = commandObj->GetTimeout(); - std::function callback; + if (Checkable::ExecuteCommandProcessFinishedHandler) { callback = Checkable::ExecuteCommandProcessFinishedHandler; } else { callback = std::bind(&PluginEventTask::ProcessFinishedHandler, checkable, _1, _2); } + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), resolvers, resolvedMacros, useResolvedMacros, timeout, callback); } diff --git a/lib/methods/pluginnotificationtask.cpp b/lib/methods/pluginnotificationtask.cpp index ae89cc245..8dde4ff37 100644 --- a/lib/methods/pluginnotificationtask.cpp +++ b/lib/methods/pluginnotificationtask.cpp @@ -42,6 +42,7 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) resolvers.emplace_back("override", MacroResolver::OverrideMacros); @@ -55,13 +56,14 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); int timeout = commandObj->GetTimeout(); - std::function callback; + if (Checkable::ExecuteCommandProcessFinishedHandler) { callback = Checkable::ExecuteCommandProcessFinishedHandler; } else { callback = std::bind(&PluginNotificationTask::ProcessFinishedHandler, checkable, _1, _2); } + PluginUtility::ExecuteCommand(commandObj, checkable, cr, resolvers, resolvedMacros, useResolvedMacros, timeout, callback); } diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp index ed3a5b6ee..a018de46b 100644 --- a/lib/methods/sleepchecktask.cpp +++ b/lib/methods/sleepchecktask.cpp @@ -25,6 +25,7 @@ void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) resolvers.emplace_back("override", MacroResolver::OverrideMacros);