summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/application/inspect.rb51
-rw-r--r--lib/puppet/defaults.rb5
-rw-r--r--lib/puppet/file_bucket/dipper.rb9
-rw-r--r--lib/puppet/file_bucket/file.rb108
-rw-r--r--lib/puppet/indirector/file_bucket_file/file.rb120
-rw-r--r--lib/puppet/indirector/indirection.rb26
-rw-r--r--lib/puppet/indirector/rest.rb21
-rw-r--r--lib/puppet/network/http/api/v1.rb3
-rw-r--r--lib/puppet/network/http/handler.rb17
-rw-r--r--lib/puppet/network/rest_authconfig.rb16
-rwxr-xr-xlib/puppet/network/rights.rb37
-rw-r--r--lib/puppet/resource/status.rb4
-rw-r--r--lib/puppet/transaction/resource_harness.rb7
13 files changed, 201 insertions, 223 deletions
diff --git a/lib/puppet/application/inspect.rb b/lib/puppet/application/inspect.rb
index 8c3a0011f..19324e285 100644
--- a/lib/puppet/application/inspect.rb
+++ b/lib/puppet/application/inspect.rb
@@ -1,4 +1,6 @@
+require 'puppet'
require 'puppet/application'
+require 'puppet/file_bucket/dipper'
class Puppet::Application::Inspect < Puppet::Application
@@ -54,20 +56,55 @@ class Puppet::Application::Inspect < Puppet::Application
inspect_starttime = Time.now
@report.add_times("config_retrieval", inspect_starttime - retrieval_starttime)
+ if Puppet[:archive_files]
+ dipper = Puppet::FileBucket::Dipper.new(:Server => Puppet[:archive_file_server])
+ end
+
catalog.to_ral.resources.each do |ral_resource|
audited_attributes = ral_resource[:audit]
next unless audited_attributes
- audited_resource = ral_resource.to_resource
-
status = Puppet::Resource::Status.new(ral_resource)
- audited_attributes.each do |name|
- next if audited_resource[name].nil?
- # Skip :absent properties of :absent resources. Really, it would be nicer if the RAL returned nil for those, but it doesn't. ~JW
- if name == :ensure or audited_resource[:ensure] != :absent or audited_resource[name] != :absent
- event = ral_resource.event(:previous_value => audited_resource[name], :property => name, :status => "audit", :message => "inspected value is #{audited_resource[name].inspect}")
+
+ begin
+ audited_resource = ral_resource.to_resource
+ rescue StandardError => detail
+ puts detail.backtrace if Puppet[:trace]
+ ral_resource.err "Could not inspect #{ral_resource}; skipping: #{detail}"
+ audited_attributes.each do |name|
+ event = ral_resource.event(
+ :property => name,
+ :status => "failure",
+ :audited => true,
+ :message => "failed to inspect #{name}"
+ )
status.add_event(event)
end
+ else
+ audited_attributes.each do |name|
+ next if audited_resource[name].nil?
+ # Skip :absent properties of :absent resources. Really, it would be nicer if the RAL returned nil for those, but it doesn't. ~JW
+ if name == :ensure or audited_resource[:ensure] != :absent or audited_resource[name] != :absent
+ event = ral_resource.event(
+ :previous_value => audited_resource[name],
+ :property => name,
+ :status => "audit",
+ :audited => true,
+ :message => "inspected value is #{audited_resource[name].inspect}"
+ )
+ status.add_event(event)
+ end
+ end
+ end
+ if Puppet[:archive_files] and ral_resource.type == :file and audited_attributes.include?(:content)
+ path = ral_resource[:path]
+ if File.readable?(path)
+ begin
+ dipper.backup(path)
+ rescue StandardError => detail
+ Puppet.warning detail
+ end
+ end
end
@report.add_resource_status(status)
end
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 1e7229d01..e8b9846cb 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -622,6 +622,11 @@ module Puppet
compression, but if it supports it, this setting might reduce performance on high-speed LANs."]
)
+ setdefaults(:inspect,
+ :archive_files => [false, "During an inspect run, whether to archive files whose contents are audited to a file bucket."],
+ :archive_file_server => ["$server", "During an inspect run, the file bucket server to archive files to if archive_files is set."]
+ )
+
# Plugin information.
setdefaults(
diff --git a/lib/puppet/file_bucket/dipper.rb b/lib/puppet/file_bucket/dipper.rb
index 367d6bfbd..be487d83f 100644
--- a/lib/puppet/file_bucket/dipper.rb
+++ b/lib/puppet/file_bucket/dipper.rb
@@ -33,10 +33,15 @@ class Puppet::FileBucket::Dipper
raise(ArgumentError, "File #{file} does not exist") unless ::File.exist?(file)
contents = ::File.read(file)
begin
- file_bucket_file = Puppet::FileBucket::File.new(contents, :bucket_path => @local_path, :path => absolutize_path(file) )
+ file_bucket_file = Puppet::FileBucket::File.new(contents, :bucket_path => @local_path)
dest_path = "#{@rest_path}#{file_bucket_file.name}"
- Puppet::FileBucket::File.indirection.save(file_bucket_file, dest_path)
+ # Make a HEAD request for the file so that we don't waste time
+ # uploading it if it already exists in the bucket.
+ unless Puppet::FileBucket::File.indirection.head("#{@rest_path}#{file_bucket_file.checksum_type}/#{file_bucket_file.checksum_data}")
+ Puppet::FileBucket::File.indirection.save(file_bucket_file, dest_path)
+ end
+
return file_bucket_file.checksum_data
rescue => detail
puts detail.backtrace if Puppet[:trace]
diff --git a/lib/puppet/file_bucket/file.rb b/lib/puppet/file_bucket/file.rb
index 96fd8e225..08c0329f1 100644
--- a/lib/puppet/file_bucket/file.rb
+++ b/lib/puppet/file_bucket/file.rb
@@ -1,10 +1,9 @@
require 'puppet/file_bucket'
require 'puppet/indirector'
require 'puppet/util/checksums'
+require 'digest/md5'
class Puppet::FileBucket::File
- include Puppet::Util::Checksums
-
# This class handles the abstract notion of a file in a filebucket.
# There are mechanisms to save and load this file locally and remotely in puppet/indirector/filebucketfile/*
# There is a compatibility class that emulates pre-indirector filebuckets in Puppet::FileBucket::Dipper
@@ -12,71 +11,27 @@ class Puppet::FileBucket::File
require 'puppet/file_bucket/file/indirection_hooks'
indirects :file_bucket_file, :terminus_class => :file, :extend => Puppet::FileBucket::File::IndirectionHooks
- attr :path, true
- attr :paths, true
- attr :contents, true
- attr :checksum_type
- attr :bucket_path, true
-
- def self.default_checksum_type
- "md5"
- end
+ attr :contents
+ attr :bucket_path
def initialize( contents, options = {} )
- @bucket_path = options[:bucket_path]
- @path = options[:path]
- @paths = options[:paths] || []
-
- @checksum = options[:checksum]
- @checksum_type = options[:checksum_type]
-
- self.contents = contents
-
- yield(self) if block_given?
-
- validate!
- end
+ raise ArgumentError if !contents.is_a?(String)
+ @contents = contents
- def validate!
- validate_checksum_type!(checksum_type)
- validate_checksum!(checksum) if checksum
+ @bucket_path = options.delete(:bucket_path)
+ raise ArgumentError if options != {}
end
- def contents=(str)
- raise "You may not change the contents of a FileBucket File" if @contents
- validate_content!(str)
- @contents = str
+ def checksum_type
+ 'md5'
end
def checksum
- return @checksum if @checksum
- @checksum = calculate_checksum if contents
- @checksum
- end
-
- def checksum=(checksum)
- validate_checksum!(checksum)
- @checksum = checksum
- end
-
- def checksum_type=( new_checksum_type )
- @checksum = nil
- @checksum_type = new_checksum_type
- end
-
- def checksum_type
- unless @checksum_type
- if @checksum
- @checksum_type = sumtype(checksum)
- else
- @checksum_type = self.class.default_checksum_type
- end
- end
- @checksum_type
+ "{#{checksum_type}}#{checksum_data}"
end
def checksum_data
- sumdata(checksum)
+ @checksum_data ||= Digest::MD5.hexdigest(contents)
end
def to_s
@@ -84,18 +39,7 @@ class Puppet::FileBucket::File
end
def name
- [checksum_type, checksum_data, path].compact.join('/')
- end
-
- def name=(name)
- data = name.split('/',3)
- self.path = data.pop
- @checksum_type = nil
- self.checksum = "{#{data[0]}}#{data[1]}"
- end
-
- def conflict_check?
- true
+ "#{checksum_type}/#{checksum_data}"
end
def self.from_s( contents )
@@ -103,34 +47,10 @@ class Puppet::FileBucket::File
end
def to_pson
- hash = { "contents" => contents }
- hash["path"] = @path if @path
- hash.to_pson
+ { "contents" => contents }.to_pson
end
def self.from_pson( pson )
- self.new( pson["contents"], :path => pson["path"] )
- end
-
- private
-
- def calculate_checksum
- "{#{checksum_type}}" + send(checksum_type, contents)
- end
-
- def validate_content!(content)
- raise ArgumentError, "Contents must be a string" if content and ! content.is_a?(String)
- end
-
- def validate_checksum!(new_checksum)
- newtype = sumtype(new_checksum)
-
- unless sumdata(new_checksum) == (calc_sum = send(newtype, contents))
- raise Puppet::Error, "Checksum #{new_checksum} does not match contents #{calc_sum}"
- end
- end
-
- def validate_checksum_type!(type)
- raise ArgumentError, "Invalid checksum type #{type}" unless respond_to?(type)
+ self.new( pson["contents"] )
end
end
diff --git a/lib/puppet/indirector/file_bucket_file/file.rb b/lib/puppet/indirector/file_bucket_file/file.rb
index 318858aaf..8bea2d767 100644
--- a/lib/puppet/indirector/file_bucket_file/file.rb
+++ b/lib/puppet/indirector/file_bucket_file/file.rb
@@ -14,16 +14,31 @@ module Puppet::FileBucketFile
end
def find( request )
- checksum, path = request_to_checksum_and_path( request )
- find_by_checksum( checksum, request.options )
+ checksum = request_to_checksum( request )
+ file_path = path_for(request.options[:bucket_path], checksum, 'contents')
+
+ return nil unless ::File.exists?(file_path)
+
+ if request.options[:diff_with]
+ hash_protocol = sumtype(checksum)
+ file2_path = path_for(request.options[:bucket_path], request.options[:diff_with], 'contents')
+ raise "could not find diff_with #{request.options[:diff_with]}" unless ::File.exists?(file2_path)
+ return `diff #{file_path.inspect} #{file2_path.inspect}`
+ else
+ contents = ::File.read file_path
+ Puppet.info "FileBucket read #{checksum}"
+ model.new(contents)
+ end
end
- def save( request )
- checksum, path = request_to_checksum_and_path( request )
+ def head(request)
+ checksum = request_to_checksum(request)
+ file_path = path_for(request.options[:bucket_path], checksum, 'contents')
+ ::File.exists?(file_path)
+ end
+ def save( request )
instance = request.instance
- instance.checksum = checksum if checksum
- instance.path = path if path
save_to_disk(instance)
instance.to_s
@@ -31,66 +46,41 @@ module Puppet::FileBucketFile
private
- def find_by_checksum( checksum, options )
- model.new( nil, :checksum => checksum ) do |bucket_file|
- bucket_file.bucket_path = options[:bucket_path]
- filename = contents_path_for( bucket_file )
-
- return nil if ! ::File.exist? filename
-
- begin
- contents = ::File.read filename
- Puppet.info "FileBucket read #{bucket_file.checksum}"
- rescue RuntimeError => e
- raise Puppet::Error, "file could not be read: #{e.message}"
- end
-
- if ::File.exist?(paths_path_for( bucket_file) )
- ::File.open(paths_path_for( bucket_file) ) do |f|
- bucket_file.paths = f.readlines.map { |l| l.chomp }
- end
- end
-
- bucket_file.contents = contents
- end
- end
-
def save_to_disk( bucket_file )
- # If the file already exists, just return the md5 sum.
- if ::File.exist?(contents_path_for( bucket_file) )
+ filename = path_for(bucket_file.bucket_path, bucket_file.checksum_data, 'contents')
+ dirname = path_for(bucket_file.bucket_path, bucket_file.checksum_data)
+
+ # If the file already exists, do nothing.
+ if ::File.exist?(filename)
verify_identical_file!(bucket_file)
else
# Make the directories if necessary.
- unless ::File.directory?( path_for( bucket_file) )
+ unless ::File.directory?(dirname)
Puppet::Util.withumask(0007) do
- ::FileUtils.mkdir_p( path_for( bucket_file) )
+ ::FileUtils.mkdir_p(dirname)
end
end
- Puppet.info "FileBucket adding #{bucket_file.path} as #{bucket_file.checksum}"
+ Puppet.info "FileBucket adding #{bucket_file.checksum}"
# Write the file to disk.
Puppet::Util.withumask(0007) do
- ::File.open(contents_path_for(bucket_file), ::File::WRONLY|::File::CREAT, 0440) do |of|
+ ::File.open(filename, ::File::WRONLY|::File::CREAT, 0440) do |of|
of.print bucket_file.contents
end
end
end
-
- save_path_to_paths_file(bucket_file)
- bucket_file.checksum_data
end
- def request_to_checksum_and_path( request )
- return [request.key, nil] if checksum?(request.key)
-
- checksum_type, checksum, path = request.key.split(/\//, 3)
- return(checksum_type.to_s == "" ? nil : [ "{#{checksum_type}}#{checksum}", path ])
+ def request_to_checksum( request )
+ checksum_type, checksum, path = request.key.split(/\//, 3) # Note: we ignore path if present.
+ raise "Unsupported checksum type #{checksum_type.inspect}" if checksum_type != 'md5'
+ raise "Invalid checksum #{checksum.inspect}" if checksum !~ /^[0-9a-f]{32}$/
+ checksum
end
- def path_for(bucket_file, subfile = nil)
- bucket_path = bucket_file.bucket_path || Puppet[:bucketdir]
- digest = bucket_file.checksum_data
+ def path_for(bucket_path, digest, subfile = nil)
+ bucket_path ||= Puppet[:bucketdir]
dir = ::File.join(digest[0..7].split(""))
basedir = ::File.join(bucket_path, dir, digest)
@@ -99,48 +89,18 @@ module Puppet::FileBucketFile
::File.join(basedir, subfile)
end
- def contents_path_for(bucket_file)
- path_for(bucket_file, "contents")
- end
-
- def paths_path_for(bucket_file)
- path_for(bucket_file, "paths")
- end
-
- def content_check?
- true
- end
-
# If conflict_check is enabled, verify that the passed text is
# the same as the text in our file.
def verify_identical_file!(bucket_file)
- return unless content_check?
- disk_contents = ::File.read(contents_path_for(bucket_file))
+ disk_contents = ::File.read(path_for(bucket_file.bucket_path, bucket_file.checksum_data, 'contents'))
# If the contents don't match, then we've found a conflict.
# Unlikely, but quite bad.
if disk_contents != bucket_file.contents
- raise Puppet::FileBucket::BucketError, "Got passed new contents for sum #{bucket_file.checksum}", caller
+ raise Puppet::FileBucket::BucketError, "Got passed new contents for sum #{bucket_file.checksum}"
else
- Puppet.info "FileBucket got a duplicate file #{bucket_file.path} (#{bucket_file.checksum})"
+ Puppet.info "FileBucket got a duplicate file #{bucket_file.checksum}"
end
end
-
- def save_path_to_paths_file(bucket_file)
- return unless bucket_file.path
-
- # check for dupes
- if ::File.exist?(paths_path_for( bucket_file) )
- ::File.open(paths_path_for( bucket_file) ) do |f|
- return if f.readlines.collect { |l| l.chomp }.include?(bucket_file.path)
- end
- end
-
- # if it's a new file, or if our path isn't in the file yet, add it
- ::File.open(paths_path_for(bucket_file), ::File::WRONLY|::File::CREAT|::File::APPEND) do |of|
- of.puts bucket_file.path
- end
- end
-
end
end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index eb0aa8aee..d958a82ac 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -180,18 +180,13 @@ class Puppet::Indirector::Indirection
request = request(:find, key, *args)
terminus = prepare(request)
- begin
- if result = find_in_cache(request)
- return result
- end
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Cached #{self.name} for #{request.key} failed: #{detail}"
+ if result = find_in_cache(request)
+ return result
end
# Otherwise, return the result from the terminus, caching if appropriate.
if ! request.ignore_terminus? and result = terminus.find(request)
- result.expiration ||= self.expiration
+ result.expiration ||= self.expiration if result.respond_to?(:expiration)
if cache? and request.use_cache?
Puppet.info "Caching #{self.name} for #{request.key}"
cache.save request(:save, result, *args)
@@ -203,6 +198,17 @@ class Puppet::Indirector::Indirection
nil
end
+ # Search for an instance in the appropriate terminus, and return a
+ # boolean indicating whether the instance was found.
+ def head(key, *args)
+ request = request(:head, key, *args)
+ terminus = prepare(request)
+
+ # Look in the cache first, then in the terminus. Force the result
+ # to be a boolean.
+ !!(find_in_cache(request) || terminus.head(request))
+ end
+
def find_in_cache(request)
# See if our instance is in the cache and up to date.
return nil unless cache? and ! request.ignore_cache? and cached = cache.find(request)
@@ -213,6 +219,10 @@ class Puppet::Indirector::Indirection
Puppet.debug "Using cached #{self.name} for #{request.key}"
cached
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Cached #{self.name} for #{request.key} failed: #{detail}"
+ nil
end
# Remove something via the terminus.
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index eb41ff3b1..e50dc68ae 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -53,11 +53,15 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
end
else
# Raise the http error if we didn't get a 'success' of some kind.
- message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
- raise Net::HTTPError.new(message, response)
+ raise convert_to_http_error(response)
end
end
+ def convert_to_http_error(response)
+ message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
+ Net::HTTPError.new(message, response)
+ end
+
# Provide appropriate headers.
def headers
add_accept_encoding({"Accept" => model.supported_formats.join(", ")})
@@ -73,6 +77,19 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
result
end
+ def head(request)
+ response = network(request).head(indirection2uri(request), headers)
+ case response.code
+ when "404"
+ return false
+ when /^2/
+ return true
+ else
+ # Raise the http error if we didn't get a 'success' of some kind.
+ raise convert_to_http_error(response)
+ end
+ end
+
def search(request)
unless result = deserialize(network(request).get(indirection2uri(request), headers), true)
return []
diff --git a/lib/puppet/network/http/api/v1.rb b/lib/puppet/network/http/api/v1.rb
index abbb2dfa9..4b7c15a36 100644
--- a/lib/puppet/network/http/api/v1.rb
+++ b/lib/puppet/network/http/api/v1.rb
@@ -13,6 +13,9 @@ module Puppet::Network::HTTP::API::V1
},
"DELETE" => {
:singular => :destroy
+ },
+ "HEAD" => {
+ :singular => :head
}
}
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
index 916f02c8d..2b9e81b61 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -114,7 +114,22 @@ module Puppet::Network::HTTP::Handler
format = format_to_use(request)
set_content_type(response, format)
- set_response(response, result.render(format))
+ if result.respond_to?(:render)
+ set_response(response, result.render(format))
+ else
+ set_response(response, result)
+ end
+ end
+
+ # Execute our head.
+ def do_head(indirection_request, request, response)
+ unless indirection_request.model.head(indirection_request.key, indirection_request.to_hash)
+ Puppet.info("Could not find #{indirection_request.indirection_name} for '#{indirection_request.key}'")
+ return do_exception(response, "Could not find #{indirection_request.indirection_name} #{indirection_request.key}", 404)
+ end
+
+ # No need to set a response because no response is expected from a
+ # HEAD request. All we need to do is not die.
end
# Execute our search.
diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb
index 850f9211c..9e3632499 100644
--- a/lib/puppet/network/rest_authconfig.rb
+++ b/lib/puppet/network/rest_authconfig.rb
@@ -38,14 +38,10 @@ module Puppet
# fail_on_deny could as well be called in the XMLRPC context
# with a ClientRequest.
- @rights.fail_on_deny(
- build_uri(indirection, key),
- :node => params[:node],
- :ip => params[:ip],
- :method => method,
- :environment => params[:environment],
- :authenticated => params[:authenticated]
- )
+ if authorization_failure_exception = @rights.is_request_forbidden_and_why?(indirection, method, key, params)
+ Puppet.warning("Denying access: #{authorization_failure_exception}")
+ raise authorization_failure_exception
+ end
end
def initialize(file = nil, parsenow = true)
@@ -88,9 +84,5 @@ module Puppet
end
@rights.restrict_authenticated(acl[:acl], acl[:authenticated]) unless acl[:authenticated].nil?
end
-
- def build_uri(indirection_name, key)
- "/#{indirection_name}/#{key}"
- end
end
end
diff --git a/lib/puppet/network/rights.rb b/lib/puppet/network/rights.rb
index e3cd3179a..56af53983 100755
--- a/lib/puppet/network/rights.rb
+++ b/lib/puppet/network/rights.rb
@@ -26,19 +26,29 @@ class Rights
# Check that name is allowed or not
def allowed?(name, *args)
- begin
- fail_on_deny(name, :node => args[0], :ip => args[1])
- rescue AuthorizationError
- return false
- rescue ArgumentError
- # the namespace contract says we should raise this error
- # if we didn't find the right acl
- raise
+ !is_forbidden_and_why?(name, :node => args[0], :ip => args[1])
+ end
+
+ def is_request_forbidden_and_why?(indirection, method, key, params)
+ methods_to_check = if method == :head
+ # :head is ok if either :find or :save is ok.
+ [:find, :save]
+ else
+ [method]
+ end
+ authorization_failure_exceptions = methods_to_check.map do |method|
+ is_forbidden_and_why?("/#{indirection}/#{key}", params.merge({:method => method}))
+ end
+ if authorization_failure_exceptions.include? nil
+ # One of the methods we checked is ok, therefore this request is ok.
+ nil
+ else
+ # Just need to return any of the failure exceptions.
+ authorization_failure_exceptions.first
end
- true
end
- def fail_on_deny(name, args = {})
+ def is_forbidden_and_why?(name, args = {})
res = :nomatch
right = @rights.find do |acl|
found = false
@@ -49,7 +59,7 @@ class Rights
args[:match] = match
if (res = acl.allowed?(args[:node], args[:ip], args)) != :dunno
# return early if we're allowed
- return if res
+ return nil if res
# we matched, select this acl
found = true
end
@@ -70,13 +80,12 @@ class Rights
error.file = right.file
error.line = right.line
end
- Puppet.warning("Denying access: #{error}")
else
# there were no rights allowing/denying name
# if name is not a path, let's throw
- error = ArgumentError.new "Unknown namespace right '#{name}'"
+ raise ArgumentError.new "Unknown namespace right '#{name}'"
end
- raise error
+ error
end
def initialize
diff --git a/lib/puppet/resource/status.rb b/lib/puppet/resource/status.rb
index ee83004bb..dea8c105d 100644
--- a/lib/puppet/resource/status.rb
+++ b/lib/puppet/resource/status.rb
@@ -12,7 +12,7 @@ module Puppet
attr_reader :source_description, :default_log_level, :time, :resource
attr_reader :change_count, :out_of_sync_count, :resource_type, :title
- YAML_ATTRIBUTES = %w{@resource @file @line @evaluation_time @change_count @out_of_sync_count @tags @time @events @out_of_sync @changed @resource_type @title}
+ YAML_ATTRIBUTES = %w{@resource @file @line @evaluation_time @change_count @out_of_sync_count @tags @time @events @out_of_sync @changed @resource_type @title @skipped @failed}
# Provide a boolean method for each of the states.
STATES.each do |attr|
@@ -51,6 +51,8 @@ module Puppet
@out_of_sync_count = 0
@changed = false
@out_of_sync = false
+ @skipped = false
+ @failed = false
[:file, :line].each do |attr|
send(attr.to_s + "=", resource.send(attr))
diff --git a/lib/puppet/transaction/resource_harness.rb b/lib/puppet/transaction/resource_harness.rb
index c259d3e05..c1b980632 100644
--- a/lib/puppet/transaction/resource_harness.rb
+++ b/lib/puppet/transaction/resource_harness.rb
@@ -37,7 +37,10 @@ class Puppet::Transaction::ResourceHarness
current_values = current.to_hash
historical_values = Puppet::Util::Storage.cache(resource).dup
- desired_values = resource.to_resource.to_hash
+ desired_values = {}
+ resource.properties.each do |property|
+ desired_values[property.name] = property.should
+ end
audited_params = (resource[:audit] || []).map { |p| p.to_sym }
synced_params = []
@@ -55,7 +58,7 @@ class Puppet::Transaction::ResourceHarness
elsif current_values[:ensure] != :absent
work_order = resource.properties # Note: only the resource knows what order to apply changes in
work_order.each do |param|
- if !param.insync?(current_values[param.name])
+ if desired_values[param.name] && !param.insync?(current_values[param.name])
events << apply_parameter(param, current_values[param.name], audited_params.include?(param.name), historical_values[param.name])
synced_params << param.name
end