diff options
author | Luke Kanies <luke@madstop.com> | 2005-07-10 01:36:20 +0000 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2005-07-10 01:36:20 +0000 |
commit | c718044c000f3f074fefbe356e9a71f530dfda1b (patch) | |
tree | 2659d77c96bd7154f4c4420b80d41691c4cd4296 | |
parent | 3441b82f84ff7dbc15e9a9d3c20da84a7eae8ce5 (diff) | |
download | puppet-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.rb | 1 | ||||
-rwxr-xr-x | lib/puppet/type/exec.rb | 127 | ||||
-rwxr-xr-x | test/types/tc_exec.rb | 92 |
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 |