summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2007-01-04 23:51:41 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2007-01-04 23:51:41 +0000
commit42c13e27535c868d6b70ba806554197ce3b833dc (patch)
treea747ef1d76d7b67f31464f4d200482404662b48d
parent6e10004e67b6d6f964c65edc27e8d2b350ba0175 (diff)
downloadpuppet-42c13e27535c868d6b70ba806554197ce3b833dc.tar.gz
puppet-42c13e27535c868d6b70ba806554197ce3b833dc.tar.xz
puppet-42c13e27535c868d6b70ba806554197ce3b833dc.zip
Adding a timeout to execs. This is not really a sufficient solution, since it needs to be added throughout the system, but this is a good start. The default timeout is 5 minutes.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@2047 980ebf18-57e1-0310-9a29-db15c13687c0
-rwxr-xr-xlib/puppet/type/exec.rb45
-rwxr-xr-xtest/types/exec.rb13
2 files changed, 54 insertions, 4 deletions
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index 44903f40c..1be9c030c 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -1,6 +1,7 @@
module Puppet
newtype(:exec) do
include Puppet::Util::Execution
+ require 'timeout'
@doc = "Executes external commands. It is critical that all commands
executed using this mechanism can be run multiple times without
@@ -134,7 +135,11 @@ module Puppet
event = :executed_command
- @output, status = @parent.run(self.parent[:command])
+ begin
+ @output, status = @parent.run(self.parent[:command])
+ rescue Timeout::Error
+ self.fail "Command exceeded timeout" % value.inspect
+ end
loglevel = @parent[:loglevel]
if status.exitstatus.to_s != self.should.to_s
@@ -281,6 +286,26 @@ module Puppet
end
end
end
+
+ newparam(:timeout) do
+ desc "The maximum time the command should take. If the command takes
+ longer than the timeout, the command is considered to have failed
+ and will be stopped. Use any negative number to disable the timeout."
+
+ munge do |value|
+ value = value.shift if value.is_a?(Array)
+ if value.is_a?(String)
+ unless value =~ /^[-\d.]+$/
+ raise ArgumentError, "The timeout must be a number."
+ end
+ Float(value)
+ else
+ value
+ end
+ end
+
+ defaultto 300
+ end
newcheck(:refreshonly) do
desc "The command should only be run as a
@@ -377,7 +402,12 @@ module Puppet
# Return true if the command does not return 0.
def check(value)
- output, status = @parent.run(value, true)
+ begin
+ output, status = @parent.run(value, true)
+ rescue Timeout::Error
+ err "Check %s exceeded timeout" % value.inspect
+ return false
+ end
return status.exitstatus != 0
end
@@ -408,7 +438,12 @@ module Puppet
# Return true if the command returns 0.
def check(value)
- output, status = @parent.run(value, true)
+ begin
+ output, status = @parent.run(value, true)
+ rescue Timeout::Error
+ err "Check %s exceeded timeout" % value.inspect
+ return false
+ end
return status.exitstatus == 0
end
@@ -542,7 +577,9 @@ module Puppet
end
withenv env do
- output, status = Puppet::SUIDManager.run_and_capture([command], self[:user], self[:group])
+ Timeout::timeout(self[:timeout]) do
+ output, status = Puppet::SUIDManager.run_and_capture([command], self[:user], self[:group])
+ end
# The shell returns 127 if the command is missing.
if status.exitstatus == 127
raise ArgumentError, output
diff --git a/test/types/exec.rb b/test/types/exec.rb
index fd304e7d1..0c5ee0258 100755
--- a/test/types/exec.rb
+++ b/test/types/exec.rb
@@ -603,6 +603,19 @@ and stuff"
}
assert_equal("A B\n", output)
end
+
+ def test_timeout
+ exec = Puppet::Type.type(:exec).create(:command => "sleep 1", :path => ENV["PATH"], :timeout => "0.2")
+ time = Time.now
+
+ assert_raise(Timeout::Error) {
+ exec.run("sleep 1")
+ }
+ Puppet.info "%s seconds, vs a timeout of %s" % [Time.now.to_f - time.to_f, exec[:timeout]]
+
+
+ assert_apply(exec)
+ end
end
# $Id$