summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2005-07-10 01:36:20 +0000
committerLuke Kanies <luke@madstop.com>2005-07-10 01:36:20 +0000
commitc718044c000f3f074fefbe356e9a71f530dfda1b (patch)
tree2659d77c96bd7154f4c4420b80d41691c4cd4296
parent3441b82f84ff7dbc15e9a9d3c20da84a7eae8ce5 (diff)
downloadpuppet-c718044c000f3f074fefbe356e9a71f530dfda1b.tar.gz
puppet-c718044c000f3f074fefbe356e9a71f530dfda1b.tar.xz
puppet-c718044c000f3f074fefbe356e9a71f530dfda1b.zip
adding the exec stuff
git-svn-id: https://reductivelabs.com/svn/puppet/library/trunk@338 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r--lib/puppet/type.rb1
-rwxr-xr-xlib/puppet/type/exec.rb127
-rwxr-xr-xtest/types/tc_exec.rb92
3 files changed, 220 insertions, 0 deletions
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 2ec09dc81..03d042a20 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -875,6 +875,7 @@ end # Puppet::Type
end
require 'puppet/type/service'
+require 'puppet/type/exec'
require 'puppet/type/pfile'
require 'puppet/type/symlink'
require 'puppet/type/package'
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
new file mode 100755
index 000000000..e981e67ca
--- /dev/null
+++ b/lib/puppet/type/exec.rb
@@ -0,0 +1,127 @@
+#!/usr/local/bin/ruby -w
+
+# $Id$
+
+require 'puppet/type/state'
+require 'puppet/type/pfile'
+
+module Puppet
+ # okay, how do we deal with parameters that don't have operations
+ # associated with them?
+ class State
+ # this always runs
+ class Returns < Puppet::State
+ @name = :returns
+
+ # because this command always runs,
+ # we're just using retrieve to verify that the command
+ # exists and such
+ def retrieve
+ cmd = self.parent[:command]
+ if cmd =~ /^\//
+ exe = cmd.split(/ /)[0]
+ unless FileTest.exists?(exe)
+ raise TypeError.new(
+ "Could not find executable %s" % exe
+ )
+ end
+ unless FileTest.executable?(exe)
+ raise TypeError.new(
+ "%s is not executable" % exe
+ )
+ end
+ elsif path = self.parent[:path]
+ exe = cmd.split(/ /)[0]
+ tmppath = ENV["PATH"]
+ ENV["PATH"] = self.parent[:path]
+
+ path = %{which #{exe}}.chomp
+ if path == ""
+ raise TypeError.new(
+ "Could not find command '%s'" % exe
+ )
+ end
+ ENV["PATH"] = tmppath
+ else
+ raise TypeError.new(
+ "%s is somehow not qualified with no search path" %
+ self.parent[:command]
+ )
+ end
+ end
+
+ def sync
+ tmppath = ENV["PATH"]
+ ENV["PATH"] = self.parent[:path]
+
+ # capture both stdout and stderr
+ output = %x{#{self.parent[:command]} 2>&1}
+ status = $?
+
+ ENV["PATH"] = tmppath
+
+ Puppet.debug("%s: status: %s; returns: %s" %
+ [self.parent[:command],status.exitstatus, self.should]
+ )
+ if status.exitstatus != self.should
+ Puppet.err("%s returned %s" %
+ [self.parent[:command],status.exitstatus])
+
+ # and log
+ output.split(/\n/).each { |line|
+ Puppet.info("%s: %s" % [self.parent[:command],line])
+ }
+ end
+
+ return :executed_command
+ end
+ end
+ end
+
+ class Type
+ class Exec < Type
+ attr_reader :command, :user, :returns
+ # class instance variable
+
+ # this is kind of hackish, using the return value as the
+ # state, but apparently namevars can't also be states
+ # who knew?
+ @states = [
+ Puppet::State::Returns
+ ]
+
+ @parameters = [
+ :path,
+ :user,
+ :command
+ ]
+
+ @name = :exec
+ @namevar = :command
+
+ def initialize(hash)
+ # default to erroring on a non-zero return
+ unless hash.include?("returns") or hash.include?(:returns)
+ hash["returns"] = 0
+ end
+
+ super
+
+ if self[:command].nil?
+ raise TypeError.new("Somehow the command is nil")
+ end
+
+ # if we're not fully qualified, require a path
+ if self[:command] !~ /^\//
+ if self[:path].nil?
+ error = TypeError.new(
+ "'%s' is both unqualifed and specified no search path" %
+ self[:command]
+ )
+ raise error
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/test/types/tc_exec.rb b/test/types/tc_exec.rb
new file mode 100755
index 000000000..d188c4487
--- /dev/null
+++ b/test/types/tc_exec.rb
@@ -0,0 +1,92 @@
+if __FILE__ == $0
+ $:.unshift '..'
+ $:.unshift '../../lib'
+ $puppetbase = "../../../../language/trunk"
+end
+
+require 'puppet'
+require 'test/unit'
+require 'facter'
+
+# $Id$
+
+class TestExec < Test::Unit::TestCase
+ def setup
+ Puppet[:loglevel] = :debug if __FILE__ == $0
+ end
+
+ def teardown
+ Puppet::Type.allclear
+ end
+
+ def test_execution
+ command = nil
+ output = nil
+ assert_nothing_raised {
+ command = Puppet::Type::Exec.new(
+ :command => "/bin/echo"
+ )
+ }
+ assert_nothing_raised {
+ command.retrieve
+ }
+ assert_nothing_raised {
+ output = command.sync
+ }
+ assert_equal([:executed_command],output)
+ end
+
+ def test_path_or_qualified
+ command = nil
+ output = nil
+ assert_raise(TypeError) {
+ command = Puppet::Type::Exec.new(
+ :command => "echo"
+ )
+ }
+ Puppet::Type::Exec.clear
+ assert_nothing_raised {
+ command = Puppet::Type::Exec.new(
+ :command => "echo",
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin"
+ )
+ }
+ Puppet::Type::Exec.clear
+ assert_nothing_raised {
+ command = Puppet::Type::Exec.new(
+ :command => "/bin/echo"
+ )
+ }
+ Puppet::Type::Exec.clear
+ assert_nothing_raised {
+ command = Puppet::Type::Exec.new(
+ :command => "/bin/echo",
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin"
+ )
+ }
+ end
+
+ def test_nonzero_returns
+ assert_nothing_raised {
+ command = Puppet::Type::Exec.new(
+ :command => "mkdir /this/directory/does/not/exist",
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
+ :returns => 1
+ )
+ }
+ assert_nothing_raised {
+ command = Puppet::Type::Exec.new(
+ :command => "touch /etc",
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
+ :returns => 1
+ )
+ }
+ assert_nothing_raised {
+ command = Puppet::Type::Exec.new(
+ :command => "thiscommanddoesnotexist",
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
+ :returns => 127
+ )
+ }
+ end
+end