summaryrefslogtreecommitdiffstats
path: root/lib/methods
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:34:54 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:34:54 +0000
commit0915b3ef56dfac3113cce55a59a5765dc94976be (patch)
treea8fea11d50b4f083e1bf0f90025ece7f0824784a /lib/methods
parentInitial commit. (diff)
downloadicinga2-0915b3ef56dfac3113cce55a59a5765dc94976be.tar.xz
icinga2-0915b3ef56dfac3113cce55a59a5765dc94976be.zip
Adding upstream version 2.13.6.upstream/2.13.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/methods')
-rw-r--r--lib/methods/CMakeLists.txt33
-rw-r--r--lib/methods/clusterchecktask.cpp117
-rw-r--r--lib/methods/clusterchecktask.hpp29
-rw-r--r--lib/methods/clusterzonechecktask.cpp211
-rw-r--r--lib/methods/clusterzonechecktask.hpp28
-rw-r--r--lib/methods/dummychecktask.cpp77
-rw-r--r--lib/methods/dummychecktask.hpp30
-rw-r--r--lib/methods/exceptionchecktask.cpp41
-rw-r--r--lib/methods/exceptionchecktask.hpp29
-rw-r--r--lib/methods/i2-methods.hpp15
-rw-r--r--lib/methods/icingachecktask.cpp211
-rw-r--r--lib/methods/icingachecktask.hpp29
-rw-r--r--lib/methods/methods-itl.conf85
-rw-r--r--lib/methods/nullchecktask.cpp50
-rw-r--r--lib/methods/nullchecktask.hpp30
-rw-r--r--lib/methods/nulleventtask.cpp26
-rw-r--r--lib/methods/nulleventtask.hpp30
-rw-r--r--lib/methods/pluginchecktask.cpp91
-rw-r--r--lib/methods/pluginchecktask.hpp33
-rw-r--r--lib/methods/plugineventtask.cpp63
-rw-r--r--lib/methods/plugineventtask.hpp33
-rw-r--r--lib/methods/pluginnotificationtask.cpp80
-rw-r--r--lib/methods/pluginnotificationtask.hpp36
-rw-r--r--lib/methods/randomchecktask.cpp65
-rw-r--r--lib/methods/randomchecktask.hpp29
-rw-r--r--lib/methods/sleepchecktask.cpp69
-rw-r--r--lib/methods/sleepchecktask.hpp30
-rw-r--r--lib/methods/timeperiodtask.cpp35
-rw-r--r--lib/methods/timeperiodtask.hpp28
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 */