diff options
Diffstat (limited to 'lib/methods')
29 files changed, 1663 insertions, 0 deletions
diff --git a/lib/methods/CMakeLists.txt b/lib/methods/CMakeLists.txt new file mode 100644 index 0000000..9fde9fd --- /dev/null +++ b/lib/methods/CMakeLists.txt @@ -0,0 +1,33 @@ +# Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ + +mkembedconfig_target(methods-itl.conf methods-itl.cpp) + +set(methods_SOURCES + i2-methods.hpp methods-itl.cpp + clusterchecktask.cpp clusterchecktask.hpp + clusterzonechecktask.cpp clusterzonechecktask.hpp + dummychecktask.cpp dummychecktask.hpp + exceptionchecktask.cpp exceptionchecktask.hpp + icingachecktask.cpp icingachecktask.hpp + nullchecktask.cpp nullchecktask.hpp + nulleventtask.cpp nulleventtask.hpp + pluginchecktask.cpp pluginchecktask.hpp + plugineventtask.cpp plugineventtask.hpp + pluginnotificationtask.cpp pluginnotificationtask.hpp + randomchecktask.cpp randomchecktask.hpp + timeperiodtask.cpp timeperiodtask.hpp + sleepchecktask.cpp sleepchecktask.hpp +) + +if(ICINGA2_UNITY_BUILD) + mkunity_target(methods methods methods_SOURCES) +endif() + +add_library(methods OBJECT ${methods_SOURCES}) + +add_dependencies(methods base config icinga) + +set_target_properties ( + methods PROPERTIES + FOLDER Lib +) diff --git a/lib/methods/clusterchecktask.cpp b/lib/methods/clusterchecktask.cpp new file mode 100644 index 0000000..6ce28ca --- /dev/null +++ b/lib/methods/clusterchecktask.cpp @@ -0,0 +1,117 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/clusterchecktask.hpp" +#include "remote/apilistener.hpp" +#include "remote/endpoint.hpp" +#include "icinga/cib.hpp" +#include "icinga/service.hpp" +#include "icinga/icingaapplication.hpp" +#include "icinga/checkcommand.hpp" +#include "base/application.hpp" +#include "base/objectlock.hpp" +#include "base/convert.hpp" +#include "base/utility.hpp" +#include "base/function.hpp" +#include "base/configtype.hpp" +#include <boost/algorithm/string/join.hpp> + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, ClusterCheck, &ClusterCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + if (resolvedMacros && !useResolvedMacros) + return; + + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); + String commandName = command->GetName(); + + 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; + pr.PID = -1; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 126; + pr.Output = output; + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetOutput(output); + cr->SetState(ServiceUnknown); + checkable->ProcessCheckResult(cr); + } + + return; + } + + std::pair<Dictionary::Ptr, Dictionary::Ptr> stats = listener->GetStatus(); + Dictionary::Ptr status = stats.first; + int numConnEndpoints = status->Get("num_conn_endpoints"); + int numNotConnEndpoints = status->Get("num_not_conn_endpoints"); + + ServiceState state; + String output = "Icinga 2 Cluster"; + + if (numNotConnEndpoints > 0) { + output += " Problem: " + Convert::ToString(numNotConnEndpoints) + " endpoints are not connected."; + output += "\n(" + FormatArray(status->Get("not_conn_endpoints")) + ")"; + + state = ServiceCritical; + } else { + output += " OK: " + Convert::ToString(numConnEndpoints) + " endpoints are connected."; + output += "\n(" + FormatArray(status->Get("conn_endpoints")) + ")"; + + state = ServiceOK; + } + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + /* use feature stats perfdata */ + std::pair<Dictionary::Ptr, Array::Ptr> feature_stats = CIB::GetFeatureStats(); + cr->SetPerformanceData(feature_stats.second); + + cr->SetCommand(commandName); + cr->SetState(state); + cr->SetOutput(output); + + checkable->ProcessCheckResult(cr); + } +} + +String ClusterCheckTask::FormatArray(const Array::Ptr& arr) +{ + bool first = true; + String str; + + if (arr) { + ObjectLock olock(arr); + for (const Value& value : arr) { + if (first) + first = false; + else + str += ", "; + + str += Convert::ToString(value); + } + } + + return str; +} diff --git a/lib/methods/clusterchecktask.hpp b/lib/methods/clusterchecktask.hpp new file mode 100644 index 0000000..16ee8a5 --- /dev/null +++ b/lib/methods/clusterchecktask.hpp @@ -0,0 +1,29 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef CLUSTERCHECKTASK_H +#define CLUSTERCHECKTASK_H + +#include "icinga/service.hpp" + +namespace icinga +{ + +/** + * Cluster check type. + * + * @ingroup methods + */ +class ClusterCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + ClusterCheckTask(); + static String FormatArray(const Array::Ptr& arr); +}; + +} + +#endif /* CLUSTERCHECKTASK_H */ diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp new file mode 100644 index 0000000..c5b6bbb --- /dev/null +++ b/lib/methods/clusterzonechecktask.cpp @@ -0,0 +1,211 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/clusterzonechecktask.hpp" +#include "icinga/checkcommand.hpp" +#include "icinga/macroprocessor.hpp" +#include "remote/apilistener.hpp" +#include "remote/endpoint.hpp" +#include "remote/zone.hpp" +#include "base/function.hpp" +#include "base/utility.hpp" +#include "base/perfdatavalue.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, ClusterZoneCheck, &ClusterZoneCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + ApiListener::Ptr listener = ApiListener::GetInstance(); + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); + String commandName = command->GetName(); + + if (!listener) { + String output = "No API listener is configured for this instance."; + ServiceState state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetCommand(commandName); + cr->SetOutput(output); + cr->SetState(state); + checkable->ProcessCheckResult(cr); + } + + return; + } + + Value raw_command = command->GetCommandLine(); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(checkable); + + MacroProcessor::ResolverList resolvers; + + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + + if (service) + resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); + resolvers.emplace_back("command", command); + resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); + + String zoneName = MacroProcessor::ResolveMacros("$cluster_zone$", resolvers, checkable->GetLastCheckResult(), + nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); + + String missingLagWarning; + String missingLagCritical; + + double lagWarning = MacroProcessor::ResolveMacros("$cluster_lag_warning$", resolvers, checkable->GetLastCheckResult(), + &missingLagWarning, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); + + double lagCritical = MacroProcessor::ResolveMacros("$cluster_lag_critical$", resolvers, checkable->GetLastCheckResult(), + &missingLagCritical, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); + + if (resolvedMacros && !useResolvedMacros) + return; + + if (zoneName.IsEmpty()) { + String output = "Macro 'cluster_zone' must be set."; + ServiceState state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetCommand(commandName); + cr->SetOutput(output); + cr->SetState(state); + checkable->ProcessCheckResult(cr); + } + + return; + } + + Zone::Ptr zone = Zone::GetByName(zoneName); + + if (!zone) { + String output = "Zone '" + zoneName + "' does not exist."; + ServiceState state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetCommand(commandName); + cr->SetOutput(output); + cr->SetState(state); + checkable->ProcessCheckResult(cr); + } + return; + } + + bool connected = false; + double zoneLag = 0; + + double lastMessageSent = 0; + double lastMessageReceived = 0; + double messagesSentPerSecond = 0; + double messagesReceivedPerSecond = 0; + double bytesSentPerSecond = 0; + double bytesReceivedPerSecond = 0; + + for (const Endpoint::Ptr& endpoint : zone->GetEndpoints()) { + if (endpoint->GetConnected()) + connected = true; + + double eplag = ApiListener::CalculateZoneLag(endpoint); + + if (eplag > 0 && eplag > zoneLag) + zoneLag = eplag; + + if (endpoint->GetLastMessageSent() > lastMessageSent) + lastMessageSent = endpoint->GetLastMessageSent(); + + if (endpoint->GetLastMessageReceived() > lastMessageReceived) + lastMessageReceived = endpoint->GetLastMessageReceived(); + + messagesSentPerSecond += endpoint->GetMessagesSentPerSecond(); + messagesReceivedPerSecond += endpoint->GetMessagesReceivedPerSecond(); + bytesSentPerSecond += endpoint->GetBytesSentPerSecond(); + bytesReceivedPerSecond += endpoint->GetBytesReceivedPerSecond(); + } + + ServiceState state; + String output; + + if (connected) { + state = ServiceOK; + output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag); + + /* Check whether the thresholds have been resolved and compare them */ + if (missingLagCritical.IsEmpty() && zoneLag > lagCritical) { + state = ServiceCritical; + output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag) + + " greater than critical threshold: " + Utility::FormatDuration(lagCritical); + } else if (missingLagWarning.IsEmpty() && zoneLag > lagWarning) { + state = ServiceWarning; + output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag) + + " greater than warning threshold: " + Utility::FormatDuration(lagWarning); + } + } else { + state = ServiceCritical; + output = "Zone '" + zoneName + "' is not connected. Log lag: " + Utility::FormatDuration(zoneLag); + } + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetCommand(commandName); + cr->SetState(state); + cr->SetOutput(output); + cr->SetPerformanceData(new Array({ + new PerfdataValue("slave_lag", zoneLag, false, "s", lagWarning, lagCritical), + new PerfdataValue("last_messages_sent", lastMessageSent), + new PerfdataValue("last_messages_received", lastMessageReceived), + new PerfdataValue("sum_messages_sent_per_second", messagesSentPerSecond), + new PerfdataValue("sum_messages_received_per_second", messagesReceivedPerSecond), + new PerfdataValue("sum_bytes_sent_per_second", bytesSentPerSecond), + new PerfdataValue("sum_bytes_received_per_second", bytesReceivedPerSecond) + })); + + checkable->ProcessCheckResult(cr); + } +} diff --git a/lib/methods/clusterzonechecktask.hpp b/lib/methods/clusterzonechecktask.hpp new file mode 100644 index 0000000..2af442c --- /dev/null +++ b/lib/methods/clusterzonechecktask.hpp @@ -0,0 +1,28 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef CLUSTERZONECHECKTASK_H +#define CLUSTERZONECHECKTASK_H + +#include "icinga/service.hpp" + +namespace icinga +{ + +/** + * Cluster zone check type. + * + * @ingroup methods + */ +class ClusterZoneCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + ClusterZoneCheckTask(); +}; + +} + +#endif /* CLUSTERZONECHECKTASK_H */ diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp new file mode 100644 index 0000000..561415c --- /dev/null +++ b/lib/methods/dummychecktask.cpp @@ -0,0 +1,77 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef _WIN32 +# include <stdlib.h> +#endif /* _WIN32 */ +#include "methods/dummychecktask.hpp" +#include "icinga/icingaapplication.hpp" +#include "icinga/pluginutility.hpp" +#include "base/utility.hpp" +#include "base/perfdatavalue.hpp" +#include "base/convert.hpp" +#include "base/function.hpp" +#include "base/logger.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, DummyCheck, &DummyCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(checkable); + + MacroProcessor::ResolverList resolvers; + + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + + if (service) + resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); + resolvers.emplace_back("command", command); + resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); + + int dummyState = MacroProcessor::ResolveMacros("$dummy_state$", resolvers, checkable->GetLastCheckResult(), + nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); + + String dummyText = MacroProcessor::ResolveMacros("$dummy_text$", resolvers, checkable->GetLastCheckResult(), + nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); + + if (resolvedMacros && !useResolvedMacros) + return; + + /* Parse output and performance data. */ + std::pair<String, String> co = PluginUtility::ParseCheckOutput(dummyText); + + double now = Utility::GetTime(); + String commandName = command->GetName(); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + ProcessResult pr; + pr.PID = -1; + pr.Output = dummyText; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = dummyState; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetOutput(co.first); + cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); + cr->SetState(PluginUtility::ExitStatusToState(dummyState)); + cr->SetExitStatus(dummyState); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + cr->SetCommand(commandName); + + checkable->ProcessCheckResult(cr); + } +} diff --git a/lib/methods/dummychecktask.hpp b/lib/methods/dummychecktask.hpp new file mode 100644 index 0000000..621bbfb --- /dev/null +++ b/lib/methods/dummychecktask.hpp @@ -0,0 +1,30 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef DUMMYCHECKTASK_H +#define DUMMYCHECKTASK_H + +#include "methods/i2-methods.hpp" +#include "icinga/service.hpp" +#include "base/dictionary.hpp" + +namespace icinga +{ + +/** + * Test class for additional check types. Implements the "dummy" check type. + * + * @ingroup methods + */ +class DummyCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + DummyCheckTask(); +}; + +} + +#endif /* DUMMYCHECKTASK_H */ diff --git a/lib/methods/exceptionchecktask.cpp b/lib/methods/exceptionchecktask.cpp new file mode 100644 index 0000000..47707f2 --- /dev/null +++ b/lib/methods/exceptionchecktask.cpp @@ -0,0 +1,41 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef _WIN32 +# include <stdlib.h> +#endif /* _WIN32 */ +#include "methods/exceptionchecktask.hpp" +#include "base/utility.hpp" +#include "base/convert.hpp" +#include "base/function.hpp" +#include "base/logger.hpp" +#include "base/exception.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, ExceptionCheck, &ExceptionCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void ExceptionCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + if (resolvedMacros && !useResolvedMacros) + return; + + ScriptError scriptError = ScriptError("Test") << boost::errinfo_api_function("Test"); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = scriptError.what(); + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 3; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } else { + BOOST_THROW_EXCEPTION(ScriptError("Test") << boost::errinfo_api_function("Test")); + } +} diff --git a/lib/methods/exceptionchecktask.hpp b/lib/methods/exceptionchecktask.hpp new file mode 100644 index 0000000..09db104 --- /dev/null +++ b/lib/methods/exceptionchecktask.hpp @@ -0,0 +1,29 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef EXCEPTIONCHECKTASK_H +#define EXCEPTIONCHECKTASK_H + +#include "icinga/service.hpp" +#include "base/dictionary.hpp" + +namespace icinga +{ + +/** + * Test class for additional check types. Implements the "exception" check type. + * + * @ingroup methods + */ +class ExceptionCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + ExceptionCheckTask(); +}; + +} + +#endif /* EXCEPTIONCHECKTASK_H */ diff --git a/lib/methods/i2-methods.hpp b/lib/methods/i2-methods.hpp new file mode 100644 index 0000000..ffd8002 --- /dev/null +++ b/lib/methods/i2-methods.hpp @@ -0,0 +1,15 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef I2METHODS_H +#define I2METHODS_H + +/** + * @defgroup methods Icinga methods + * + * The methods library implements methods for various task (e.g. checks, event + * handlers, etc.). + */ + +#include "base/i2-base.hpp" + +#endif /* I2METHODS_H */ diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp new file mode 100644 index 0000000..4079549 --- /dev/null +++ b/lib/methods/icingachecktask.cpp @@ -0,0 +1,211 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/icingachecktask.hpp" +#include "icinga/cib.hpp" +#include "icinga/service.hpp" +#include "icinga/checkcommand.hpp" +#include "icinga/macroprocessor.hpp" +#include "icinga/icingaapplication.hpp" +#include "icinga/clusterevents.hpp" +#include "icinga/checkable.hpp" +#include "remote/apilistener.hpp" +#include "base/application.hpp" +#include "base/objectlock.hpp" +#include "base/utility.hpp" +#include "base/perfdatavalue.hpp" +#include "base/function.hpp" +#include "base/configtype.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, IcingaCheck, &IcingaCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(checkable); + + MacroProcessor::ResolverList resolvers; + + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + + if (service) + resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); + resolvers.emplace_back("command", command); + resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); + + String missingIcingaMinVersion; + + String icingaMinVersion = MacroProcessor::ResolveMacros("$icinga_min_version$", resolvers, checkable->GetLastCheckResult(), + &missingIcingaMinVersion, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); + + if (resolvedMacros && !useResolvedMacros) + return; + + double interval = Utility::GetTime() - Application::GetStartTime(); + + if (interval > 60) + interval = 60; + + /* use feature stats perfdata */ + std::pair<Dictionary::Ptr, Array::Ptr> feature_stats = CIB::GetFeatureStats(); + + Array::Ptr perfdata = feature_stats.second; + + perfdata->Add(new PerfdataValue("active_host_checks", CIB::GetActiveHostChecksStatistics(interval) / interval)); + perfdata->Add(new PerfdataValue("passive_host_checks", CIB::GetPassiveHostChecksStatistics(interval) / interval)); + perfdata->Add(new PerfdataValue("active_host_checks_1min", CIB::GetActiveHostChecksStatistics(60))); + perfdata->Add(new PerfdataValue("passive_host_checks_1min", CIB::GetPassiveHostChecksStatistics(60))); + perfdata->Add(new PerfdataValue("active_host_checks_5min", CIB::GetActiveHostChecksStatistics(60 * 5))); + perfdata->Add(new PerfdataValue("passive_host_checks_5min", CIB::GetPassiveHostChecksStatistics(60 * 5))); + perfdata->Add(new PerfdataValue("active_host_checks_15min", CIB::GetActiveHostChecksStatistics(60 * 15))); + perfdata->Add(new PerfdataValue("passive_host_checks_15min", CIB::GetPassiveHostChecksStatistics(60 * 15))); + + perfdata->Add(new PerfdataValue("active_service_checks", CIB::GetActiveServiceChecksStatistics(interval) / interval)); + perfdata->Add(new PerfdataValue("passive_service_checks", CIB::GetPassiveServiceChecksStatistics(interval) / interval)); + perfdata->Add(new PerfdataValue("active_service_checks_1min", CIB::GetActiveServiceChecksStatistics(60))); + perfdata->Add(new PerfdataValue("passive_service_checks_1min", CIB::GetPassiveServiceChecksStatistics(60))); + perfdata->Add(new PerfdataValue("active_service_checks_5min", CIB::GetActiveServiceChecksStatistics(60 * 5))); + perfdata->Add(new PerfdataValue("passive_service_checks_5min", CIB::GetPassiveServiceChecksStatistics(60 * 5))); + perfdata->Add(new PerfdataValue("active_service_checks_15min", CIB::GetActiveServiceChecksStatistics(60 * 15))); + perfdata->Add(new PerfdataValue("passive_service_checks_15min", CIB::GetPassiveServiceChecksStatistics(60 * 15))); + + perfdata->Add(new PerfdataValue("current_pending_callbacks", Application::GetTP().GetPending())); + perfdata->Add(new PerfdataValue("current_concurrent_checks", Checkable::CurrentConcurrentChecks.load())); + perfdata->Add(new PerfdataValue("remote_check_queue", ClusterEvents::GetCheckRequestQueueSize())); + + CheckableCheckStatistics scs = CIB::CalculateServiceCheckStats(); + + perfdata->Add(new PerfdataValue("min_latency", scs.min_latency)); + perfdata->Add(new PerfdataValue("max_latency", scs.max_latency)); + perfdata->Add(new PerfdataValue("avg_latency", scs.avg_latency)); + perfdata->Add(new PerfdataValue("min_execution_time", scs.min_execution_time)); + perfdata->Add(new PerfdataValue("max_execution_time", scs.max_execution_time)); + perfdata->Add(new PerfdataValue("avg_execution_time", scs.avg_execution_time)); + + ServiceStatistics ss = CIB::CalculateServiceStats(); + + perfdata->Add(new PerfdataValue("num_services_ok", ss.services_ok)); + perfdata->Add(new PerfdataValue("num_services_warning", ss.services_warning)); + perfdata->Add(new PerfdataValue("num_services_critical", ss.services_critical)); + perfdata->Add(new PerfdataValue("num_services_unknown", ss.services_unknown)); + perfdata->Add(new PerfdataValue("num_services_pending", ss.services_pending)); + perfdata->Add(new PerfdataValue("num_services_unreachable", ss.services_unreachable)); + perfdata->Add(new PerfdataValue("num_services_flapping", ss.services_flapping)); + perfdata->Add(new PerfdataValue("num_services_in_downtime", ss.services_in_downtime)); + perfdata->Add(new PerfdataValue("num_services_acknowledged", ss.services_acknowledged)); + perfdata->Add(new PerfdataValue("num_services_handled", ss.services_handled)); + perfdata->Add(new PerfdataValue("num_services_problem", ss.services_problem)); + + double uptime = Application::GetUptime(); + perfdata->Add(new PerfdataValue("uptime", uptime)); + + HostStatistics hs = CIB::CalculateHostStats(); + + perfdata->Add(new PerfdataValue("num_hosts_up", hs.hosts_up)); + perfdata->Add(new PerfdataValue("num_hosts_down", hs.hosts_down)); + perfdata->Add(new PerfdataValue("num_hosts_pending", hs.hosts_pending)); + perfdata->Add(new PerfdataValue("num_hosts_unreachable", hs.hosts_unreachable)); + perfdata->Add(new PerfdataValue("num_hosts_flapping", hs.hosts_flapping)); + perfdata->Add(new PerfdataValue("num_hosts_in_downtime", hs.hosts_in_downtime)); + perfdata->Add(new PerfdataValue("num_hosts_acknowledged", hs.hosts_acknowledged)); + perfdata->Add(new PerfdataValue("num_hosts_handled", hs.hosts_handled)); + perfdata->Add(new PerfdataValue("num_hosts_problem", hs.hosts_problem)); + + std::vector<Endpoint::Ptr> endpoints = ConfigType::GetObjectsByType<Endpoint>(); + + double lastMessageSent = 0; + double lastMessageReceived = 0; + double messagesSentPerSecond = 0; + double messagesReceivedPerSecond = 0; + double bytesSentPerSecond = 0; + double bytesReceivedPerSecond = 0; + + for (const Endpoint::Ptr& endpoint : endpoints) + { + if (endpoint->GetLastMessageSent() > lastMessageSent) + lastMessageSent = endpoint->GetLastMessageSent(); + + if (endpoint->GetLastMessageReceived() > lastMessageReceived) + lastMessageReceived = endpoint->GetLastMessageReceived(); + + messagesSentPerSecond += endpoint->GetMessagesSentPerSecond(); + messagesReceivedPerSecond += endpoint->GetMessagesReceivedPerSecond(); + bytesSentPerSecond += endpoint->GetBytesSentPerSecond(); + bytesReceivedPerSecond += endpoint->GetBytesReceivedPerSecond(); + } + + perfdata->Add(new PerfdataValue("last_messages_sent", lastMessageSent)); + perfdata->Add(new PerfdataValue("last_messages_received", lastMessageReceived)); + perfdata->Add(new PerfdataValue("sum_messages_sent_per_second", messagesSentPerSecond)); + perfdata->Add(new PerfdataValue("sum_messages_received_per_second", messagesReceivedPerSecond)); + perfdata->Add(new PerfdataValue("sum_bytes_sent_per_second", bytesSentPerSecond)); + perfdata->Add(new PerfdataValue("sum_bytes_received_per_second", bytesReceivedPerSecond)); + + cr->SetPerformanceData(perfdata); + ServiceState state = ServiceOK; + + String appVersion = Application::GetAppVersion(); + + String output = "Icinga 2 has been running for " + Utility::FormatDuration(uptime) + + ". Version: " + appVersion; + + /* Indicate a warning if the last reload failed. */ + double lastReloadFailed = Application::GetLastReloadFailed(); + + if (lastReloadFailed > 0) { + output += "; Last reload attempt failed at " + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", lastReloadFailed); + state =ServiceWarning; + } + + /* Indicate a warning when the last synced config caused a stage validation error. */ + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (listener) { + Dictionary::Ptr validationResult = listener->GetLastFailedZonesStageValidation(); + + if (validationResult) { + output += "; Last zone sync stage validation failed at " + + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", validationResult->Get("ts")); + + state = ServiceWarning; + } + } + + String parsedAppVersion = Utility::ParseVersion(appVersion); + + /* Return an error if the version is less than specified (optional). */ + if (missingIcingaMinVersion.IsEmpty() && !icingaMinVersion.IsEmpty() && Utility::CompareVersion(icingaMinVersion, parsedAppVersion) < 0) { + output += "; Minimum version " + icingaMinVersion + " is not installed."; + state = ServiceCritical; + } + + String commandName = command->GetName(); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetState(state); + cr->SetOutput(output); + cr->SetCommand(commandName); + + checkable->ProcessCheckResult(cr); + } +} diff --git a/lib/methods/icingachecktask.hpp b/lib/methods/icingachecktask.hpp new file mode 100644 index 0000000..93def62 --- /dev/null +++ b/lib/methods/icingachecktask.hpp @@ -0,0 +1,29 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef ICINGACHECKTASK_H +#define ICINGACHECKTASK_H + +#include "methods/i2-methods.hpp" +#include "icinga/service.hpp" + +namespace icinga +{ + +/** + * Icinga check type. + * + * @ingroup methods + */ +class IcingaCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + IcingaCheckTask(); +}; + +} + +#endif /* ICINGACHECKTASK_H */ diff --git a/lib/methods/methods-itl.conf b/lib/methods/methods-itl.conf new file mode 100644 index 0000000..f9126f7 --- /dev/null +++ b/lib/methods/methods-itl.conf @@ -0,0 +1,85 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +System.assert(Internal.run_with_activation_context(function() { + template CheckCommand "icinga-check-command" use (IcingaCheck = Internal.IcingaCheck) { + execute = IcingaCheck + + vars.icinga_min_version = "" + } + + template CheckCommand "cluster-check-command" use (ClusterCheck = Internal.ClusterCheck) { + execute = ClusterCheck + } + + template CheckCommand "cluster-zone-check-command" use (ClusterZoneCheck = Internal.ClusterZoneCheck) { + execute = ClusterZoneCheck + } + + template CheckCommand "plugin-check-command" use (PluginCheck = Internal.PluginCheck) default { + execute = PluginCheck + } + + template NotificationCommand "plugin-notification-command" use (PluginNotification = Internal.PluginNotification) default { + execute = PluginNotification + } + + template EventCommand "plugin-event-command" use (PluginEvent = Internal.PluginEvent) default { + execute = PluginEvent + } + + template CheckCommand "dummy-check-command" use (DummyCheck = Internal.DummyCheck) { + execute = DummyCheck + } + + template CheckCommand "random-check-command" use (RandomCheck = Internal.RandomCheck) { + execute = RandomCheck + } + + template CheckCommand "exception-check-command" use (ExceptionCheck = Internal.ExceptionCheck) { + execute = ExceptionCheck + } + + template CheckCommand "null-check-command" use (NullCheck = Internal.NullCheck) { + execute = NullCheck + } + + template EventCommand "null-event-command" use (NullEvent = Internal.NullEvent) { + execute = NullEvent + } + + template TimePeriod "empty-timeperiod" use (EmptyTimePeriod = Internal.EmptyTimePeriod) { + update = EmptyTimePeriod + } + + template TimePeriod "even-minutes-timeperiod" use (EvenMinutesTimePeriod = Internal.EvenMinutesTimePeriod) { + update = EvenMinutesTimePeriod + } + + template CheckCommand "sleep-check-command" use (SleepCheck = Internal.SleepCheck) { + execute = SleepCheck + + vars.sleep_time = 1s + } +})) + +var methods = [ + "IcingaCheck", + "ClusterCheck", + "ClusterZoneCheck", + "PluginCheck", + "ClrCheck", + "PluginNotification", + "PluginEvent", + "DummyCheck", + "RandomCheck", + "ExceptionCheck", + "NullCheck", + "NullEvent", + "EmptyTimePeriod", + "EvenMinutesTimePeriod", + "SleepCheck" +] + +for (method in methods) { + Internal.remove(method) +} diff --git a/lib/methods/nullchecktask.cpp b/lib/methods/nullchecktask.cpp new file mode 100644 index 0000000..ee66029 --- /dev/null +++ b/lib/methods/nullchecktask.cpp @@ -0,0 +1,50 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef _WIN32 +# include <stdlib.h> +#endif /* _WIN32 */ +#include "methods/nullchecktask.hpp" +#include "icinga/icingaapplication.hpp" +#include "base/utility.hpp" +#include "base/perfdatavalue.hpp" +#include "base/convert.hpp" +#include "base/function.hpp" +#include "base/logger.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, NullCheck, &NullCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void NullCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + if (resolvedMacros && !useResolvedMacros) + return; + + String output = "Hello from "; + output += IcingaApplication::GetInstance()->GetNodeName(); + ServiceState state = ServiceOK; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } else { + cr->SetOutput(output); + cr->SetPerformanceData(new Array({ + new PerfdataValue("time", Convert::ToDouble(Utility::GetTime())) + })); + cr->SetState(state); + + checkable->ProcessCheckResult(cr); + } +} diff --git a/lib/methods/nullchecktask.hpp b/lib/methods/nullchecktask.hpp new file mode 100644 index 0000000..954cf8d --- /dev/null +++ b/lib/methods/nullchecktask.hpp @@ -0,0 +1,30 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef NULLCHECKTASK_H +#define NULLCHECKTASK_H + +#include "methods/i2-methods.hpp" +#include "icinga/service.hpp" +#include "base/dictionary.hpp" + +namespace icinga +{ + +/** + * Test class for additional check types. Implements the "null" check type. + * + * @ingroup methods + */ +class NullCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + NullCheckTask(); +}; + +} + +#endif /* NULLCHECKTASK_H */ diff --git a/lib/methods/nulleventtask.cpp b/lib/methods/nulleventtask.cpp new file mode 100644 index 0000000..3c02f23 --- /dev/null +++ b/lib/methods/nulleventtask.cpp @@ -0,0 +1,26 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/nulleventtask.hpp" +#include "base/function.hpp" +#include "base/logger.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, NullEvent, &NullEventTask::ScriptFunc, "checkable:resolvedMacros:useResolvedMacros"); + +void NullEventTask::ScriptFunc(const Checkable::Ptr& checkable, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = ""; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 0; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } +} diff --git a/lib/methods/nulleventtask.hpp b/lib/methods/nulleventtask.hpp new file mode 100644 index 0000000..153470f --- /dev/null +++ b/lib/methods/nulleventtask.hpp @@ -0,0 +1,30 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef NULLEVENTTASK_H +#define NULLEVENTTASK_H + +#include "methods/i2-methods.hpp" +#include "icinga/service.hpp" +#include "base/dictionary.hpp" + +namespace icinga +{ + +/** + * Test class for additional event handler types. Implements the "null" event handler type. + * + * @ingroup methods + */ +class NullEventTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& service, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + NullEventTask(); +}; + +} + +#endif /* NULLEVENTTASK_H */ diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp new file mode 100644 index 0000000..9bfa722 --- /dev/null +++ b/lib/methods/pluginchecktask.cpp @@ -0,0 +1,91 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/pluginchecktask.hpp" +#include "icinga/pluginutility.hpp" +#include "icinga/checkcommand.hpp" +#include "icinga/macroprocessor.hpp" +#include "icinga/icingaapplication.hpp" +#include "base/configtype.hpp" +#include "base/logger.hpp" +#include "base/function.hpp" +#include "base/utility.hpp" +#include "base/process.hpp" +#include "base/convert.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, PluginCheck, &PluginCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + CheckCommand::Ptr commandObj = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(checkable); + + MacroProcessor::ResolverList resolvers; + + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + + if (service) + resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); + resolvers.emplace_back("command", commandObj); + resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); + + int timeout = commandObj->GetTimeout(); + + if (!checkable->GetCheckTimeout().IsEmpty()) + timeout = checkable->GetCheckTimeout(); + + std::function<void(const Value& commandLine, const ProcessResult&)> callback; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + callback = Checkable::ExecuteCommandProcessFinishedHandler; + } else { + callback = [checkable, cr](const Value& commandLine, const ProcessResult& pr) { + ProcessFinishedHandler(checkable, cr, commandLine, pr); + }; + } + + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), + resolvers, resolvedMacros, useResolvedMacros, timeout, callback); + + if (!resolvedMacros || useResolvedMacros) { + Checkable::CurrentConcurrentChecks.fetch_add(1); + Checkable::IncreasePendingChecks(); + } +} + +void PluginCheckTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) +{ + Checkable::CurrentConcurrentChecks.fetch_sub(1); + Checkable::DecreasePendingChecks(); + + if (pr.ExitStatus > 3) { + Process::Arguments parguments = Process::PrepareCommand(commandLine); + Log(LogWarning, "PluginCheckTask") + << "Check command for object '" << checkable->GetName() << "' (PID: " << pr.PID + << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " + << pr.ExitStatus << ", output: " << pr.Output; + } + + String output = pr.Output.Trim(); + + std::pair<String, String> co = PluginUtility::ParseCheckOutput(output); + cr->SetCommand(commandLine); + cr->SetOutput(co.first); + cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); + cr->SetState(PluginUtility::ExitStatusToState(pr.ExitStatus)); + cr->SetExitStatus(pr.ExitStatus); + cr->SetExecutionStart(pr.ExecutionStart); + cr->SetExecutionEnd(pr.ExecutionEnd); + + checkable->ProcessCheckResult(cr); +} diff --git a/lib/methods/pluginchecktask.hpp b/lib/methods/pluginchecktask.hpp new file mode 100644 index 0000000..a4fc3a3 --- /dev/null +++ b/lib/methods/pluginchecktask.hpp @@ -0,0 +1,33 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef PLUGINCHECKTASK_H +#define PLUGINCHECKTASK_H + +#include "methods/i2-methods.hpp" +#include "base/process.hpp" +#include "icinga/service.hpp" + +namespace icinga +{ + +/** + * Implements service checks based on external plugins. + * + * @ingroup methods + */ +class PluginCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + PluginCheckTask(); + + static void ProcessFinishedHandler(const Checkable::Ptr& service, + const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr); +}; + +} + +#endif /* PLUGINCHECKTASK_H */ diff --git a/lib/methods/plugineventtask.cpp b/lib/methods/plugineventtask.cpp new file mode 100644 index 0000000..8b2fc44 --- /dev/null +++ b/lib/methods/plugineventtask.cpp @@ -0,0 +1,63 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/plugineventtask.hpp" +#include "icinga/eventcommand.hpp" +#include "icinga/macroprocessor.hpp" +#include "icinga/pluginutility.hpp" +#include "icinga/icingaapplication.hpp" +#include "base/configtype.hpp" +#include "base/logger.hpp" +#include "base/function.hpp" +#include "base/utility.hpp" +#include "base/process.hpp" +#include "base/convert.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, PluginEvent, &PluginEventTask::ScriptFunc, "checkable:resolvedMacros:useResolvedMacros"); + +void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + + EventCommand::Ptr commandObj = EventCommand::ExecuteOverride ? EventCommand::ExecuteOverride : checkable->GetEventCommand(); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(checkable); + + MacroProcessor::ResolverList resolvers; + + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + + if (service) + resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); + resolvers.emplace_back("command", commandObj); + resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); + + int timeout = commandObj->GetTimeout(); + std::function<void(const Value& commandLine, const ProcessResult&)> callback; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + callback = Checkable::ExecuteCommandProcessFinishedHandler; + } else { + callback = [checkable](const Value& commandLine, const ProcessResult& pr) { ProcessFinishedHandler(checkable, commandLine, pr); }; + } + + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), + resolvers, resolvedMacros, useResolvedMacros, timeout, callback); +} + +void PluginEventTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr) +{ + if (pr.ExitStatus != 0) { + Process::Arguments parguments = Process::PrepareCommand(commandLine); + Log(LogWarning, "PluginEventTask") + << "Event command for object '" << checkable->GetName() << "' (PID: " << pr.PID + << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " + << pr.ExitStatus << ", output: " << pr.Output; + } +} diff --git a/lib/methods/plugineventtask.hpp b/lib/methods/plugineventtask.hpp new file mode 100644 index 0000000..8908a82 --- /dev/null +++ b/lib/methods/plugineventtask.hpp @@ -0,0 +1,33 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef PLUGINEVENTTASK_H +#define PLUGINEVENTTASK_H + +#include "methods/i2-methods.hpp" +#include "icinga/service.hpp" +#include "base/process.hpp" + +namespace icinga +{ + +/** + * Implements event handlers based on external plugins. + * + * @ingroup methods + */ +class PluginEventTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& service, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + PluginEventTask(); + + static void ProcessFinishedHandler(const Checkable::Ptr& checkable, + const Value& commandLine, const ProcessResult& pr); +}; + +} + +#endif /* PLUGINEVENTTASK_H */ diff --git a/lib/methods/pluginnotificationtask.cpp b/lib/methods/pluginnotificationtask.cpp new file mode 100644 index 0000000..17f34cd --- /dev/null +++ b/lib/methods/pluginnotificationtask.cpp @@ -0,0 +1,80 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/pluginnotificationtask.hpp" +#include "icinga/notification.hpp" +#include "icinga/notificationcommand.hpp" +#include "icinga/pluginutility.hpp" +#include "icinga/service.hpp" +#include "icinga/macroprocessor.hpp" +#include "icinga/icingaapplication.hpp" +#include "base/function.hpp" +#include "base/logger.hpp" +#include "base/utility.hpp" +#include "base/process.hpp" +#include "base/convert.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, PluginNotification, &PluginNotificationTask::ScriptFunc, "notification:user:cr:itype:author:comment:resolvedMacros:useResolvedMacros"); + +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) +{ + REQUIRE_NOT_NULL(notification); + REQUIRE_NOT_NULL(user); + + NotificationCommand::Ptr commandObj = NotificationCommand::ExecuteOverride ? NotificationCommand::ExecuteOverride : notification->GetCommand(); + + auto type = static_cast<NotificationType>(itype); + + Checkable::Ptr checkable = notification->GetCheckable(); + + Dictionary::Ptr notificationExtra = new Dictionary({ + { "type", Notification::NotificationTypeToStringCompat(type) }, //TODO: Change that to our types. + { "author", author }, + { "comment", comment } + }); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(checkable); + + MacroProcessor::ResolverList resolvers; + + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + + resolvers.emplace_back("user", user); + resolvers.emplace_back("notification", notificationExtra); + resolvers.emplace_back("notification", notification); + if (service) + resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); + resolvers.emplace_back("command", commandObj); + resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); + + int timeout = commandObj->GetTimeout(); + std::function<void(const Value& commandLine, const ProcessResult&)> callback; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + callback = Checkable::ExecuteCommandProcessFinishedHandler; + } else { + callback = [checkable](const Value& commandline, const ProcessResult& pr) { ProcessFinishedHandler(checkable, commandline, pr); }; + } + + PluginUtility::ExecuteCommand(commandObj, checkable, cr, resolvers, + resolvedMacros, useResolvedMacros, timeout, callback); +} + +void PluginNotificationTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr) +{ + if (pr.ExitStatus != 0) { + Process::Arguments parguments = Process::PrepareCommand(commandLine); + Log(LogWarning, "PluginNotificationTask") + << "Notification command for object '" << checkable->GetName() << "' (PID: " << pr.PID + << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " + << pr.ExitStatus << ", output: " << pr.Output; + } +} diff --git a/lib/methods/pluginnotificationtask.hpp b/lib/methods/pluginnotificationtask.hpp new file mode 100644 index 0000000..66d6539 --- /dev/null +++ b/lib/methods/pluginnotificationtask.hpp @@ -0,0 +1,36 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef PLUGINNOTIFICATIONTASK_H +#define PLUGINNOTIFICATIONTASK_H + +#include "methods/i2-methods.hpp" +#include "icinga/notification.hpp" +#include "icinga/service.hpp" +#include "base/process.hpp" + +namespace icinga +{ + +/** + * Implements sending notifications based on external plugins. + * + * @ingroup methods + */ +class 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 Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + PluginNotificationTask(); + + static void ProcessFinishedHandler(const Checkable::Ptr& checkable, + const Value& commandLine, const ProcessResult& pr); +}; + +} + +#endif /* PLUGINNOTIFICATIONTASK_H */ diff --git a/lib/methods/randomchecktask.cpp b/lib/methods/randomchecktask.cpp new file mode 100644 index 0000000..9b133ef --- /dev/null +++ b/lib/methods/randomchecktask.cpp @@ -0,0 +1,65 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef _WIN32 +# include <stdlib.h> +#endif /* _WIN32 */ +#include "methods/randomchecktask.hpp" +#include "icinga/icingaapplication.hpp" +#include "icinga/checkcommand.hpp" +#include "base/utility.hpp" +#include "base/perfdatavalue.hpp" +#include "base/function.hpp" +#include "base/logger.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, RandomCheck, &RandomCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void RandomCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + if (resolvedMacros && !useResolvedMacros) + return; + + double now = Utility::GetTime(); + double uptime = Application::GetUptime(); + + String output = "Hello from " + IcingaApplication::GetInstance()->GetNodeName() + + ". Icinga 2 has been running for " + Utility::FormatDuration(uptime) + + ". Version: " + Application::GetAppVersion(); + + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); + String commandName = command->GetName(); + ServiceState state = static_cast<ServiceState>(Utility::Random() % 4); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetOutput(output); + + double random = Utility::Random() % 1000; + cr->SetPerformanceData(new Array({ + new PerfdataValue("time", now), + new PerfdataValue("value", random), + new PerfdataValue("value_1m", random * 0.9), + new PerfdataValue("value_5m", random * 0.8), + new PerfdataValue("uptime", uptime), + })); + + cr->SetState(state); + cr->SetCommand(commandName); + + checkable->ProcessCheckResult(cr); + } +} diff --git a/lib/methods/randomchecktask.hpp b/lib/methods/randomchecktask.hpp new file mode 100644 index 0000000..00ce663 --- /dev/null +++ b/lib/methods/randomchecktask.hpp @@ -0,0 +1,29 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef RANDOMCHECKTASK_H +#define RANDOMCHECKTASK_H + +#include "icinga/service.hpp" +#include "base/dictionary.hpp" + +namespace icinga +{ + +/** + * Test class for additional check types. Implements the "null" check type. + * + * @ingroup methods + */ +class RandomCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + RandomCheckTask(); +}; + +} + +#endif /* RANDOMCHECKTASK_H */ diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp new file mode 100644 index 0000000..a018de4 --- /dev/null +++ b/lib/methods/sleepchecktask.cpp @@ -0,0 +1,69 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/sleepchecktask.hpp" +#include "icinga/icingaapplication.hpp" +#include "icinga/pluginutility.hpp" +#include "base/utility.hpp" +#include "base/convert.hpp" +#include "base/function.hpp" +#include "base/logger.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, SleepCheck, &SleepCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); + +void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +{ + REQUIRE_NOT_NULL(checkable); + REQUIRE_NOT_NULL(cr); + + CheckCommand::Ptr commandObj = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(checkable); + + MacroProcessor::ResolverList resolvers; + + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + + if (service) + resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); + resolvers.emplace_back("command", commandObj); + resolvers.emplace_back("icinga", IcingaApplication::GetInstance()); + + double sleepTime = MacroProcessor::ResolveMacros("$sleep_time$", resolvers, checkable->GetLastCheckResult(), + nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); + + if (resolvedMacros && !useResolvedMacros) + return; + + Utility::Sleep(sleepTime); + + String output = "Slept for " + Convert::ToString(sleepTime) + " seconds."; + + double now = Utility::GetTime(); + CheckCommand::Ptr command = checkable->GetCheckCommand(); + String commandName = command->GetName(); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now - sleepTime; + pr.ExecutionEnd = now; + pr.ExitStatus = 0; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } else { + cr->SetOutput(output); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + cr->SetCommand(commandName); + + checkable->ProcessCheckResult(cr); + } +}
\ No newline at end of file diff --git a/lib/methods/sleepchecktask.hpp b/lib/methods/sleepchecktask.hpp new file mode 100644 index 0000000..b104f60 --- /dev/null +++ b/lib/methods/sleepchecktask.hpp @@ -0,0 +1,30 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef SLEEPCHECKTASK_H +#define SLEEPCHECKTASK_H + +#include "methods/i2-methods.hpp" +#include "icinga/service.hpp" +#include "base/dictionary.hpp" + +namespace icinga +{ + +/** + * Test class for additional check types. Implements the "sleep" check type. + * + * @ingroup methods + */ +class SleepCheckTask +{ +public: + static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + +private: + SleepCheckTask(); +}; + +} + +#endif /* SLEEPCHECKTASK_H */
\ No newline at end of file diff --git a/lib/methods/timeperiodtask.cpp b/lib/methods/timeperiodtask.cpp new file mode 100644 index 0000000..bb3f1bb --- /dev/null +++ b/lib/methods/timeperiodtask.cpp @@ -0,0 +1,35 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/timeperiodtask.hpp" +#include "base/function.hpp" + +using namespace icinga; + +REGISTER_FUNCTION_NONCONST(Internal, EmptyTimePeriod, &TimePeriodTask::EmptyTimePeriodUpdate, "tp:begin:end"); +REGISTER_FUNCTION_NONCONST(Internal, EvenMinutesTimePeriod, &TimePeriodTask::EvenMinutesTimePeriodUpdate, "tp:begin:end"); + +Array::Ptr TimePeriodTask::EmptyTimePeriodUpdate(const TimePeriod::Ptr& tp, double, double) +{ + REQUIRE_NOT_NULL(tp); + + Array::Ptr segments = new Array(); + return segments; +} + +Array::Ptr TimePeriodTask::EvenMinutesTimePeriodUpdate(const TimePeriod::Ptr& tp, double begin, double end) +{ + REQUIRE_NOT_NULL(tp); + + ArrayData segments; + + for (long t = begin / 60 - 1; t * 60 < end; t++) { + if ((t % 2) == 0) { + segments.push_back(new Dictionary({ + { "begin", t * 60 }, + { "end", (t + 1) * 60 } + })); + } + } + + return new Array(std::move(segments)); +} diff --git a/lib/methods/timeperiodtask.hpp b/lib/methods/timeperiodtask.hpp new file mode 100644 index 0000000..0dff1c6 --- /dev/null +++ b/lib/methods/timeperiodtask.hpp @@ -0,0 +1,28 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef TIMEPERIODTASK_H +#define TIMEPERIODTASK_H + +#include "icinga/timeperiod.hpp" + +namespace icinga +{ + +/** +* Test timeperiod functions. +* +* @ingroup methods +*/ +class TimePeriodTask +{ +public: + static Array::Ptr EmptyTimePeriodUpdate(const TimePeriod::Ptr& tp, double begin, double end); + static Array::Ptr EvenMinutesTimePeriodUpdate(const TimePeriod::Ptr& tp, double begin, double end); + +private: + TimePeriodTask(); +}; + +} + +#endif /* TIMEPERIODTASK_H */ |