summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Martin <max@puppetlabs.com>2011-03-17 13:42:46 -0700
committerMax Martin <max@puppetlabs.com>2011-03-17 13:42:46 -0700
commit462a56060f0fffc7b8577f252000195e9384fb7a (patch)
treec3447659483c2e286df255053655b00a46af4070
parent17f673dd6fee08309970f8ff721855cf1644b45f (diff)
parentec1aa192825f17afbe4dc12be1e0f2d644d74155 (diff)
downloadpuppet-462a56060f0fffc7b8577f252000195e9384fb7a.tar.gz
puppet-462a56060f0fffc7b8577f252000195e9384fb7a.tar.xz
puppet-462a56060f0fffc7b8577f252000195e9384fb7a.zip
Merge branch 'feature/2.6.next/4884-an-exec-provider-that-executes-unfiltered-bash-code' into 2.6.next
* feature/2.6.next/4884-an-exec-provider-that-executes-unfiltered-bash-code: (#4884) Revise new exec tests, add a few more (#4884) Add an shell provider for execs (#4884) Fix Test::Unit exec tests (#4884) Break the exec type out to have a posix provider (#4884) Add consistent path validation and behavior (#4884) Add expand_path to requiring the spec_helper (#4884) Autorequire shared behaviors and method to silence warnings (#4884) Fix whitespace (#4884) Get rid of open3 require since it wasn't being used
-rw-r--r--lib/puppet/parameter.rb2
-rw-r--r--lib/puppet/parameter/path.rb42
-rw-r--r--lib/puppet/provider/exec/posix.rb112
-rw-r--r--lib/puppet/provider/exec/shell.rb17
-rwxr-xr-xlib/puppet/type/exec.rb183
-rwxr-xr-xspec/integration/transaction_spec.rb24
-rw-r--r--spec/lib/puppet_spec/verbose.rb9
-rw-r--r--spec/shared_behaviours/path_parameters.rb185
-rw-r--r--spec/spec_helper.rb6
-rw-r--r--spec/unit/parameter/path_spec.rb24
-rwxr-xr-xspec/unit/provider/exec/posix_spec.rb120
-rw-r--r--spec/unit/provider/exec/shell_spec.rb50
-rwxr-xr-xspec/unit/type/exec_spec.rb674
-rwxr-xr-xspec/unit/type_spec.rb2
-rwxr-xr-xtest/ral/type/exec.rb263
15 files changed, 1279 insertions, 434 deletions
diff --git a/lib/puppet/parameter.rb b/lib/puppet/parameter.rb
index ff7cab22b..29d60fc66 100644
--- a/lib/puppet/parameter.rb
+++ b/lib/puppet/parameter.rb
@@ -300,3 +300,5 @@ class Puppet::Parameter
name.to_s
end
end
+
+require 'puppet/parameter/path'
diff --git a/lib/puppet/parameter/path.rb b/lib/puppet/parameter/path.rb
new file mode 100644
index 000000000..44886afd0
--- /dev/null
+++ b/lib/puppet/parameter/path.rb
@@ -0,0 +1,42 @@
+require 'puppet/parameter'
+
+class Puppet::Parameter::Path < Puppet::Parameter
+ def self.accept_arrays(bool = true)
+ @accept_arrays = !!bool
+ end
+ def self.arrays?
+ @accept_arrays
+ end
+
+ def validate_path(paths)
+ if paths.is_a?(Array) and ! self.class.arrays? then
+ fail "#{name} only accepts a single path, not an array of paths"
+ end
+
+ # We *always* support Unix path separators, as Win32 does now too.
+ absolute = "[/#{::Regexp.quote(::File::SEPARATOR)}]"
+ win32 = Puppet.features.microsoft_windows?
+
+ Array(paths).each do |path|
+ next if path =~ %r{^#{absolute}}
+ next if win32 and path =~ %r{^(?:[a-zA-Z]:)?#{absolute}}
+ fail("#{name} must be a fully qualified path")
+ end
+
+ paths
+ end
+
+ # This will be overridden if someone uses the validate option, which is why
+ # it just delegates to the other, useful, method.
+ def unsafe_validate(paths)
+ validate_path(paths)
+ end
+
+ # Likewise, this might be overridden, but by default...
+ def unsafe_munge(paths)
+ if paths.is_a?(Array) and ! self.class.arrays? then
+ fail "#{name} only accepts a single path, not an array of paths"
+ end
+ paths
+ end
+end
diff --git a/lib/puppet/provider/exec/posix.rb b/lib/puppet/provider/exec/posix.rb
new file mode 100644
index 000000000..92dbd8c98
--- /dev/null
+++ b/lib/puppet/provider/exec/posix.rb
@@ -0,0 +1,112 @@
+Puppet::Type.type(:exec).provide :posix do
+ include Puppet::Util::Execution
+
+ confine :feature => :posix
+ defaultfor :feature => :posix
+
+ desc "Execute external binaries directly, on POSIX systems.
+This does not pass through a shell, or perform any interpolation, but
+only directly calls the command with the arguments given."
+
+ def run(command, check = false)
+ output = nil
+ status = nil
+ dir = nil
+
+ checkexe(command)
+
+ if dir = resource[:cwd]
+ unless File.directory?(dir)
+ if check
+ dir = nil
+ else
+ self.fail "Working directory '#{dir}' does not exist"
+ end
+ end
+ end
+
+ dir ||= Dir.pwd
+
+ debug "Executing#{check ? " check": ""} '#{command}'"
+ begin
+ # Do our chdir
+ Dir.chdir(dir) do
+ environment = {}
+
+ environment[:PATH] = resource[:path].join(":") if resource[:path]
+
+ if envlist = resource[:environment]
+ envlist = [envlist] unless envlist.is_a? Array
+ envlist.each do |setting|
+ if setting =~ /^(\w+)=((.|\n)+)$/
+ env_name = $1
+ value = $2
+ if environment.include?(env_name) || environment.include?(env_name.to_sym)
+ warning "Overriding environment setting '#{env_name}' with '#{value}'"
+ end
+ environment[env_name] = value
+ else
+ warning "Cannot understand environment setting #{setting.inspect}"
+ end
+ end
+ end
+
+ withenv environment do
+ Timeout::timeout(resource[:timeout]) do
+ output, status = Puppet::Util::SUIDManager.
+ run_and_capture([command], resource[:user], resource[:group])
+ end
+ # The shell returns 127 if the command is missing.
+ if status.exitstatus == 127
+ raise ArgumentError, output
+ end
+ end
+ end
+ rescue Errno::ENOENT => detail
+ self.fail detail.to_s
+ end
+
+ return output, status
+ end
+
+ # Verify that we have the executable
+ def checkexe(command)
+ exe = extractexe(command)
+
+ if resource[:path]
+ if Puppet.features.posix? and !File.exists?(exe)
+ withenv :PATH => resource[:path].join(File::PATH_SEPARATOR) do
+ exe = which(exe) || raise(ArgumentError,"Could not find command '#{exe}'")
+ end
+ elsif Puppet.features.microsoft_windows? and !File.exists?(exe)
+ resource[:path].each do |path|
+ [".exe", ".ps1", ".bat", ".com", ""].each do |extension|
+ file = File.join(path, exe+extension)
+ return if File.exists?(file)
+ end
+ end
+ end
+ end
+
+ raise ArgumentError, "Could not find command '#{exe}'" unless File.exists?(exe)
+ unless File.executable?(exe)
+ raise ArgumentError,
+ "'#{exe}' is not executable"
+ end
+ end
+
+ def extractexe(command)
+ # easy case: command was quoted
+ if command =~ /^"([^"]+)"/
+ $1
+ else
+ command.split(/ /)[0]
+ end
+ end
+
+ def validatecmd(command)
+ exe = extractexe(command)
+ # if we're not fully qualified, require a path
+ self.fail "'#{command}' is not qualified and no path was specified. Please qualify the command or specify a path." if File.expand_path(exe) != exe and resource[:path].nil?
+ end
+end
diff --git a/lib/puppet/provider/exec/shell.rb b/lib/puppet/provider/exec/shell.rb
new file mode 100644
index 000000000..98f309e8f
--- /dev/null
+++ b/lib/puppet/provider/exec/shell.rb
@@ -0,0 +1,17 @@
+Puppet::Type.type(:exec).provide :shell, :parent => :posix do
+ include Puppet::Util::Execution
+
+ confine :feature => :posix
+
+ desc "Execute external binaries directly, on POSIX systems.
+passing through a shell so that shell built ins are available."
+
+ def run(command, check = false)
+ command = %Q{/bin/sh -c "#{command.gsub(/"/,'\"')}"}
+ super(command, check)
+ end
+
+ def validatecmd(command)
+ true
+ end
+end
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index 5ed2b104c..4458bf081 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -23,17 +23,15 @@ module Puppet
you are doing a lot of work with `exec`, please at least notify
us at Puppet Labs what you are doing, and hopefully we can work with
you to get a native resource type for the work you are doing.
-
- **Autorequires:** If Puppet is managing an exec's cwd or the executable file used in an exec's command, the exec resource will autorequire those files. If Puppet is managing the user that an exec should run as, the exec resource will autorequire that user."
- require 'open3'
+ **Autorequires:** If Puppet is managing an exec's cwd or the executable file used in an exec's command, the exec resource will autorequire those files. If Puppet is managing the user that an exec should run as, the exec resource will autorequire that user."
# Create a new check mechanism. It's basically just a parameter that
# provides one extra 'check' method.
- def self.newcheck(name, &block)
+ def self.newcheck(name, options = {}, &block)
@checks ||= {}
- check = newparam(name, &block)
+ check = newparam(name, options, &block)
@checks[name] = check
end
@@ -65,9 +63,11 @@ module Puppet
# First verify that all of our checks pass.
def retrieve
- # Default to somethinng
-
- if @resource.check
+ # We need to return :notrun to trigger evaluation; when that isn't
+ # true, we *LIE* about what happened and return a "success" for the
+ # value, which causes us to be treated as in_sync?, which means we
+ # don't actually execute anything. I think. --daniel 2011-03-10
+ if @resource.check_all_attributes
return :notrun
else
return self.should
@@ -89,7 +89,7 @@ module Puppet
tries.times do |try|
# Only add debug messages for tries > 1 to reduce log spam.
debug("Exec try #{try+1}/#{tries}") if tries > 1
- @output, @status = @resource.run(self.resource[:command])
+ @output, @status = provider.run(self.resource[:command])
break if self.should.include?(@status.exitstatus.to_s)
if try_sleep > 0 and tries > 1
debug("Sleeping for #{try_sleep} seconds between tries")
@@ -139,7 +139,7 @@ module Puppet
newparam(:path) do
desc "The search path used for command execution.
Commands must be fully qualified if no path is specified. Paths
- can be specified as an array or as a colon-separated list."
+ can be specified as an array or as a colon separated list."
# Support both arrays and colon-separated fields.
def value=(*values)
@@ -176,21 +176,9 @@ module Puppet
# Validation is handled by the SUIDManager class.
end
- newparam(:cwd) do
+ newparam(:cwd, :parent => Puppet::Parameter::Path) do
desc "The directory from which to run the command. If
this directory does not exist, the command will fail."
-
- validate do |dir|
- unless dir =~ /^#{File::SEPARATOR}/
- self.fail("CWD must be a fully qualified path")
- end
- end
-
- munge do |dir|
- dir = dir[0] if dir.is_a?(Array)
-
- dir
- end
end
newparam(:logoutput) do
@@ -209,7 +197,7 @@ module Puppet
for refreshing."
validate do |command|
- @resource.validatecmd(command)
+ provider.validatecmd(command)
end
end
@@ -333,7 +321,7 @@ module Puppet
end
end
- newcheck(:creates) do
+ newcheck(:creates, :parent => Puppet::Parameter::Path) do
desc "A file that this command creates. If this
parameter is provided, then the command will only be run
if the specified file does not exist:
@@ -346,19 +334,7 @@ module Puppet
"
- # FIXME if they try to set this and fail, then we should probably
- # fail the entire exec, right?
- validate do |files|
- files = [files] unless files.is_a? Array
-
- files.each do |file|
- self.fail("'creates' must be set to a fully qualified path") unless file
-
- unless file =~ %r{^#{File::SEPARATOR}}
- self.fail "'creates' files must be fully qualified."
- end
- end
- end
+ accept_arrays
# If the file exists, return false (i.e., don't run the command),
# else return true
@@ -386,15 +362,15 @@ module Puppet
validate do |cmds|
cmds = [cmds] unless cmds.is_a? Array
- cmds.each do |cmd|
- @resource.validatecmd(cmd)
+ cmds.each do |command|
+ provider.validatecmd(command)
end
end
# Return true if the command does not return 0.
def check(value)
begin
- output, status = @resource.run(value, true)
+ output, status = provider.run(value, true)
rescue Timeout::Error
err "Check #{value.inspect} exceeded timeout"
return false
@@ -428,15 +404,15 @@ module Puppet
validate do |cmds|
cmds = [cmds] unless cmds.is_a? Array
- cmds.each do |cmd|
- @resource.validatecmd(cmd)
+ cmds.each do |command|
+ provider.validatecmd(command)
end
end
# Return true if the command returns 0.
def check(value)
begin
- output, status = @resource.run(value, true)
+ output, status = provider.run(value, true)
rescue Timeout::Error
err "Check #{value.inspect} exceeded timeout"
return false
@@ -450,7 +426,7 @@ module Puppet
@isomorphic = false
validate do
- validatecmd(self[:command])
+ provider.validatecmd(self[:command])
end
# FIXME exec should autorequire any exec that 'creates' our cwd
@@ -503,7 +479,7 @@ module Puppet
# Verify that we pass all of the checks. The argument determines whether
# we skip the :refreshonly check, which is necessary because we now check
# within refresh
- def check(refreshing = false)
+ def check_all_attributes(refreshing = false)
self.class.checks.each { |check|
next if refreshing and check == :refreshonly
if @parameters.include?(check)
@@ -518,32 +494,6 @@ module Puppet
true
end
- # Verify that we have the executable
- def checkexe(cmd)
- exe = extractexe(cmd)
-
- if self[:path]
- if Puppet.features.posix? and !File.exists?(exe)
- withenv :PATH => self[:path].join(File::PATH_SEPARATOR) do
- exe = which(exe) || raise(ArgumentError,"Could not find command '#{exe}'")
- end
- elsif Puppet.features.microsoft_windows? and !File.exists?(exe)
- self[:path].each do |path|
- [".exe", ".ps1", ".bat", ".com", ""].each do |extension|
- file = File.join(path, exe+extension)
- return if File.exists?(file)
- end
- end
- end
- end
-
- raise ArgumentError, "Could not find executable '#{exe}'" unless FileTest.exists?(exe)
- unless FileTest.executable?(exe)
- raise ArgumentError,
- "'#{exe}' is not executable"
- end
- end
-
def output
if self.property(:returns).nil?
return nil
@@ -554,98 +504,13 @@ module Puppet
# Run the command, or optionally run a separately-specified command.
def refresh
- if self.check(true)
+ if self.check_all_attributes(true)
if cmd = self[:refresh]
- self.run(cmd)
+ provider.run(cmd)
else
self.property(:returns).sync
end
end
end
-
- # Run a command.
- def run(command, check = false)
- output = nil
- status = nil
-
- dir = nil
-
- checkexe(command)
-
- if dir = self[:cwd]
- unless File.directory?(dir)
- if check
- dir = nil
- else
- self.fail "Working directory '#{dir}' does not exist"
- end
- end
- end
-
- dir ||= Dir.pwd
-
- if check
- debug "Executing check '#{command}'"
- else
- debug "Executing '#{command}'"
- end
- begin
- # Do our chdir
- Dir.chdir(dir) do
- environment = {}
-
- environment[:PATH] = self[:path].join(":") if self[:path]
-
- if envlist = self[:environment]
- envlist = [envlist] unless envlist.is_a? Array
- envlist.each do |setting|
- if setting =~ /^(\w+)=((.|\n)+)$/
- name = $1
- value = $2
- if environment.include? name
- warning(
- "Overriding environment setting '#{name}' with '#{value}'"
- )
- end
- environment[name] = value
- else
- warning "Cannot understand environment setting #{setting.inspect}"
- end
- end
- end
-
- withenv environment do
- Timeout::timeout(self[:timeout]) do
- output, status = Puppet::Util::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
- end
- end
- end
- rescue Errno::ENOENT => detail
- self.fail detail.to_s
- end
-
- return output, status
- end
-
- def validatecmd(cmd)
- exe = extractexe(cmd)
- # if we're not fully qualified, require a path
- self.fail "'#{cmd}' is not qualified and no path was specified. Please qualify the command or specify a path." if File.expand_path(exe) != exe and self[:path].nil?
- end
-
- def extractexe(cmd)
- # easy case: command was quoted
- if cmd =~ /^"([^"]+)"/
- $1
- else
- cmd.split(/ /)[0]
- end
- end
end
end
diff --git a/spec/integration/transaction_spec.rb b/spec/integration/transaction_spec.rb
index d5478d7a7..2c12b3d5f 100755
--- a/spec/integration/transaction_spec.rb
+++ b/spec/integration/transaction_spec.rb
@@ -107,29 +107,23 @@ describe Puppet::Transaction do
file1 = tmpfile("file1")
file2 = tmpfile("file2")
- file = Puppet::Type.type(:file).new(
-
- :path => path,
-
+ file = Puppet::Type.type(:file).new(
+ :path => path,
:ensure => "file"
)
- exec1 = Puppet::Type.type(:exec).new(
-
- :path => ENV["PATH"],
+ exec1 = Puppet::Type.type(:exec).new(
+ :path => ENV["PATH"],
:command => "touch #{file1}",
:refreshonly => true,
-
- :subscribe => Puppet::Resource.new(:file, path)
+ :subscribe => Puppet::Resource.new(:file, path)
)
- exec2 = Puppet::Type.type(:exec).new(
-
- :path => ENV["PATH"],
- :command => "touch #{file2}",
+ exec2 = Puppet::Type.type(:exec).new(
+ :path => ENV["PATH"],
+ :command => "touch #{file2}",
:refreshonly => true,
-
- :subscribe => Puppet::Resource.new(:file, path)
+ :subscribe => Puppet::Resource.new(:file, path)
)
catalog = mk_catalog(file, exec1, exec2)
diff --git a/spec/lib/puppet_spec/verbose.rb b/spec/lib/puppet_spec/verbose.rb
new file mode 100644
index 000000000..d9834f2d7
--- /dev/null
+++ b/spec/lib/puppet_spec/verbose.rb
@@ -0,0 +1,9 @@
+# Support code for running stuff with warnings disabled.
+module Kernel
+ def with_verbose_disabled
+ verbose, $VERBOSE = $VERBOSE, nil
+ result = yield
+ $VERBOSE = verbose
+ return result
+ end
+end
diff --git a/spec/shared_behaviours/path_parameters.rb b/spec/shared_behaviours/path_parameters.rb
new file mode 100644
index 000000000..b5a907900
--- /dev/null
+++ b/spec/shared_behaviours/path_parameters.rb
@@ -0,0 +1,185 @@
+# In order to use this correctly you must define a method to get an instance
+# of the type being tested, so that this code can remain generic:
+#
+# it_should_behave_like "all path parameters", :path do
+# def instance(path)
+# Puppet::Type.type(:example).new(
+# :name => 'foo', :require => 'bar', :path_param => path
+# )
+# end
+#
+# That method will be invoked for each test to create the instance that we
+# subsequently test through the system; you should ensure that the minimum of
+# possible attributes are set to keep the tests clean.
+#
+# You must also pass the symbolic name of the parameter being tested to the
+# block, and optionally can pass a hash of additional options to the block.
+#
+# The known options are:
+# :array :: boolean, does this support arrays of paths, default true.
+
+shared_examples_for "all pathname parameters with arrays" do |win32|
+ path_types = {
+ "unix absolute" => "/foo/bar",
+ "unix relative" => "foo/bar",
+ "win32 absolute" => %q{\foo\bar},
+ "win32 relative" => %q{foo\bar},
+ "drive absolute" => %q{c:\foo\bar},
+ "drive relative" => %q{c:foo\bar}
+ }
+
+ describe "when given an array of paths" do
+ (1..path_types.length).each do |n|
+ path_types.keys.combination(n) do |set|
+ data = path_types.collect { |k, v| set.member?(k) ? v : nil } .compact
+ reject = true
+ only_absolute = set.find { |k| k =~ /relative/ } .nil?
+ only_unix = set.reject { |k| k =~ /unix/ } .length == 0
+
+ if only_absolute and (only_unix or win32) then
+ reject = false
+ end
+
+ it "should #{reject ? 'reject' : 'accept'} #{set.join(", ")}" do
+ if reject then
+ expect { instance(data) }.
+ should raise_error Puppet::Error, /fully qualified/
+ else
+ instance = instance(data)
+ instance[@param].should == data
+ end
+ end
+
+ it "should #{reject ? 'reject' : 'accept'} #{set.join(", ")} doubled" do
+ if reject then
+ expect { instance(data + data) }.
+ should raise_error Puppet::Error, /fully qualified/
+ else
+ instance = instance(data + data)
+ instance[@param].should == (data + data)
+ end
+ end
+ end
+ end
+ end
+end
+
+
+shared_examples_for "all path parameters" do |param, options|
+ # Extract and process options to the block.
+ options ||= {}
+ array = options[:array].nil? ? true : options.delete(:array)
+ if options.keys.length > 0 then
+ fail "unknown options for 'all path parameters': " +
+ options.keys.sort.join(', ')
+ end
+
+ def instance(path)
+ fail "we didn't implement the 'instance(path)' method in the it_should_behave_like block"
+ end
+
+ ########################################################################
+ # The actual testing code...
+ before :all do
+ @param = param
+ end
+
+ before :each do
+ @file_separator = File::SEPARATOR
+ end
+ after :each do
+ with_verbose_disabled do
+ verbose, $VERBOSE = $VERBOSE, nil
+ File::SEPARATOR = @file_separator
+ $VERBOSE = verbose
+ end
+ end
+
+ describe "on a Unix-like platform it" do
+ before :each do
+ with_verbose_disabled do
+ File::SEPARATOR = '/'
+ end
+ Puppet.features.stubs(:microsoft_windows?).returns(false)
+ Puppet.features.stubs(:posix?).returns(true)
+ end
+
+ if array then
+ it_should_behave_like "all pathname parameters with arrays", false
+ end
+
+ it "should accept a fully qualified path" do
+ path = File.join('', 'foo')
+ instance = instance(path)
+ instance[@param].should == path
+ end
+
+ it "should give a useful error when the path is not absolute" do
+ path = 'foo'
+ expect { instance(path) }.
+ should raise_error Puppet::Error, /fully qualified/
+ end
+
+ { "Unix" => '/', "Win32" => '\\' }.each do |style, slash|
+ %w{q Q a A z Z c C}.sort.each do |drive|
+ it "should reject drive letter '#{drive}' with #{style} path separators" do
+ path = "#{drive}:#{slash}Program Files"
+ expect { instance(path) }.
+ should raise_error Puppet::Error, /fully qualified/
+ end
+ end
+ end
+ end
+
+ describe "on a Windows-like platform it" do
+ before :each do
+ with_verbose_disabled do
+ File::SEPARATOR = '\\'
+ end
+ Puppet.features.stubs(:microsoft_windows?).returns(true)
+ Puppet.features.stubs(:posix?).returns(false)
+ end
+
+ if array then
+ it_should_behave_like "all pathname parameters with arrays", true
+ end
+
+ it "should accept a fully qualified path" do
+ path = File.join('', 'foo')
+ instance = instance(path)
+ instance[@param].should == path
+ end
+
+ it "should give a useful error when the path is not absolute" do
+ path = 'foo'
+ expect { instance(path) }.
+ should raise_error Puppet::Error, /fully qualified/
+ end
+
+ it "also accepts Unix style path separators" do
+ path = '/Program Files'
+ instance = instance(path)
+ instance[@param].should == path
+ end
+
+ { "Unix" => '/', "Win32" => '\\' }.each do |style, slash|
+ %w{q Q a A z Z c C}.sort.each do |drive|
+ it "should accept drive letter '#{drive}' with #{style} path separators " do
+ path = "#{drive}:#{slash}Program Files"
+ instance = instance(path)
+ instance[@param].should == path
+ end
+ end
+ end
+
+ { "UNC paths" => %q{\\foo\bar},
+ "unparsed local paths" => %q{\\?\c:\foo},
+ "unparsed UNC paths" => %q{\\?\foo\bar}
+ }.each do |name, path|
+ it "should accept #{name} as absolute" do
+ instance = instance(path)
+ instance[@param].should == path
+ end
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index ae4edb2d9..505a8f973 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -23,10 +23,16 @@ end
module PuppetTest
end
+require 'pathname'
+require 'lib/puppet_spec/verbose'
require 'lib/puppet_spec/files'
require 'monkey_patches/alias_should_to_must'
require 'monkey_patches/publicize_methods'
+Pathname.glob("#{dir}/shared_behaviours/**/*.rb") do |behaviour|
+ require behaviour.relative_path_from(Pathname.new(dir))
+end
+
RSpec.configure do |config|
config.mock_with :mocha
diff --git a/spec/unit/parameter/path_spec.rb b/spec/unit/parameter/path_spec.rb
new file mode 100644
index 000000000..08a26de33
--- /dev/null
+++ b/spec/unit/parameter/path_spec.rb
@@ -0,0 +1,24 @@
+#!/usr/bin/env ruby
+require File.expand_path(File.join(File.dirname(__FILE__), '../../spec_helper'))
+
+require 'puppet/parameter/path'
+
+[false, true].each do |arrays|
+ describe "Puppet::Parameter::Path with arrays #{arrays}" do
+ it_should_behave_like "all path parameters", :path, :array => arrays do
+ # The new type allows us a test that is guaranteed to go direct to our
+ # validation code, without passing through any "real type" overrides or
+ # whatever on the way.
+ Puppet::newtype(:test_puppet_parameter_path) do
+ newparam(:path, :parent => Puppet::Parameter::Path, :arrays => arrays) do
+ isnamevar
+ accept_arrays arrays
+ end
+ end
+
+ def instance(path)
+ Puppet::Type.type(:test_puppet_parameter_path).new(:path => path)
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/exec/posix_spec.rb b/spec/unit/provider/exec/posix_spec.rb
new file mode 100755
index 000000000..d02099250
--- /dev/null
+++ b/spec/unit/provider/exec/posix_spec.rb
@@ -0,0 +1,120 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+provider_class = Puppet::Type.type(:exec).provider(:posix)
+
+describe provider_class do
+ before :each do
+ @resource = Puppet::Resource.new(:exec, 'foo')
+ @provider = provider_class.new(@resource)
+ end
+
+ ["posix", "microsoft_windows"].each do |feature|
+ describe "when in #{feature} environment" do
+ before :each do
+ if feature == "microsoft_windows"
+ Puppet.features.stubs(:microsoft_windows?).returns(true)
+ Puppet.features.stubs(:posix?).returns(false)
+ else
+ Puppet.features.stubs(:posix?).returns(true)
+ Puppet.features.stubs(:microsoft_windows?).returns(false)
+ end
+ end
+
+ describe "#validatecmd" do
+ it "should fail if no path is specified and the command is not fully qualified" do
+ lambda { @provider.validatecmd("foo") }.should raise_error(
+ Puppet::Error,
+ "'foo' is not qualified and no path was specified. Please qualify the command or specify a path."
+ )
+ end
+
+ it "should pass if a path is given" do
+ @provider.resource[:path] = ['/bogus/bin']
+ @provider.validatecmd("../foo")
+ end
+
+ it "should pass if command is fully qualifed" do
+ @provider.resource[:path] = ['/bogus/bin']
+ @provider.validatecmd("/bin/blah/foo")
+ end
+ end
+
+ describe "#run" do
+ it "should fail if no path is specified and command does not exist" do
+ lambda { @provider.run("foo") }.should raise_error(ArgumentError, "Could not find command 'foo'")
+ end
+
+ it "should fail if the command isn't in the path" do
+ @provider.resource[:path] = ['/bogus/bin']
+ lambda { @provider.run("foo") }.should raise_error(ArgumentError, "Could not find command 'foo'")
+ end
+
+ it "should fail if the command isn't executable" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).with("foo").returns(true)
+
+ lambda { @provider.run("foo") }.should raise_error(ArgumentError, "'foo' is not executable")
+ end
+
+ it "should not be able to execute shell builtins" do
+ @provider.resource[:path] = ['/bin']
+ lambda { @provider.run("cd ..") }.should raise_error(ArgumentError, "Could not find command 'cd'")
+ end
+
+ it "should execute the command if the command given includes arguments or subcommands" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).returns(false)
+ File.stubs(:exists?).with("foo").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+
+ Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo bar --sillyarg=true --blah']) && (arguments.is_a? Hash) }
+ @provider.run("foo bar --sillyarg=true --blah")
+ end
+
+ it "should fail if quoted command doesn't exist" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).returns(false)
+ File.stubs(:exists?).with("foo").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+
+ lambda { @provider.run('"foo bar --sillyarg=true --blah"') }.should raise_error(ArgumentError, "Could not find command 'foo bar --sillyarg=true --blah'")
+ end
+
+ it "should execute the command if it finds it in the path and is executable" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).with("foo").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+ Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) }
+
+ @provider.run("foo")
+ end
+
+ if feature == "microsoft_windows"
+ [".exe", ".ps1", ".bat", ".com", ""].each do |extension|
+ it "should check file extension #{extension} when it can't find the executable" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).returns(false)
+ File.stubs(:exists?).with("/bogus/bin/foo#{extension}").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+ Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) }
+
+ @provider.run("foo")
+ end
+ end
+ end
+
+ it "should warn if you're overriding something in environment" do
+ @provider.resource[:environment] = ['WHATEVER=/something/else', 'WHATEVER=/foo']
+ File.stubs(:exists?).returns(false)
+ File.stubs(:exists?).with("foo").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+
+ Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) }
+ @provider.run("foo")
+ @logs.map {|l| "#{l.level}: #{l.message}" }.should == ["warning: Overriding environment setting 'WHATEVER' with '/foo'"]
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/exec/shell_spec.rb b/spec/unit/provider/exec/shell_spec.rb
new file mode 100644
index 000000000..a9b1f06ba
--- /dev/null
+++ b/spec/unit/provider/exec/shell_spec.rb
@@ -0,0 +1,50 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+provider_class = Puppet::Type.type(:exec).provider(:shell)
+
+describe provider_class do
+ before :each do
+ @resource = Puppet::Resource.new(:exec, 'foo')
+ @provider = provider_class.new(@resource)
+ end
+
+ describe "#run" do
+ it "should be able to run builtin shell commands" do
+ output, status = @provider.run("if [ 1 == 1 ]; then echo 'blah'; fi")
+ status.exitstatus.should == 0
+ output.should == "blah\n"
+ end
+
+ it "should be able to run commands with single quotes in them" do
+ output, status = @provider.run("echo 'foo bar'")
+ status.exitstatus.should == 0
+ output.should == "foo bar\n"
+ end
+
+ it "should be able to run commands with double quotes in them" do
+ output, status = @provider.run('echo "foo bar"')
+ status.exitstatus.should == 0
+ output.should == "foo bar\n"
+ end
+
+ it "should be able to run multiple commands separated by a semicolon" do
+ output, status = @provider.run("echo 'foo' ; echo 'bar'")
+ status.exitstatus.should == 0
+ output.should == "foo\nbar\n"
+ end
+
+ it "should be able to read values from the environment parameter" do
+ @resource[:environment] = "FOO=bar"
+ output, status = @provider.run("echo $FOO")
+ status.exitstatus.should == 0
+ output.should == "bar\n"
+ end
+ end
+
+ describe "#validatecmd" do
+ it "should always return true because builtins don't need path or to be fully qualified" do
+ @provider.validatecmd('whateverdoesntmatter').should == true
+ end
+ end
+end
diff --git a/spec/unit/type/exec_spec.rb b/spec/unit/type/exec_spec.rb
index e04cfc065..4d691d580 100755
--- a/spec/unit/type/exec_spec.rb
+++ b/spec/unit/type/exec_spec.rb
@@ -1,31 +1,32 @@
#!/usr/bin/env ruby
-
require File.dirname(__FILE__) + '/../../spec_helper'
describe Puppet::Type.type(:exec) do
-
- def create_resource(command, output, exitstatus, returns = 0)
- @user_name = 'some_user_name'
+ def exec_tester(command, exitstatus = 0, rest = {})
+ @user_name = 'some_user_name'
@group_name = 'some_group_name'
Puppet.features.stubs(:root?).returns(true)
- @execer = Puppet::Type.type(:exec).new(:name => command, :path => @example_path, :user => @user_name, :group => @group_name, :returns => returns)
- status = stub "process"
- status.stubs(:exitstatus).returns(exitstatus)
+ output = rest.delete(:output) || ''
+ tries = rest[:tries] || 1
- Puppet::Util::SUIDManager.expects(:run_and_capture).with([command], @user_name, @group_name).returns([output, status])
- end
+ args = {
+ :name => command,
+ :path => @example_path,
+ :user => @user_name,
+ :group => @group_name,
+ :logoutput => false,
+ :loglevel => :err,
+ :returns => 0
+ }.merge(rest)
- def create_logging_resource(command, output, exitstatus, logoutput, loglevel, returns = 0)
- create_resource(command, output, exitstatus, returns)
- @execer[:logoutput] = logoutput
- @execer[:loglevel] = loglevel
- end
+ exec = Puppet::Type.type(:exec).new(args)
- def expect_output(output, loglevel)
- output.split(/\n/).each do |line|
- @execer.property(:returns).expects(loglevel).with(line)
- end
+ status = stub "process", :exitstatus => exitstatus
+ Puppet::Util::SUIDManager.expects(:run_and_capture).times(tries).
+ with([command], @user_name, @group_name).returns([output, status])
+
+ return exec
end
before do
@@ -44,119 +45,626 @@ describe Puppet::Type.type(:exec) do
end
describe "when execing" do
-
it "should use the 'run_and_capture' method to exec" do
- command = "true"
- create_resource(command, "", 0)
-
- @execer.refresh.should == :executed_command
+ exec_tester("true").refresh.should == :executed_command
end
it "should report a failure" do
- command = "false"
- create_resource(command, "", 1)
-
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ proc { exec_tester('false', 1).refresh }.
+ should raise_error(Puppet::Error, /^false returned 1 instead of/)
end
it "should not report a failure if the exit status is specified in a returns array" do
- command = "false"
- create_resource(command, "", 1, [0,1])
- proc { @execer.refresh }.should_not raise_error(Puppet::Error)
+ proc { exec_tester("false", 1, :returns => [0, 1]).refresh }.should_not raise_error
end
it "should report a failure if the exit status is not specified in a returns array" do
- command = "false"
- create_resource(command, "", 1, [0,100])
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ proc { exec_tester('false', 1, :returns => [0, 100]).refresh }.
+ should raise_error(Puppet::Error, /^false returned 1 instead of/)
end
it "should log the output on success" do
- #Puppet::Util::Log.newdestination :console
- command = "false"
output = "output1\noutput2\n"
- create_logging_resource(command, output, 0, true, :err)
- expect_output(output, :err)
- @execer.refresh
+ exec_tester('false', 0, :output => output, :logoutput => true).refresh
+ output.split("\n").each do |line|
+ log = @logs.shift
+ log.level.should == :err
+ log.message.should == line
+ end
end
it "should log the output on failure" do
- #Puppet::Util::Log.newdestination :console
- command = "false"
output = "output1\noutput2\n"
- create_logging_resource(command, output, 1, true, :err)
- expect_output(output, :err)
+ proc { exec_tester('false', 1, :output => output, :logoutput => true).refresh }.
+ should raise_error(Puppet::Error)
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ output.split("\n").each do |line|
+ log = @logs.shift
+ log.level.should == :err
+ log.message.should == line
+ end
end
-
end
describe "when logoutput=>on_failure is set" do
-
it "should log the output on failure" do
- #Puppet::Util::Log.newdestination :console
- command = "false"
output = "output1\noutput2\n"
- create_logging_resource(command, output, 1, :on_failure, :err)
- expect_output(output, :err)
+ proc { exec_tester('false', 1, :output => output, :logoutput => :on_failure).refresh }.
+ should raise_error(Puppet::Error, /^false returned 1 instead of/)
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ output.split("\n").each do |line|
+ log = @logs.shift
+ log.level.should == :err
+ log.message.should == line
+ end
end
it "should log the output on failure when returns is specified as an array" do
- #Puppet::Util::Log.newdestination :console
- command = "false"
output = "output1\noutput2\n"
- create_logging_resource(command, output, 1, :on_failure, :err, [0, 100])
- expect_output(output, :err)
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ proc {
+ exec_tester('false', 1, :output => output, :returns => [0, 100],
+ :logoutput => :on_failure).refresh
+ }.should raise_error(Puppet::Error, /^false returned 1 instead of/)
+
+ output.split("\n").each do |line|
+ log = @logs.shift
+ log.level.should == :err
+ log.message.should == line
+ end
end
it "shouldn't log the output on success" do
- #Puppet::Util::Log.newdestination :console
- command = "true"
- output = "output1\noutput2\n"
- create_logging_resource(command, output, 0, :on_failure, :err)
- @execer.property(:returns).expects(:err).never
- @execer.refresh
+ exec_tester('true', 0, :output => "a\nb\nc\n", :logoutput => :on_failure).refresh
+ @logs.should == []
end
end
it "shouldn't log the output on success when non-zero exit status is in a returns array" do
- #Puppet::Util::Log.newdestination :console
- command = "true"
- output = "output1\noutput2\n"
- create_logging_resource(command, output, 100, :on_failure, :err, [1,100])
- @execer.property(:returns).expects(:err).never
- @execer.refresh
+ exec_tester("true", 100, :output => "a\n", :logoutput => :on_failure, :returns => [1, 100]).refresh
+ @logs.should == []
end
describe " when multiple tries are set," do
-
it "should repeat the command attempt 'tries' times on failure and produce an error" do
- Puppet.features.stubs(:root?).returns(true)
- command = "false"
- user = "user"
- group = "group"
tries = 5
- retry_exec = Puppet::Type.type(:exec).new(:name => command, :path => %w{/usr/bin /bin}, :user => user, :group => group, :returns => 0, :tries => tries, :try_sleep => 0)
- status = stub "process"
- status.stubs(:exitstatus).returns(1)
- Puppet::Util::SUIDManager.expects(:run_and_capture).with([command], user, group).times(tries).returns(["", status])
- proc { retry_exec.refresh }.should raise_error(Puppet::Error)
+ resource = exec_tester("false", 1, :tries => tries, :try_sleep => 0)
+ proc { resource.refresh }.should raise_error(Puppet::Error)
end
end
it "should be able to autorequire files mentioned in the command" do
catalog = Puppet::Resource::Catalog.new
- catalog.add_resource Puppet::Type.type(:file).new(:name => @executable)
- @execer = Puppet::Type.type(:exec).new(:name => @command)
- catalog.add_resource @execer
+ tmp = Puppet::Type.type(:file).new(:name => "/bin/foo")
+ catalog.add_resource tmp
+ execer = Puppet::Type.type(:exec).new(:name => "/bin/foo")
+ catalog.add_resource execer
+
+ catalog.relationship_graph.dependencies(execer).should == [tmp]
+ end
+
+ describe "when handling the path parameter" do
+ expect = %w{one two three four}
+ { "an array" => expect,
+ "a colon separated list" => "one:two:three:four",
+ "a semi-colon separated list" => "one;two;three;four",
+ "both array and colon lists" => ["one", "two:three", "four"],
+ "both array and semi-colon lists" => ["one", "two;three", "four"],
+ "colon and semi-colon lists" => ["one:two", "three;four"]
+ }.each do |test, input|
+ it "should accept #{test}" do
+ type = Puppet::Type.type(:exec).new(:name => @command, :path => input)
+ type[:path].should == expect
+ end
+ end
+ end
+
+ describe "when setting user" do
+ it "should fail if we are not root" do
+ Puppet.features.stubs(:root?).returns(false)
+ expect { Puppet::Type.type(:exec).new(:name => @command, :user => 'input') }.
+ should raise_error Puppet::Error, /Parameter user failed/
+ end
+
+ ['one', 2, 'root', 4294967295, 4294967296].each do |value|
+ it "should accept '#{value}' as user if we are root" do
+ Puppet.features.stubs(:root?).returns(true)
+ type = Puppet::Type.type(:exec).new(:name => @command, :user => value)
+ type[:user].should == value
+ end
+ end
+ end
+
+ describe "when setting group" do
+ shared_examples_for "exec[:group]" do
+ ['one', 2, 'wheel', 4294967295, 4294967296].each do |value|
+ it "should accept '#{value}' without error or judgement" do
+ type = Puppet::Type.type(:exec).new(:name => @command, :group => value)
+ type[:group].should == value
+ end
+ end
+ end
+
+ describe "when running as root" do
+ before :each do Puppet.features.stubs(:root?).returns(true) end
+ it_behaves_like "exec[:group]"
+ end
+
+ describe "when not running as root" do
+ before :each do Puppet.features.stubs(:root?).returns(false) end
+ it_behaves_like "exec[:group]"
+ end
+ end
+
+ describe "when setting cwd" do
+ it_should_behave_like "all path parameters", :cwd, :array => false do
+ def instance(path)
+ Puppet::Type.type(:exec).new(:name => '/bin/true', :cwd => path)
+ end
+ end
+ end
+
+ shared_examples_for "all exec command parameters" do |param|
+ { "relative" => "example", "absolute" => "/bin/example" }.sort.each do |name, command|
+ describe "if command is #{name}" do
+ before :each do
+ @param = param
+ end
+
+ def test(command, valid)
+ if @param == :name then
+ instance = Puppet::Type.type(:exec).new()
+ else
+ instance = Puppet::Type.type(:exec).new(:name => "/bin/true")
+ end
+ if valid then
+ instance.provider.expects(:validatecmd).returns(true)
+ else
+ instance.provider.expects(:validatecmd).raises(Puppet::Error, "from a stub")
+ end
+ instance[@param] = command
+ end
+
+ it "should work if the provider calls the command valid" do
+ expect { test(command, true) }.should_not raise_error
+ end
+
+ it "should fail if the provider calls the command invalid" do
+ expect { test(command, false) }.
+ should raise_error Puppet::Error, /Parameter #{@param} failed: from a stub/
+ end
+ end
+ end
+ end
+
+ shared_examples_for "all exec command parameters that take arrays" do |param|
+ describe "when given an array of inputs" do
+ before :each do
+ @test = Puppet::Type.type(:exec).new(:name => "/bin/true")
+ end
+
+ it "should accept the array when all commands return valid" do
+ input = %w{one two three}
+ @test.provider.expects(:validatecmd).times(input.length).returns(true)
+ @test[param] = input
+ @test[param].should == input
+ end
+
+ it "should reject the array when any commands return invalid" do
+ input = %w{one two three}
+ @test.provider.expects(:validatecmd).with(input.first).returns(false)
+ input[1..-1].each do |cmd|
+ @test.provider.expects(:validatecmd).with(cmd).returns(true)
+ end
+ @test[param] = input
+ @test[param].should == input
+ end
+
+ it "should reject the array when all commands return invalid" do
+ input = %w{one two three}
+ @test.provider.expects(:validatecmd).times(input.length).returns(false)
+ @test[param] = input
+ @test[param].should == input
+ end
+ end
+ end
+
+ describe "when setting refresh" do
+ it_should_behave_like "all exec command parameters", :refresh
+ end
+
+ describe "for simple parameters" do
+ before :each do
+ @exec = Puppet::Type.type(:exec).new(:name => '/bin/true')
+ end
+
+ describe "when setting env" do
+ it "should issue a deprecation warning" do
+ expect { @exec[:env] = 'foo=bar' }.should_not raise_error
+ @logs.first.message.should =~ /deprecate.*environment/
+ end
+
+ it "should update the value of env" do
+ data = ['foo=bar']
+ @exec[:env] = data
+ @exec[:env].should == data
+ end
+
+ it "should forward to environment" do
+ data = ['foo=bar']
+ @exec[:env] = data
+ @exec[:environment].should == data
+ end
+
+ it "should not override environment if both are set" do
+ pending "can't fix: too disruptive for 2.6, removed in 2.7"
+ # ...so this test is here to validate that we know about the problem.
+ # This ensures correct order of evaluation to trigger the bug; don't
+ # count on this happening in the constructor. --daniel 2011-03-01
+ @exec[:environment] = 'environment=true'
+ @exec[:env] = 'env=true'
+
+ @exec[:environment].should == "environment=true"
+ end
+ end
+
+ describe "when setting environment" do
+ { "single values" => "foo=bar",
+ "multiple values" => ["foo=bar", "baz=quux"],
+ }.each do |name, data|
+ it "should accept #{name}" do
+ @exec[:environment] = data
+ @exec[:environment].should == data
+ end
+ end
+
+ { "single values" => "foo",
+ "only values" => ["foo", "bar"],
+ "any values" => ["foo=bar", "baz"]
+ }.each do |name, data|
+ it "should reject #{name} without assignment" do
+ expect { @exec[:environment] = data }.
+ should raise_error Puppet::Error, /Invalid environment setting/
+ end
+ end
+ end
+
+ describe "when setting timeout" do
+ [-3.5, -1, 0, 0.1, 1, 10, 4294967295].each do |valid|
+ it "should accept '#{valid}' as valid" do
+ @exec[:timeout] = valid
+ @exec[:timeout].should == valid
+ end
+
+ it "should accept '#{valid}' in an array as valid" do
+ @exec[:timeout] = [valid]
+ @exec[:timeout].should == valid
+ end
+ end
+
+ ['1/2', '1_000_000', '+12', '', 'foo'].each do |invalid|
+ it "should reject '#{invalid}' as invalid" do
+ expect { @exec[:timeout] = invalid }.
+ should raise_error Puppet::Error, /The timeout must be a number/
+ end
+
+ it "should reject '#{invalid}' in an array as invalid" do
+ expect { @exec[:timeout] = [invalid] }.
+ should raise_error Puppet::Error, /The timeout must be a number/
+ end
+ end
+
+ it "should fail if timeout is exceeded" do
+ File.stubs(:exists?).with('/bin/sleep').returns(true)
+ sleep_exec = Puppet::Type.type(:exec).new(:name => 'sleep 1', :path => ['/bin'], :timeout => '0.2')
+ lambda { sleep_exec.refresh }.should raise_error Puppet::Error, "Command exceeded timeout"
+ end
+ end
+
+ describe "when setting tries" do
+ [1, 10, 4294967295].each do |valid|
+ it "should accept '#{valid}' as valid" do
+ @exec[:tries] = valid
+ @exec[:tries].should == valid
+ end
+
+ if "REVISIT: too much test log spam" == "a good thing" then
+ it "should accept '#{valid}' in an array as valid" do
+ pending "inconsistent, but this is not supporting arrays, unlike timeout"
+ @exec[:tries] = [valid]
+ @exec[:tries].should == valid
+ end
+ end
+ end
+
+ [-3.5, -1, 0, 0.2, '1/2', '1_000_000', '+12', '', 'foo'].each do |invalid|
+ it "should reject '#{invalid}' as invalid" do
+ expect { @exec[:tries] = invalid }.
+ should raise_error Puppet::Error, /Tries must be an integer/
+ end
- rels = @execer.autorequire
- rels[0].should be_instance_of(Puppet::Relationship)
- rels[0].target.should equal(@execer)
+ if "REVISIT: too much test log spam" == "a good thing" then
+ it "should reject '#{invalid}' in an array as invalid" do
+ pending "inconsistent, but this is not supporting arrays, unlike timeout"
+ expect { @exec[:tries] = [invalid] }.
+ should raise_error Puppet::Error, /Tries must be an integer/
+ end
+ end
+ end
+ end
+
+ describe "when setting try_sleep" do
+ [0, 0.2, 1, 10, 4294967295].each do |valid|
+ it "should accept '#{valid}' as valid" do
+ @exec[:try_sleep] = valid
+ @exec[:try_sleep].should == valid
+ end
+
+ if "REVISIT: too much test log spam" == "a good thing" then
+ it "should accept '#{valid}' in an array as valid" do
+ pending "inconsistent, but this is not supporting arrays, unlike timeout"
+ @exec[:try_sleep] = [valid]
+ @exec[:try_sleep].should == valid
+ end
+ end
+ end
+
+ { -3.5 => "cannot be a negative number",
+ -1 => "cannot be a negative number",
+ '1/2' => 'must be a number',
+ '1_000_000' => 'must be a number',
+ '+12' => 'must be a number',
+ '' => 'must be a number',
+ 'foo' => 'must be a number',
+ }.each do |invalid, error|
+ it "should reject '#{invalid}' as invalid" do
+ expect { @exec[:try_sleep] = invalid }.
+ should raise_error Puppet::Error, /try_sleep #{error}/
+ end
+
+ if "REVISIT: too much test log spam" == "a good thing" then
+ it "should reject '#{invalid}' in an array as invalid" do
+ pending "inconsistent, but this is not supporting arrays, unlike timeout"
+ expect { @exec[:try_sleep] = [invalid] }.
+ should raise_error Puppet::Error, /try_sleep #{error}/
+ end
+ end
+ end
+ end
+
+ describe "when setting refreshonly" do
+ [:true, :false].each do |value|
+ it "should accept '#{value}'" do
+ @exec[:refreshonly] = value
+ @exec[:refreshonly].should == value
+ end
+ end
+
+ [1, 0, "1", "0", "yes", "y", "no", "n"].each do |value|
+ it "should reject '#{value}'" do
+ expect { @exec[:refreshonly] = value }.
+ should raise_error(Puppet::Error,
+ /Invalid value #{value.inspect}\. Valid values are true, false/
+ )
+ end
+ end
+ end
+
+ describe "when setting creates" do
+ it_should_behave_like "all path parameters", :creates, :array => true do
+ def instance(path)
+ Puppet::Type.type(:exec).new(:name => '/bin/true', :creates => path)
+ end
+ end
+ end
+ end
+
+ describe "when setting unless" do
+ it_should_behave_like "all exec command parameters", :unless
+ it_should_behave_like "all exec command parameters that take arrays", :unless
+ end
+
+ describe "when setting onlyif" do
+ it_should_behave_like "all exec command parameters", :onlyif
+ it_should_behave_like "all exec command parameters that take arrays", :onlyif
+ end
+
+ describe "#check" do
+ before :each do
+ @test = Puppet::Type.type(:exec).new(:name => "/bin/true")
+ end
+
+ describe ":refreshonly" do
+ { :true => false, :false => true }.each do |input, result|
+ it "should return '#{result}' when given '#{input}'" do
+ @test[:refreshonly] = input
+ @test.check_all_attributes.should == result
+ end
+ end
+ end
+
+ describe ":creates" do
+ before :all do
+ @exist = "/"
+ @unexist = "/this/path/should/never/exist"
+ while FileTest.exist?(@unexist) do @unexist += "/foo" end
+ end
+
+ context "with a single item" do
+ it "should run when the item does not exist" do
+ @test[:creates] = @unexist
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run when the item exists" do
+ @test[:creates] = @exist
+ @test.check_all_attributes.should == false
+ end
+ end
+
+ context "with an array with one item" do
+ it "should run when the item does not exist" do
+ @test[:creates] = [@unexist]
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run when the item exists" do
+ @test[:creates] = [@exist]
+ @test.check_all_attributes.should == false
+ end
+ end
+
+ context "with an array with multiple items" do
+ it "should run when all items do not exist" do
+ @test[:creates] = [@unexist] * 3
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run when one item exists" do
+ @test[:creates] = [@unexist, @exist, @unexist]
+ @test.check_all_attributes.should == false
+ end
+
+ it "should not run when all items exist" do
+ @test[:creates] = [@exist] * 3
+ end
+ end
+ end
+
+ { :onlyif => { :pass => false, :fail => true },
+ :unless => { :pass => true, :fail => false },
+ }.each do |param, sense|
+ describe ":#{param}" do
+ before :each do
+ @pass = "/magic/pass"
+ @fail = "/magic/fail"
+
+ @pass_status = stub('status', :exitstatus => sense[:pass] ? 0 : 1)
+ @fail_status = stub('status', :exitstatus => sense[:fail] ? 0 : 1)
+
+ @test.provider.stubs(:checkexe).returns(true)
+ [true, false].each do |check|
+ @test.provider.stubs(:run).with(@pass, check).
+ returns(['test output', @pass_status])
+ @test.provider.stubs(:run).with(@fail, check).
+ returns(['test output', @fail_status])
+ end
+ end
+
+ context "with a single item" do
+ it "should run if the command exits non-zero" do
+ @test[param] = @fail
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run if the command exits zero" do
+ @test[param] = @pass
+ @test.check_all_attributes.should == false
+ end
+ end
+
+ context "with an array with a single item" do
+ it "should run if the command exits non-zero" do
+ @test[param] = [@fail]
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run if the command exits zero" do
+ @test[param] = [@pass]
+ @test.check_all_attributes.should == false
+ end
+ end
+
+ context "with an array with multiple items" do
+ it "should run if all the commands exits non-zero" do
+ @test[param] = [@fail] * 3
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run if one command exits zero" do
+ @test[param] = [@pass, @fail, @pass]
+ @test.check_all_attributes.should == false
+ end
+
+ it "should not run if all command exits zero" do
+ @test[param] = [@pass] * 3
+ @test.check_all_attributes.should == false
+ end
+ end
+ end
+ end
+ end
+
+ describe "#retrieve" do
+ before :each do
+ @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd")
+ end
+
+ it "should return :notrun when check_all_attributes returns true" do
+ @exec_resource.stubs(:check_all_attributes).returns true
+ @exec_resource.retrieve[:returns].should == :notrun
+ end
+
+ it "should return default exit code 0 when check_all_attributes returns false" do
+ @exec_resource.stubs(:check_all_attributes).returns false
+ @exec_resource.retrieve[:returns].should == ['0']
+ end
+
+ it "should return the specified exit code when check_all_attributes returns false" do
+ @exec_resource.stubs(:check_all_attributes).returns false
+ @exec_resource[:returns] = 42
+ @exec_resource.retrieve[:returns].should == ["42"]
+ end
+ end
+
+ describe "#output" do
+ before :each do
+ @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd")
+ end
+
+ it "should return the provider's run output" do
+ provider = stub 'provider'
+ status = stubs "process_status"
+ status.stubs(:exitstatus).returns("0")
+ provider.expects(:run).returns(["silly output", status])
+ @exec_resource.stubs(:provider).returns(provider)
+
+ @exec_resource.refresh
+ @exec_resource.output.should == 'silly output'
+ end
+ end
+
+ describe "#refresh" do
+ before :each do
+ @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd")
+ end
+
+ it "should call provider run with the refresh parameter if it is set" do
+ provider = stub 'provider'
+ @exec_resource.stubs(:provider).returns(provider)
+ @exec_resource.stubs(:[]).with(:refresh).returns('/myother/bogus/cmd')
+ provider.expects(:run).with('/myother/bogus/cmd')
+
+ @exec_resource.refresh
+ end
+
+ it "should call provider run with the specified command if the refresh parameter is not set" do
+ provider = stub 'provider'
+ status = stubs "process_status"
+ status.stubs(:exitstatus).returns("0")
+ provider.expects(:run).with('/bogus/cmd').returns(["silly output", status])
+ @exec_resource.stubs(:provider).returns(provider)
+
+ @exec_resource.refresh
+ end
+
+ it "should not run the provider if check_all_attributes is false" do
+ @exec_resource.stubs(:check_all_attributes).returns false
+ provider = stub 'provider'
+ provider.expects(:run).never
+ @exec_resource.stubs(:provider).returns(provider)
+
+ @exec_resource.refresh
+ end
end
end
diff --git a/spec/unit/type_spec.rb b/spec/unit/type_spec.rb
index 6d9d0b234..9b1f20500 100755
--- a/spec/unit/type_spec.rb
+++ b/spec/unit/type_spec.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-require File.dirname(__FILE__) + '/../spec_helper'
+require File.expand_path(File.join(File.dirname(__FILE__), '/../spec_helper'))
describe Puppet::Type do
it "should include the Cacher module" do
diff --git a/test/ral/type/exec.rb b/test/ral/type/exec.rb
index 5b26a98a2..dd42ae61f 100755
--- a/test/ral/type/exec.rb
+++ b/test/ral/type/exec.rb
@@ -34,10 +34,8 @@ class TestExec < Test::Unit::TestCase
assert_nothing_raised {
command = Puppet::Type.type(:exec).new(
-
:command => "echo",
-
- :path => "/usr/bin:/bin:/usr/sbin:/sbin"
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin"
)
}
assert_nothing_raised {
@@ -48,10 +46,8 @@ class TestExec < Test::Unit::TestCase
assert_nothing_raised {
command = Puppet::Type.type(:exec).new(
-
:command => "/bin/echo",
-
- :path => "/usr/bin:/bin:/usr/sbin:/sbin"
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin"
)
}
end
@@ -60,30 +56,24 @@ class TestExec < Test::Unit::TestCase
assert_nothing_raised {
command = Puppet::Type.type(:exec).new(
-
:command => "mkdir /this/directory/does/not/exist",
- :path => "/usr/bin:/bin:/usr/sbin:/sbin",
-
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
:returns => 1
)
}
assert_nothing_raised {
command = Puppet::Type.type(:exec).new(
-
:command => "touch /etc",
- :path => "/usr/bin:/bin:/usr/sbin:/sbin",
-
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
:returns => 1
)
}
assert_nothing_raised {
command = Puppet::Type.type(:exec).new(
-
:command => "thiscommanddoesnotexist",
- :path => "/usr/bin:/bin:/usr/sbin:/sbin",
-
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
:returns => 127
)
}
@@ -98,11 +88,9 @@ class TestExec < Test::Unit::TestCase
assert_nothing_raised {
command = Puppet::Type.type(:exec).new(
-
:command => "pwd",
- :cwd => dir,
- :path => "/usr/bin:/bin:/usr/sbin:/sbin",
-
+ :cwd => dir,
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
:returns => 0
)
}
@@ -117,11 +105,9 @@ class TestExec < Test::Unit::TestCase
@@tmpfiles.push tmpfile
trans = nil
- file = Puppet::Type.type(:file).new(
-
- :path => tmpfile,
-
- :content => "yay"
+ file = Puppet::Type.type(:file).new(
+ :path => tmpfile,
+ :content => "yay"
)
# Get the file in sync
assert_apply(file)
@@ -129,13 +115,10 @@ class TestExec < Test::Unit::TestCase
# Now make an exec
maker = tempfile
assert_nothing_raised {
-
cmd = Puppet::Type.type(:exec).new(
-
- :command => "touch #{maker}",
- :path => "/usr/bin:/bin:/usr/sbin:/sbin",
- :subscribe => file,
-
+ :command => "touch #{maker}",
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
+ :subscribe => file,
:refreshonly => true
)
}
@@ -143,7 +126,7 @@ class TestExec < Test::Unit::TestCase
assert(cmd, "did not make exec")
assert_nothing_raised do
- assert(! cmd.check, "Check passed when refreshonly is set")
+ assert(! cmd.check_all_attributes, "Check passed when refreshonly is set")
end
assert_events([], file, cmd)
@@ -158,25 +141,22 @@ class TestExec < Test::Unit::TestCase
def test_refreshonly
cmd = true
assert_nothing_raised {
-
cmd = Puppet::Type.type(:exec).new(
-
- :command => "pwd",
- :path => "/usr/bin:/bin:/usr/sbin:/sbin",
-
+ :command => "pwd",
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
:refreshonly => true
)
}
# Checks should always fail when refreshonly is enabled
- assert(!cmd.check, "Check passed with refreshonly true")
+ assert(!cmd.check_all_attributes, "Check passed with refreshonly true")
# Now make sure it passes if we pass in "true"
- assert(cmd.check(true), "Check failed with refreshonly true while refreshing")
+ assert(cmd.check_all_attributes(true), "Check failed with refreshonly true while refreshing")
# Now set it to false
cmd[:refreshonly] = false
- assert(cmd.check, "Check failed with refreshonly false")
+ assert(cmd.check_all_attributes, "Check failed with refreshonly false")
end
def test_creates
@@ -186,10 +166,8 @@ class TestExec < Test::Unit::TestCase
assert_nothing_raised {
exec = Puppet::Type.type(:exec).new(
-
:command => "touch #{file}",
- :path => "/usr/bin:/bin:/usr/sbin:/sbin",
-
+ :path => "/usr/bin:/bin:/usr/sbin:/sbin",
:creates => file
)
}
@@ -206,21 +184,15 @@ class TestExec < Test::Unit::TestCase
sh = %x{which sh}
File.open(exe, "w") { |f| f.puts "#!#{sh}\necho yup" }
-
- file = Puppet::Type.type(:file).new(
-
- :path => oexe,
- :source => exe,
-
- :mode => 0755
+ file = Puppet::Type.type(:file).new(
+ :path => oexe,
+ :source => exe,
+ :mode => 0755
)
-
- exec = Puppet::Type.type(:exec).new(
-
- :command => oexe,
-
- :require => Puppet::Resource.new(:file, oexe)
+ exec = Puppet::Type.type(:exec).new(
+ :command => oexe,
+ :require => Puppet::Resource.new(:file, oexe)
)
comp = mk_catalog("Testing", file, exec)
@@ -236,47 +208,36 @@ class TestExec < Test::Unit::TestCase
File.open(exe, "w") { |f| f.puts "#!#{sh}\necho yup" }
- file = Puppet::Type.type(:file).new(
-
- :path => oexe,
- :source => exe,
-
- :mode => 755
+ file = Puppet::Type.type(:file).new(
+ :path => oexe,
+ :source => exe,
+ :mode => 755
)
basedir = File.dirname(oexe)
- baseobj = Puppet::Type.type(:file).new(
-
- :path => basedir,
- :source => exe,
-
- :mode => 755
+ baseobj = Puppet::Type.type(:file).new(
+ :path => basedir,
+ :source => exe,
+ :mode => 755
)
- ofile = Puppet::Type.type(:file).new(
-
- :path => exe,
-
- :mode => 755
+ ofile = Puppet::Type.type(:file).new(
+ :path => exe,
+ :mode => 755
)
- exec = Puppet::Type.type(:exec).new(
-
- :command => oexe,
- :path => ENV["PATH"],
-
- :cwd => basedir
+ exec = Puppet::Type.type(:exec).new(
+ :command => oexe,
+ :path => ENV["PATH"],
+ :cwd => basedir
)
-
- cat = Puppet::Type.type(:exec).new(
-
- :command => "cat #{exe} #{oexe}",
-
- :path => ENV["PATH"]
+ cat = Puppet::Type.type(:exec).new(
+ :command => "cat #{exe} #{oexe}",
+ :path => ENV["PATH"]
)
catalog = mk_catalog(file, baseobj, ofile, exec, cat)
@@ -311,11 +272,9 @@ class TestExec < Test::Unit::TestCase
assert_nothing_raised {
exec = Puppet::Type.type(:exec).new(
-
:command => "touch #{bfile}",
- :onlyif => "test -f #{afile}",
-
- :path => ENV['PATH']
+ :onlyif => "test -f #{afile}",
+ :path => ENV['PATH']
)
}
@@ -333,12 +292,9 @@ class TestExec < Test::Unit::TestCase
exec = nil
assert_nothing_raised {
-
exec = Puppet::Type.type(:exec).new(
-
:command => "touch #{bfile}",
:unless => "test -f #{afile}",
-
:path => ENV['PATH']
)
}
@@ -417,13 +373,10 @@ class TestExec < Test::Unit::TestCase
def test_logoutput
exec = nil
assert_nothing_raised {
-
exec = Puppet::Type.type(:exec).new(
-
- :title => "logoutputesting",
- :path => "/usr/bin:/bin",
- :command => "echo logoutput is false",
-
+ :title => "logoutputesting",
+ :path => "/usr/bin:/bin",
+ :command => "echo logoutput is false",
:logoutput => false
)
}
@@ -453,24 +406,19 @@ class TestExec < Test::Unit::TestCase
assert_nothing_raised {
exec = Puppet::Type.type(:exec).new(
-
- :title => "mkdir",
- :path => "/usr/bin:/bin",
+ :title => "mkdir",
+ :path => "/usr/bin:/bin",
:creates => basedir,
-
:command => "mkdir #{basedir}; touch #{path}"
-
)
}
assert_nothing_raised {
file = Puppet::Type.type(:file).new(
-
- :path => basedir,
+ :path => basedir,
:recurse => true,
- :mode => "755",
-
+ :mode => "755",
:require => Puppet::Resource.new("exec", "mkdir")
)
}
@@ -507,12 +455,9 @@ class TestExec < Test::Unit::TestCase
file = tempfile
assert_nothing_raised {
-
exec1 = Puppet::Type.type(:exec).new(
-
- :title => "one",
- :path => ENV["PATH"],
-
+ :title => "one",
+ :path => ENV["PATH"],
:command => "mkdir #{dir}"
)
}
@@ -520,12 +465,10 @@ class TestExec < Test::Unit::TestCase
assert_nothing_raised("Could not create exec w/out existing cwd") {
exec2 = Puppet::Type.type(:exec).new(
-
- :title => "two",
- :path => ENV["PATH"],
+ :title => "two",
+ :path => ENV["PATH"],
:command => "touch #{file}",
-
- :cwd => dir
+ :cwd => dir
)
}
@@ -555,11 +498,8 @@ class TestExec < Test::Unit::TestCase
test = "test -f #{file}"
assert_nothing_raised {
-
exec = Puppet::Type.type(:exec).new(
-
- :path => ENV["PATH"],
-
+ :path => ENV["PATH"],
:command => "touch #{file}"
)
}
@@ -569,7 +509,7 @@ class TestExec < Test::Unit::TestCase
}
assert_nothing_raised {
- assert(exec.check, "Check did not pass")
+ assert(exec.check_all_attributes, "Check did not pass")
}
assert_nothing_raised {
@@ -582,13 +522,13 @@ class TestExec < Test::Unit::TestCase
}
assert_nothing_raised {
- assert(exec.check, "Check did not pass")
+ assert(exec.check_all_attributes, "Check did not pass")
}
assert_apply(exec)
assert_nothing_raised {
- assert(! exec.check, "Check passed")
+ assert(! exec.check_all_attributes, "Check passed")
}
end
@@ -597,33 +537,29 @@ class TestExec < Test::Unit::TestCase
return if Facter.value(:operatingsystem) == "Solaris"
exec = Puppet::Type.type(:exec).new(
-
:command => "echo true",
- :path => ENV["PATH"],
-
- :onlyif => "/bin/nosuchthingexists"
- )
+ :path => ENV["PATH"],
+ :onlyif => "/bin/nosuchthingexists"
+ )
assert_raise(ArgumentError, "Missing command did not raise error") {
- exec.run("/bin/nosuchthingexists")
+ exec.provider.run("/bin/nosuchthingexists")
}
end
def test_envparam
exec = Puppet::Type.newexec(
-
:command => "echo $envtest",
- :path => ENV["PATH"],
-
- :env => "envtest=yayness"
+ :path => ENV["PATH"],
+ :env => "envtest=yayness"
)
assert(exec, "Could not make exec")
output = status = nil
assert_nothing_raised {
- output, status = exec.run("echo $envtest")
+ output, status = exec.provider.run("echo $envtest")
}
assert_equal("yayness\n", output)
@@ -636,7 +572,7 @@ and stuff"
output = status = nil
assert_nothing_raised {
- output, status = exec.run('echo "$envtest"')
+ output, status = exec.provider.run('echo "$envtest"')
}
assert_equal("a list of things\nand stuff\n", output)
@@ -647,7 +583,7 @@ and stuff"
output = status = nil
assert_nothing_raised {
- output, status = exec.run('echo "$funtest" "$yaytest"')
+ output, status = exec.provider.run('echo "$funtest" "$yaytest"')
}
assert_equal("A B\n", output)
end
@@ -655,10 +591,8 @@ and stuff"
def test_environmentparam
exec = Puppet::Type.newexec(
-
- :command => "echo $environmenttest",
- :path => ENV["PATH"],
-
+ :command => "echo $environmenttest",
+ :path => ENV["PATH"],
:environment => "environmenttest=yayness"
)
@@ -666,7 +600,7 @@ and stuff"
output = status = nil
assert_nothing_raised {
- output, status = exec.run("echo $environmenttest")
+ output, status = exec.provider.run("echo $environmenttest")
}
assert_equal("yayness\n", output)
@@ -679,7 +613,7 @@ and stuff"
output = status = nil
assert_nothing_raised {
- output, status = exec.run('echo "$environmenttest"')
+ output, status = exec.provider.run('echo "$environmenttest"')
}
assert_equal("a list of things\nand stuff\n", output)
@@ -690,36 +624,20 @@ and stuff"
output = status = nil
assert_nothing_raised {
- output, status = exec.run('echo "$funtest" "$yaytest"')
+ output, status = exec.provider.run('echo "$funtest" "$yaytest"')
}
assert_equal("A B\n", output)
end
- def test_timeout
- exec = Puppet::Type.type(:exec).new(:command => "sleep 1", :path => ENV["PATH"], :timeout => "0.2")
- time = Time.now
-
- assert_raise(Timeout::Error) {
- exec.run("sleep 1")
- }
- Puppet.info "#{Time.now.to_f - time.to_f} seconds, vs a timeout of #{exec[:timeout]}"
-
-
- assert_apply(exec)
- end
-
# Testing #470
def test_run_as_created_user
exec = nil
if Process.uid == 0
user = "nosuchuser"
assert_nothing_raised("Could not create exec with non-existent user") do
-
exec = Puppet::Type.type(:exec).new(
-
:command => "/bin/echo yay",
-
- :user => user
+ :user => user
)
end
end
@@ -729,10 +647,8 @@ and stuff"
assert_nothing_raised("Could not create exec with non-existent user") do
exec = Puppet::Type.type(:exec).new(
-
:command => "/bin/echo yay",
-
- :group => group
+ :group => group
)
end
end
@@ -759,12 +675,10 @@ and stuff"
file = tempfile
maker = tempfile
- exec = Puppet::Type.type(:exec).new(
-
- :title => "maker",
- :command => "touch #{maker}",
-
- :path => ENV["PATH"]
+ exec = Puppet::Type.type(:exec).new(
+ :title => "maker",
+ :command => "touch #{maker}",
+ :path => ENV["PATH"]
)
# Make sure it runs normally
@@ -801,12 +715,10 @@ and stuff"
refresher = tempfile
maker = tempfile
- exec = Puppet::Type.type(:exec).new(
-
- :title => "maker",
- :command => "touch #{maker}",
-
- :path => ENV["PATH"]
+ exec = Puppet::Type.type(:exec).new(
+ :title => "maker",
+ :command => "touch #{maker}",
+ :path => ENV["PATH"]
)
# Call refresh normally
@@ -844,4 +756,3 @@ and stuff"
end
end
end
-