[icinga-checkins] icinga.org: icinga2/master: Implement command timeouts.

git at icinga.org git at icinga.org
Thu Jun 13 12:05:45 CEST 2013


Module: icinga2
Branch: master
Commit: e30d3c56912b91d6e9ec7cfbb64de84d0d2c4049
URL:    https://git.icinga.org/?p=icinga2.git;a=commit;h=e30d3c56912b91d6e9ec7cfbb64de84d0d2c4049

Author: Gunnar Beutner <gunnar.beutner at netways.de>
Date:   Thu Jun 13 12:05:24 2013 +0200

Implement command timeouts.

Fixes #2723

---

 lib/base/process-unix.cpp             |   36 +++++++++++++++++++++++++++-----
 lib/base/process.cpp                  |   12 ++++++++++-
 lib/base/process.h                    |    5 ++++
 lib/icinga/icinga-type.conf           |    3 +-
 lib/icinga/pluginchecktask.cpp        |    5 ++++
 lib/icinga/plugineventtask.cpp        |    5 ++++
 lib/icinga/pluginnotificationtask.cpp |    5 ++++
 7 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/lib/base/process-unix.cpp b/lib/base/process-unix.cpp
index 1b90a9e..d8b11f0 100644
--- a/lib/base/process-unix.cpp
+++ b/lib/base/process-unix.cpp
@@ -32,6 +32,7 @@
 
 #ifndef _WIN32
 #include <execvpe.h>
+#include <poll.h>
 
 using namespace icinga;
 
@@ -158,13 +159,36 @@ ProcessResult Process::Run(void)
 
 	std::ostringstream outputStream;
 
+	pollfd pfd;
+	pfd.fd = fd;
+	pfd.events = POLLIN;
+	pfd.revents = 0;
+
 	for (;;) {
-		int rc = read(fd, buffer, sizeof(buffer));
+		int rc1, timeout;
+
+		timeout = 0;
+
+		if (m_Timeout != 0) {
+			timeout = m_Timeout - (Utility::GetTime() - result.ExecutionStart);
+
+			if (timeout < 0) {
+				outputStream << "<Timeout exceeded.>";
+				kill(m_Pid, SIGKILL);
+				break;
+			}
+		}
+
+		rc1 = poll(&pfd, 1, timeout * 1000);
 
-		if (rc <= 0)
-			break;
+		if (rc1 > 0) {
+			int rc2 = read(fd, buffer, sizeof(buffer));
 
-		outputStream.write(buffer, rc);
+			if (rc2 <= 0)
+				break;
+
+			outputStream.write(buffer, rc2);
+		}
 	}
 
 	String output = outputStream.str();
@@ -183,8 +207,8 @@ ProcessResult Process::Run(void)
 		exitcode = WEXITSTATUS(status);
 	} else if (WIFSIGNALED(status)) {
 		std::ostringstream outputbuf;
-		outputbuf << "Process was terminated by signal " << WTERMSIG(status);
-		output = outputbuf.str();
+		outputbuf << "<Terminated by signal " << WTERMSIG(status) << ".>";
+		output = output + outputbuf.str();
 		exitcode = 128;
 	} else {
 		exitcode = 128;
diff --git a/lib/base/process.cpp b/lib/base/process.cpp
index 009311b..e2f9904 100644
--- a/lib/base/process.cpp
+++ b/lib/base/process.cpp
@@ -26,7 +26,7 @@
 using namespace icinga;
 
 Process::Process(const std::vector<String>& arguments, const Dictionary::Ptr& extraEnvironment)
-	: m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment)
+	: m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment), m_Timeout(600)
 { }
 
 std::vector<String> Process::SplitCommand(const Value& command)
@@ -54,3 +54,13 @@ std::vector<String> Process::SplitCommand(const Value& command)
 #endif
 	return args;
 }
+
+void Process::SetTimeout(double timeout)
+{
+	m_Timeout = timeout;
+}
+
+double Process::GetTimeout(void) const
+{
+	return m_Timeout;
+}
diff --git a/lib/base/process.h b/lib/base/process.h
index 8b0ac1c..1587752 100644
--- a/lib/base/process.h
+++ b/lib/base/process.h
@@ -61,6 +61,9 @@ public:
 
 	Process(const std::vector<String>& arguments, const Dictionary::Ptr& extraEnvironment = Dictionary::Ptr());
 
+	void SetTimeout(double timeout);
+	double GetTimeout(void) const;
+
 	ProcessResult Run(void);
 
 	static std::vector<String> SplitCommand(const Value& command);
@@ -68,6 +71,8 @@ private:
 	std::vector<String> m_Arguments;
 	Dictionary::Ptr m_ExtraEnvironment;
 
+	double m_Timeout;
+
 #ifndef _WIN32
 	pid_t m_Pid;
 
diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf
index 1e0c3fb..32d6749 100644
--- a/lib/icinga/icinga-type.conf
+++ b/lib/icinga/icinga-type.conf
@@ -316,7 +316,8 @@ type Command {
 	},
 	%attribute dictionary "macros" {
 	    %attribute string "*"
-	}
+	},
+	%attribute number "timeout"
 /*    } */
 }
 
diff --git a/lib/icinga/pluginchecktask.cpp b/lib/icinga/pluginchecktask.cpp
index f1dc932..987d39c 100644
--- a/lib/icinga/pluginchecktask.cpp
+++ b/lib/icinga/pluginchecktask.cpp
@@ -67,6 +67,11 @@ Dictionary::Ptr PluginCheckTask::ScriptFunc(const Service::Ptr& service)
 
 	Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), envMacros);
 
+	Value timeout = commandObj->Get("timeout");
+
+	if (!timeout.IsEmpty())
+		process->SetTimeout(timeout);
+
 	ProcessResult pr = process->Run();
 
 	String output = pr.Output;
diff --git a/lib/icinga/plugineventtask.cpp b/lib/icinga/plugineventtask.cpp
index 54cafcd..bb71100 100644
--- a/lib/icinga/plugineventtask.cpp
+++ b/lib/icinga/plugineventtask.cpp
@@ -65,5 +65,10 @@ void PluginEventTask::ScriptFunc(const Service::Ptr& service)
 
 	Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), envMacros);
 
+	Value timeout = commandObj->Get("timeout");
+
+	if (!timeout.IsEmpty())
+		process->SetTimeout(timeout);
+
 	process->Run();
 }
diff --git a/lib/icinga/pluginnotificationtask.cpp b/lib/icinga/pluginnotificationtask.cpp
index 7e40842..63f893b 100644
--- a/lib/icinga/pluginnotificationtask.cpp
+++ b/lib/icinga/pluginnotificationtask.cpp
@@ -78,6 +78,11 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, c
 
 	Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), envMacros);
 
+	Value timeout = commandObj->Get("timeout");
+
+	if (!timeout.IsEmpty())
+		process->SetTimeout(timeout);
+
 	ProcessResult pr = process->Run();
 
 	if (pr.ExitStatus != 0) {





More information about the icinga-checkins mailing list