summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/application/agent.rb2
-rw-r--r--lib/puppet/application/apply.rb3
-rw-r--r--lib/puppet/application/master.rb2
-rw-r--r--lib/puppet/configurer.rb11
-rw-r--r--lib/puppet/defaults.rb9
-rw-r--r--lib/puppet/file_serving/fileset.rb1
-rw-r--r--lib/puppet/indirector/exec.rb3
-rw-r--r--lib/puppet/indirector/report/yaml.rb11
-rw-r--r--lib/puppet/node/environment.rb2
-rw-r--r--lib/puppet/parameter.rb2
-rw-r--r--lib/puppet/parameter/path.rb42
-rw-r--r--lib/puppet/parser/compiler.rb2
-rw-r--r--lib/puppet/parser/lexer.rb5
-rw-r--r--lib/puppet/parser/parser_support.rb1
-rw-r--r--lib/puppet/provider/exec/posix.rb112
-rw-r--r--lib/puppet/provider/exec/shell.rb17
-rwxr-xr-xlib/puppet/provider/package/gem.rb4
-rwxr-xr-xlib/puppet/provider/service/debian.rb8
-rw-r--r--lib/puppet/resource/type_collection.rb7
-rw-r--r--lib/puppet/simple_graph.rb2
-rw-r--r--lib/puppet/transaction.rb2
-rw-r--r--lib/puppet/transaction/report.rb38
-rwxr-xr-xlib/puppet/type/exec.rb197
-rw-r--r--lib/puppet/type/file.rb13
-rwxr-xr-xlib/puppet/util/command_line/puppetrun1
-rwxr-xr-xlib/puppet/util/loadedfile.rb6
-rw-r--r--lib/puppet/util/metric.rb8
27 files changed, 306 insertions, 205 deletions
diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb
index 3749241f8..9f5921de1 100644
--- a/lib/puppet/application/agent.rb
+++ b/lib/puppet/application/agent.rb
@@ -229,6 +229,8 @@ class Puppet::Application::Agent < Puppet::Application
Puppet::SSL::Host.ca_location = options[:fingerprint] ? :none : :remote
Puppet::Transaction::Report.terminus_class = :rest
+ # we want the last report to be persisted locally
+ Puppet::Transaction::Report.cache_class = :yaml
# Override the default; puppetd needs this, usually.
# You can still override this on the command-line with, e.g., :compiler.
diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb
index cc733e1f5..7f0b95a89 100644
--- a/lib/puppet/application/apply.rb
+++ b/lib/puppet/application/apply.rb
@@ -148,6 +148,9 @@ class Puppet::Application::Apply < Puppet::Application
exit(1)
end
+ # we want the last report to be persisted locally
+ Puppet::Transaction::Report.cache_class = :yaml
+
if options[:debug]
Puppet::Util::Log.level = :debug
elsif options[:verbose]
diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb
index 6d1cdef1b..c5e9ada54 100644
--- a/lib/puppet/application/master.rb
+++ b/lib/puppet/application/master.rb
@@ -136,7 +136,7 @@ class Puppet::Application::Master < Puppet::Application
exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
- Puppet.settings.use :main, :master, :ssl
+ Puppet.settings.use :main, :master, :ssl, :metrics
# Cache our nodes in yaml. Currently not configurable.
Puppet::Node.cache_class = :yaml
diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb
index d3c902576..9f68ca499 100644
--- a/lib/puppet/configurer.rb
+++ b/lib/puppet/configurer.rb
@@ -166,19 +166,28 @@ class Puppet::Configurer
execute_postrun_command
Puppet::Util::Log.close(report)
-
send_report(report, transaction)
end
def send_report(report, trans)
report.finalize_report if trans
puts report.summary if Puppet[:summarize]
+ save_last_run_summary(report)
report.save if Puppet[:report]
rescue => detail
puts detail.backtrace if Puppet[:trace]
Puppet.err "Could not send report: #{detail}"
end
+ def save_last_run_summary(report)
+ Puppet::Util::FileLocking.writelock(Puppet[:lastrunfile], 0660) do |file|
+ file.print YAML.dump(report.raw_summary)
+ end
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not save last run local report: #{detail}"
+ end
+
private
def self.timeout
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 8da104086..2a1ded592 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -474,6 +474,7 @@ module Puppet
setdefaults(:metrics,
:rrddir => {:default => "$vardir/rrd",
+ :mode => 0750,
:owner => "service",
:group => "service",
:desc => "The directory where RRD database files are stored.
@@ -606,6 +607,14 @@ module Puppet
:report => [false,
"Whether to send reports after every transaction."
],
+ :lastrunfile => { :default => "$statedir/last_run_summary.yaml",
+ :mode => 0660,
+ :desc => "Where puppet agent stores the last run report summary in yaml format."
+ },
+ :lastrunreport => { :default => "$statedir/last_run_report.yaml",
+ :mode => 0660,
+ :desc => "Where puppet agent stores the last run report in yaml format."
+ },
:graph => [false, "Whether to create dot graph files for the different
configuration graphs. These dot files can be interpreted by tools
like OmniGraffle or dot (which is part of ImageMagick)."],
diff --git a/lib/puppet/file_serving/fileset.rb b/lib/puppet/file_serving/fileset.rb
index fdbcf93a3..c020f036d 100644
--- a/lib/puppet/file_serving/fileset.rb
+++ b/lib/puppet/file_serving/fileset.rb
@@ -59,6 +59,7 @@ class Puppet::FileServing::Fileset
end
def initialize(path, options = {})
+ path = path.chomp(File::SEPARATOR)
raise ArgumentError.new("Fileset paths must be fully qualified") unless File.expand_path(path) == path
@path = path
diff --git a/lib/puppet/indirector/exec.rb b/lib/puppet/indirector/exec.rb
index fa789442b..4683eda0f 100644
--- a/lib/puppet/indirector/exec.rb
+++ b/lib/puppet/indirector/exec.rb
@@ -35,8 +35,7 @@ class Puppet::Indirector::Exec < Puppet::Indirector::Terminus
begin
output = execute(external_command)
rescue Puppet::ExecutionFailure => detail
- Puppet.err "Failed to find #{name} via exec: #{detail}"
- return nil
+ raise Puppet::Error, "Failed to find #{name} via exec: #{detail}"
end
if output =~ /\A\s*\Z/ # all whitespace
diff --git a/lib/puppet/indirector/report/yaml.rb b/lib/puppet/indirector/report/yaml.rb
new file mode 100644
index 000000000..bf7bf4fe5
--- /dev/null
+++ b/lib/puppet/indirector/report/yaml.rb
@@ -0,0 +1,11 @@
+require 'puppet/transaction/report'
+require 'puppet/indirector/yaml'
+
+class Puppet::Transaction::Report::Yaml < Puppet::Indirector::Yaml
+ desc "Store last report as a flat file, serialized using YAML."
+
+ # Force report to be saved there
+ def path(name,ext='.yaml')
+ Puppet[:lastrunreport]
+ end
+end
diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb
index b64fb8a1f..807479bc8 100644
--- a/lib/puppet/node/environment.rb
+++ b/lib/puppet/node/environment.rb
@@ -79,7 +79,7 @@ class Puppet::Node::Environment
# environment has changed do we delve deeper.
Thread.current[:known_resource_types] = nil if (krt = Thread.current[:known_resource_types]) && krt.environment != self
Thread.current[:known_resource_types] ||= synchronize {
- if @known_resource_types.nil? or @known_resource_types.stale?
+ if @known_resource_types.nil? or @known_resource_types.require_reparse?
@known_resource_types = Puppet::Resource::TypeCollection.new(self)
@known_resource_types.perform_initial_import
end
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/parser/compiler.rb b/lib/puppet/parser/compiler.rb
index fdabd05c9..6e8e3d26b 100644
--- a/lib/puppet/parser/compiler.rb
+++ b/lib/puppet/parser/compiler.rb
@@ -162,7 +162,7 @@ class Puppet::Parser::Compiler
resource.evaluate unless lazy_evaluate
found << name
else
- Puppet.info "Could not find class #{name} for #{node.name}"
+ Puppet.warning "Could not find class #{name} for #{node.name}"
@catalog.tag(name)
end
end
diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb
index 9a25263f6..71d9440ff 100644
--- a/lib/puppet/parser/lexer.rb
+++ b/lib/puppet/parser/lexer.rb
@@ -312,7 +312,8 @@ class Puppet::Parser::Lexer
def file=(file)
@file = file
@line = 1
- @scanner = StringScanner.new(File.read(file))
+ contents = File.exists?(file) ? File.read(file) : ""
+ @scanner = StringScanner.new(contents)
end
def shift_token
@@ -547,7 +548,7 @@ class Puppet::Parser::Lexer
value,terminator = slurpstring('"$')
token_queue << [TOKENS[token_type[terminator]],preamble+value]
if terminator != '$' or @scanner.scan(/\{/)
- token_queue.shift
+ token_queue.shift
elsif var_name = @scanner.scan(%r{(\w*::)*\w+|[0-9]})
token_queue << [TOKENS[:VARIABLE],var_name]
tokenize_interpolated_string(DQ_continuation_token_types)
diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb
index 7a0aa2601..9e580efb2 100644
--- a/lib/puppet/parser/parser_support.rb
+++ b/lib/puppet/parser/parser_support.rb
@@ -88,7 +88,6 @@ class Puppet::Parser::Parser
unless file =~ /\.pp$/
file = file + ".pp"
end
- raise Puppet::Error, "Could not find file #{file}" unless FileTest.exist?(file)
end
raise Puppet::AlreadyImportedError, "Import loop detected" if known_resource_types.watching_file?(file)
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/provider/package/gem.rb b/lib/puppet/provider/package/gem.rb
index 19414cec4..28731c849 100755
--- a/lib/puppet/provider/package/gem.rb
+++ b/lib/puppet/provider/package/gem.rb
@@ -22,7 +22,7 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
end
if name = hash[:justme]
- command << name
+ command << name + "$"
end
begin
@@ -94,7 +94,7 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
command << "--source" << "#{source}" << resource[:name]
end
else
- command << resource[:name]
+ command << "--no-rdoc" << "--no-ri" << resource[:name]
end
output = execute(command)
diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb
index 3d09e2849..58b808a8e 100755
--- a/lib/puppet/provider/service/debian.rb
+++ b/lib/puppet/provider/service/debian.rb
@@ -22,8 +22,12 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do
# Remove the symlinks
def disable
- update_rc "-f", @resource[:name], "remove"
- update_rc @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
+ if `dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?`.to_i == 0
+ update_rc @resource[:name], "disable"
+ else
+ update_rc "-f", @resource[:name], "remove"
+ update_rc @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
+ end
end
def enabled?
diff --git a/lib/puppet/resource/type_collection.rb b/lib/puppet/resource/type_collection.rb
index 277d37b18..4210475ad 100644
--- a/lib/puppet/resource/type_collection.rb
+++ b/lib/puppet/resource/type_collection.rb
@@ -162,17 +162,22 @@ class Puppet::Resource::TypeCollection
parser.string = code
else
file = Puppet.settings.value(:manifest, environment.to_s)
- return unless File.exist?(file)
parser.file = file
end
parser.parse
rescue => detail
+ @parse_failed = true
+
msg = "Could not parse for environment #{environment}: #{detail}"
error = Puppet::Error.new(msg)
error.set_backtrace(detail.backtrace)
raise error
end
+ def require_reparse?
+ @parse_failed || stale?
+ end
+
def stale?
@watched_files.values.detect { |file| file.changed? }
end
diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb
index c5dac0f6c..c658b3b92 100644
--- a/lib/puppet/simple_graph.rb
+++ b/lib/puppet/simple_graph.rb
@@ -329,7 +329,7 @@ class Puppet::SimpleGraph
children = other.adjacent(container, :direction => :out)
# MQR TODO: Luke suggests that it should be possible to refactor the system so that
- # container nodes are retained, thus obviating the need for the whit.
+ # container nodes are retained, thus obviating the need for the whit.
children = [whit_class.new(:name => container.name, :catalog => other)] if children.empty?
# First create new edges for each of the :in edges
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index aa650eea1..48154ad6f 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -47,7 +47,7 @@ class Puppet::Transaction
def apply(resource, ancestor = nil)
status = resource_harness.evaluate(resource)
add_resource_status(status)
- event_manager.queue_events(ancestor || resource, status.events)
+ event_manager.queue_events(ancestor || resource, status.events) unless status.failed?
rescue => detail
resource.err "Could not evaluate: #{detail}"
end
diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb
index 8e04759ad..16fee42ae 100644
--- a/lib/puppet/transaction/report.rb
+++ b/lib/puppet/transaction/report.rb
@@ -80,30 +80,49 @@ class Puppet::Transaction::Report
host
end
- # Provide a summary of this report.
+ # Provide a human readable textual summary of this report.
def summary
+ report = raw_summary
+
ret = ""
+ report.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |key|
+ ret += "#{Puppet::Util::Metric.labelize(key)}:\n"
- @metrics.sort { |a,b| a[1].label <=> b[1].label }.each do |name, metric|
- ret += "#{metric.label}:\n"
- metric.values.sort { |a,b|
+ report[key].keys.sort { |a,b|
# sort by label
- if a[0] == :total
+ if a == :total
1
- elsif b[0] == :total
+ elsif b == :total
-1
else
- a[1] <=> b[1]
+ report[key][a].to_s <=> report[key][b].to_s
end
- }.each do |name, label, value|
+ }.each do |label|
+ value = report[key][label]
next if value == 0
value = "%0.2f" % value if value.is_a?(Float)
- ret += " %15s %s\n" % [label + ":", value]
+ ret += " %15s %s\n" % [Puppet::Util::Metric.labelize(label) + ":", value]
end
end
ret
end
+ # Provide a raw hash summary of this report.
+ def raw_summary
+ report = {}
+
+ @metrics.each do |name, metric|
+ key = metric.name.to_s
+ report[key] = {}
+ metric.values.each do |name, label, value|
+ report[key][name.to_s] = value
+ end
+ report[key]["total"] = 0 unless key == "time" or report[key].include?("total")
+ end
+ (report["time"] ||= {})["last_run"] = Time.now.tv_sec
+ report
+ end
+
# Based on the contents of this report's metrics, compute a single number
# that represents the report. The resulting number is a bitmask where
# individual bits represent the presence of different metrics.
@@ -142,7 +161,6 @@ class Puppet::Transaction::Report
metrics["total"] = resource_statuses.length
resource_statuses.each do |name, status|
-
Puppet::Resource::Status::STATES.each do |state|
metrics[state.to_s] += 1 if status.send(state)
end
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index 5ed2b104c..be0ece023 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
@@ -241,19 +229,17 @@ module Puppet
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.
+ and will be stopped. Use 0 to disable the timeout.
The time is specified in seconds."
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
+ begin
+ value = Float(value)
+ rescue ArgumentError => e
+ raise ArgumentError, "The timeout must be a number."
end
+ [value, 0.0].max
end
defaultto 300
@@ -333,7 +319,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 +332,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 +360,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 +402,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 +424,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 +477,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 +492,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 +502,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/lib/puppet/type/file.rb b/lib/puppet/type/file.rb
index e1a4ecbb9..630ebe5de 100644
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -122,7 +122,18 @@ Puppet::Type.newtype(:file) do
newparam(:recurse) do
desc "Whether and how deeply to do recursive
- management."
+ management. Options are:
+
+ * `inf,true` --- Regular style recursion on both remote and local
+ directory structure.
+ * `remote` --- Descends recursively into the remote directory
+ but not the local directory. Allows copying of
+ a few files into a directory containing many
+ unmanaged files without scanning all the local files.
+ * `false` --- Default of no recursion.
+ * `[0-9]+` --- Same as true, but limit recursion. Warning: this syntax
+ has been deprecated in favor of the `recurselimit` attribute.
+ "
newvalues(:true, :false, :inf, :remote, /^[0-9]+$/)
diff --git a/lib/puppet/util/command_line/puppetrun b/lib/puppet/util/command_line/puppetrun
index 7eba3b2c4..3437405b0 100755
--- a/lib/puppet/util/command_line/puppetrun
+++ b/lib/puppet/util/command_line/puppetrun
@@ -107,7 +107,6 @@
# option requires LDAP support at this point.
#
# ping::
-#
# Do a ICMP echo against the target host. Skip hosts that don't respond to ping.
#
# = Example
diff --git a/lib/puppet/util/loadedfile.rb b/lib/puppet/util/loadedfile.rb
index 735dba459..d2f5d0923 100755
--- a/lib/puppet/util/loadedfile.rb
+++ b/lib/puppet/util/loadedfile.rb
@@ -34,10 +34,6 @@ module Puppet
# Create the file. Must be passed the file path.
def initialize(file)
@file = file
- unless FileTest.exists?(@file)
- raise Puppet::NoSuchFile,
- "Can not use a non-existent file for parsing"
- end
@statted = 0
@stamp = nil
@tstamp = stamp
@@ -50,7 +46,7 @@ module Puppet
@statted = Time.now.to_i
begin
@stamp = File.stat(@file).ctime
- rescue Errno::ENOENT
+ rescue Errno::ENOENT, Errno::ENOTDIR
@stamp = Time.now
end
end
diff --git a/lib/puppet/util/metric.rb b/lib/puppet/util/metric.rb
index 09bbb6137..835e1d610 100644
--- a/lib/puppet/util/metric.rb
+++ b/lib/puppet/util/metric.rb
@@ -122,7 +122,7 @@ class Puppet::Util::Metric
def initialize(name,label = nil)
@name = name.to_s
- @label = label || labelize(name)
+ @label = label || self.class.labelize(name)
@values = []
end
@@ -133,7 +133,7 @@ class Puppet::Util::Metric
def newvalue(name,value,label = nil)
raise ArgumentError.new("metric name #{name.inspect} is not a string") unless name.is_a? String
- label ||= labelize(name)
+ label ||= self.class.labelize(name)
@values.push [name,label,value]
end
@@ -174,10 +174,8 @@ class Puppet::Util::Metric
@values.sort { |a, b| a[1] <=> b[1] }
end
- private
-
# Convert a name into a label.
- def labelize(name)
+ def self.labelize(name)
name.to_s.capitalize.gsub("_", " ")
end
end