[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, upstream, updated. 0.25.5-639-g8f94f35

test branch puppet-dev at googlegroups.com
Wed Jul 14 10:32:13 UTC 2010


The following commit has been merged in the upstream branch:
commit 47c3ca18272e38f16d0e5690c2c9a0e0dbac3285
Author: Luke Kanies <luke at reductivelabs.com>
Date:   Fri Mar 19 22:02:14 2010 -0700

    Converted File[checksum] to a parameter not property
    
    At the same time I removed all of the code in checksum
    that managed tracking changes to the checksum over time.
    I'll add it back in as I fix the fact that changes aren't
    being tracked like the should at the moment.
    
    Signed-off-by: Luke Kanies <luke at reductivelabs.com>

diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb
index 895c0b2..efac1c8 100644
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -722,12 +722,6 @@ Puppet::Type.newtype(:file) do
     # Write out the file.  Requires the content to be written,
     # the property name for logging, and the checksum for validation.
     def write(content, property, checksum = nil)
-        if validate = validate_checksum?
-            # Use the appropriate checksum type -- md5, md5lite, etc.
-            sumtype = property(:checksum).checktype
-            checksum ||= "{#{sumtype}}" + property(:checksum).send(sumtype, content)
-        end
-
         remove_existing(:file)
 
         use_temporary_file = (content.length != 0)
@@ -750,7 +744,7 @@ Puppet::Type.newtype(:file) do
         # And put our new file in place
         if use_temporary_file # This is only not true when our file is empty.
             begin
-                fail_if_checksum_is_wrong(path, checksum) if validate
+                fail_if_checksum_is_wrong(path, content) if validate
                 File.rename(path, self[:path])
             rescue => detail
                 fail "Could not rename temporary file %s to %s : %s" % [path, self[:path], detail]
@@ -763,32 +757,17 @@ Puppet::Type.newtype(:file) do
         # make sure all of the modes are actually correct
         property_fix
 
-        # And then update our checksum, so the next run doesn't find it.
-        self.setchecksum(checksum)
-    end
-
-    # Should we validate the checksum of the file we're writing?
-    def validate_checksum?
-        if sumparam = @parameters[:checksum]
-            return sumparam.checktype.to_s !~ /time/
-        else
-            return false
-        end
     end
 
     private
 
     # Make sure the file we wrote out is what we think it is.
     def fail_if_checksum_is_wrong(path, checksum)
-        if checksum =~ /^\{(\w+)\}.+/
-            sumtype = $1
-        else
-            # This shouldn't happen, but if it happens to, it's nicer
-            # to just use a default sumtype than fail.
-            sumtype = "md5"
-        end
-        newsum = property(:checksum).getsum(sumtype, path)
-        return if newsum == checksum
+        # Use the appropriate checksum type -- md5, md5lite, etc.
+        checksum = parameter(:checksum).sum(content)
+
+        newsum = parameter(:checksum).sum_file(path)
+        return if [:absent, nil, checksum].include?(newsum)
 
         self.fail "File written to disk did not match checksum; discarding changes (%s vs %s)" % [checksum, newsum]
     end
diff --git a/lib/puppet/type/file/checksum.rb b/lib/puppet/type/file/checksum.rb
index 0c45aad..d4c2488 100755
--- a/lib/puppet/type/file/checksum.rb
+++ b/lib/puppet/type/file/checksum.rb
@@ -1,250 +1,26 @@
 require 'puppet/util/checksums'
 
-# Keep a copy of the file checksums, and notify when they change.  This
-# property never actually modifies the system, it only notices when the system
-# changes on its own.
-Puppet::Type.type(:file).newproperty(:checksum) do
+# Specify which checksum algorithm to use when checksumming
+# files.
+Puppet::Type.type(:file).newparam(:checksum) do
     include Puppet::Util::Checksums
 
-    desc "How to check whether a file has changed.  This state is used internally
-        for file copying, but it can also be used to monitor files somewhat
-        like Tripwire without managing the file contents in any way.  You can
-        specify that a file's checksum should be monitored and then subscribe to
-        the file from another object and receive events to signify
-        checksum changes, for instance.
-
-        There are a number of checksum types available including MD5 hashing (and
-        an md5lite variation that only hashes the first 500 characters of the
-        file.
+    desc "The checksum type to use when checksumming a file.
 
         The default checksum parameter, if checksums are enabled, is md5."
 
-    @event = :file_changed
-
-    @unmanaged = true
-
-    @validtypes = %w{md5 md5lite timestamp mtime time none}
-
-    def self.validtype?(type)
-        @validtypes.include?(type)
-    end
-
-    @validtypes.each do |ctype|
-        newvalue(ctype) do
-            handlesum()
-        end
-    end
-
-    str = @validtypes.join("|")
+    newvalues "md5", "md5lite", "timestamp", "mtime", "time", "none"
 
-    # This is here because Puppet sets this internally, using
-    # {md5}......
-    newvalue(/^\{#{str}\}/) do
-        handlesum()
-    end
+    defaultto :md5
 
-    # If they pass us a sum type, behave normally, but if they pass
-    # us a sum type + sum, stick the sum in the cache.
-    munge do |value|
-        if value =~ /^\{(\w+)\}(.+)$/
-            type = symbolize($1)
-            sum = $2
-            cache(type, sum)
-            return type
-        else
-            return :none if value.nil? or value.to_s == "" or value.to_s == "none"
-            if FileTest.directory?(@resource[:path])
-                return :time
-            elsif @resource[:source] and value.to_s != "md5"
-                 self.warning("Files with source set must use md5 as checksum. Forcing to md5 from %s for %s" % [ value, @resource[:path] ])
-                return :md5
-            else
-                return symbolize(value)
-            end
-        end
+    def sum(content)
+        type = value || :md5 # because this might be called before defaults are set
+        "{#{type}}" + send(type, content)
     end
 
-    # Store the checksum in the data cache, or retrieve it if only the
-    # sum type is provided.
-    def cache(type, sum = nil)
-        return unless c = resource.catalog and c.host_config?
-        unless type
-            raise ArgumentError, "A type must be specified to cache a checksum"
-        end
-        type = symbolize(type)
-        type = :mtime if type == :timestamp
-        type = :ctime if type == :time
-
-        unless state = @resource.cached(:checksums)
-            self.debug "Initializing checksum hash"
-            state = {}
-            @resource.cache(:checksums, state)
-        end
-
-        if sum
-            unless sum =~ /\{\w+\}/
-                sum = "{%s}%s" % [type, sum]
-            end
-            state[type] = sum
-        else
-            return state[type]
-        end
-    end
-
-    # Because source and content and whomever else need to set the checksum
-    # and do the updating, we provide a simple mechanism for doing so.
-    def checksum=(value)
-        munge(@should)
-        self.updatesum(value)
-    end
-
-    def checktype
-        self.should || :md5
-    end
-
-    # Checksums need to invert how changes are printed.
-    def change_to_s(currentvalue, newvalue)
-        begin
-            if currentvalue == :absent
-                return "defined '%s' as '%s'" %
-                    [self.name, self.currentsum]
-            elsif newvalue == :absent
-                return "undefined %s from '%s'" %
-                    [self.name, self.is_to_s(currentvalue)]
-            else
-                if defined? @cached and @cached
-                    return "%s changed '%s' to '%s'" %
-                        [self.name, @cached, self.is_to_s(currentvalue)]
-                else
-                    return "%s changed '%s' to '%s'" %
-                        [self.name, self.currentsum, self.is_to_s(currentvalue)]
-                end
-            end
-        rescue Puppet::Error, Puppet::DevError
-            raise
-        rescue => detail
-            raise Puppet::DevError, "Could not convert change %s to string: %s" %
-                [self.name, detail]
-        end
-    end
-
-    def currentsum
-        cache(checktype())
-    end
-
-    # Calculate the sum from disk.
-    def getsum(checktype, file = nil)
-        sum = ""
-
-        checktype = :mtime if checktype == :timestamp
-        checktype = :ctime if checktype == :time
-        self.should = checktype = :md5 if @resource.property(:source)
-
-        file ||= @resource[:path]
-
-        return nil unless FileTest.exist?(file)
-
-        if ! FileTest.file?(file)
-            checktype = :mtime
-        end
-        method = checktype.to_s + "_file"
-
-        self.fail("Invalid checksum type %s" % checktype) unless respond_to?(method)
-
-        return "{%s}%s" % [checktype, send(method, file)]
-    end
-
-    # At this point, we don't actually modify the system, we modify
-    # the stored state to reflect the current state, and then kick
-    # off an event to mark any changes.
-    def handlesum
-        currentvalue = self.retrieve
-        if currentvalue.nil?
-            raise Puppet::Error, "Checksum state for %s is somehow nil" %
-                @resource.title
-        end
-
-        if self.insync?(currentvalue)
-            self.debug "Checksum is already in sync"
-            return nil
-        end
-        # If we still can't retrieve a checksum, it means that
-        # the file still doesn't exist
-        if currentvalue == :absent
-            # if they're copying, then we won't worry about the file
-            # not existing yet
-            return nil unless @resource.property(:source)
-        end
-
-        # If the sums are different, then return an event.
-        if self.updatesum(currentvalue)
-            return :file_changed
-        else
-            return nil
-        end
-    end
-
-    def insync?(currentvalue)
-        @should = [checktype()]
-        if cache(checktype())
-            return currentvalue == currentsum()
-        else
-            # If there's no cached sum, then we don't want to generate
-            # an event.
-            return true
-        end
-    end
-
-    # Even though they can specify multiple checksums, the insync?
-    # mechanism can really only test against one, so we'll just retrieve
-    # the first specified sum type.
-    def retrieve(usecache = false)
-        # When the 'source' is retrieving, it passes "true" here so
-        # that we aren't reading the file twice in quick succession, yo.
-        currentvalue = currentsum()
-        return currentvalue if usecache and currentvalue
-
-        stat = nil
-        return :absent unless stat = @resource.stat
-
-        if stat.ftype == "link" and @resource[:links] != :follow
-            self.debug "Not checksumming symlink"
-            # @resource.delete(:checksum)
-            return currentvalue
-        end
-
-        # Just use the first allowed check type
-        currentvalue = getsum(checktype())
-
-        # If there is no sum defined, then store the current value
-        # into the cache, so that we're not marked as being
-        # out of sync.  We don't want to generate an event the first
-        # time we get a sum.
-        self.updatesum(currentvalue) unless cache(checktype())
-
-        # @resource.debug "checksum state is %s" % self.is
-        return currentvalue
-    end
-
-    # Store the new sum to the state db.
-    def updatesum(newvalue)
-        return unless c = resource.catalog and c.host_config?
-        result = false
-
-        # if we're replacing, vs. updating
-        if sum = cache(checktype())
-            return false if newvalue == sum
-
-            self.debug "Replacing %s checksum %s with %s" % [@resource.title, sum, newvalue]
-            result = true
-        else
-            @resource.debug "Creating checksum %s" % newvalue
-            result = false
-        end
-
-        # Cache the sum so the log message can be right if possible.
-        @cached = sum
-        cache(checktype(), newvalue)
-        return result
+    def sum_file(path)
+        type = value || :md5 # because this might be called before defaults are set
+        method = type.to_s + "_file"
+        "{#{type}}" + send(method, path).to_s
     end
 end
diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb
index 0f26a85..a8a5e7c 100755
--- a/lib/puppet/type/file/content.rb
+++ b/lib/puppet/type/file/content.rb
@@ -30,9 +30,13 @@ module Puppet
         munge do |value|
             if value == :absent
                 value
+            elsif checksum?(value)
+                # XXX This is potentially dangerous because it means users can't write a file whose
+                # entire contents are a plain checksum
+                value
             else
                 @actual_content = value
-                "{#{checksum_type}}" + send(self.checksum_type, value)
+                resource.parameter(:checksum).sum(value)
             end
         end
 
@@ -54,10 +58,8 @@ module Puppet
         def checksum_type
             if source = resource.parameter(:source)
                 result = source.checksum
-            elsif checksum = resource.parameter(:checksum)
-                result = checksum.checktype
-            else
-                return :md5
+            else checksum = resource.parameter(:checksum)
+                result = resource[:checksum]
             end
             if result =~ /^\{(\w+)\}.+/
                 return $1.to_sym
@@ -76,7 +78,7 @@ module Puppet
             if s = resource.parameter(:source)
                 return s.content
             end
-            return nil
+            fail "Could not find actual content from checksum"
         end
 
         def content
@@ -116,10 +118,10 @@ module Puppet
             return :absent unless stat = @resource.stat
             ftype = stat.ftype
             # Don't even try to manage the content on directories or links
-            return nil if ["directory","link"].include? ftype or checksum_type.nil?
+            return nil if ["directory","link"].include?(ftype)
 
             begin
-                "{#{checksum_type}}" + send(checksum_type.to_s + "_file", resource[:path]).to_s
+                resource.parameter(:checksum).sum_file(resource[:path])
             rescue => detail
                 raise Puppet::Error, "Could not read #{ftype} #{@resource.title}: #{detail}"
             end
diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb
index 96369f6..fc4bbea 100755
--- a/lib/puppet/type/file/ensure.rb
+++ b/lib/puppet/type/file/ensure.rb
@@ -73,7 +73,6 @@ module Puppet
                 Dir.mkdir(@resource[:path])
             end
             @resource.send(:property_fix)
-            @resource.setchecksum
             return :directory_created
         end
 
diff --git a/spec/integration/type/file.rb b/spec/integration/type/file.rb
index d1e46a2..259c975 100755
--- a/spec/integration/type/file.rb
+++ b/spec/integration/type/file.rb
@@ -130,6 +130,19 @@ describe Puppet::Type.type(:file) do
             bucket.bucket.getfile(foomd5).should == "fooyay"
             bucket.bucket.getfile(barmd5).should == "baryay"
         end
+
+        it "should propagate failures encountered when renaming the temporary file" do
+            file = Puppet::Type.type(:file).new :path => tmpfile("fail_rename"), :content => "foo"
+            catalog = Puppet::Resource::Catalog.new
+            catalog.add_resource file
+
+            File.open(file[:path], "w") { |f| f.print "bar" }
+
+            File.expects(:rename).raises ArgumentError
+
+            lambda { file.write("something", :content) }.should raise_error(Puppet::Error)
+            File.read(file[:path]).should == "bar"
+        end
     end
 
     describe "when recursing" do
@@ -372,6 +385,7 @@ describe Puppet::Type.type(:file) do
 
             # Now change the file
             File.open(source, "w") { |f| f.print "bar" }
+            file.expire
             catalog.apply
 
             # And make sure it's changed
diff --git a/spec/unit/type/file.rb b/spec/unit/type/file.rb
index cedb170..64ac135 100755
--- a/spec/unit/type/file.rb
+++ b/spec/unit/type/file.rb
@@ -139,13 +139,13 @@ describe Puppet::Type.type(:file) do
     end
 
     describe "when validating attributes" do
-        %w{path backup recurse recurselimit source replace force ignore links purge sourceselect}.each do |attr|
+        %w{path checksum backup recurse recurselimit source replace force ignore links purge sourceselect}.each do |attr|
             it "should have a '#{attr}' parameter" do
                 Puppet::Type.type(:file).attrtype(attr.intern).should == :param
             end
         end
 
-        %w{checksum content target ensure owner group mode type}.each do |attr|
+        %w{content target ensure owner group mode type}.each do |attr|
             it "should have a '#{attr}' property" do
                 Puppet::Type.type(:file).attrtype(attr.intern).should == :property
             end
diff --git a/spec/unit/type/file/checksum.rb b/spec/unit/type/file/checksum.rb
index 5d715d1..8f0f842 100644
--- a/spec/unit/type/file/checksum.rb
+++ b/spec/unit/type/file/checksum.rb
@@ -5,24 +5,55 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f
 checksum = Puppet::Type.type(:file).attrclass(:checksum)
 describe checksum do
     before do
-        # Wow that's a messy interface to the resource.
-        @resource = stub 'resource', :[] => nil, :[]= => nil, :property => nil, :newattr => nil, :parameter => nil
+        @resource = Puppet::Type.type(:file).new :path => "/foo/bar"
+        @checksum = @resource.parameter(:checksum)
     end
 
-    it "should be a subclass of Property" do
-        checksum.superclass.must == Puppet::Property
+    it "should be a parameter" do
+        checksum.superclass.must == Puppet::Parameter
     end
 
-    it "should have default checksum of :md5" do
-        @checksum = checksum.new(:resource => @resource)
-        @checksum.checktype.should == :md5
+    it "should use its current value when asked to sum content" do
+        @checksum.value = :md5lite
+        @checksum.expects(:md5lite).with("foobar").returns "yay"
+        @checksum.sum("foobar")
     end
 
-    [:none, nil, ""].each do |ck|
-        it "should use a none checksum for #{ck.inspect}" do
-            @checksum = checksum.new(:resource => @resource)
-            @checksum.should = "none"
-            @checksum.checktype.should == :none
-        end
+    it "should use :md5 to sum when no value is set" do
+        @checksum.expects(:md5).with("foobar").returns "yay"
+        @checksum.sum("foobar")
+    end
+
+    it "should return the summed contents with a checksum label" do
+        sum = Digest::MD5.hexdigest("foobar")
+        @resource[:checksum] = :md5
+        @checksum.sum("foobar").should == "{md5}#{sum}"
+    end
+
+    it "should use :md5 as its default type" do
+        @checksum.default.should == :md5
+    end
+
+    it "should use its current value when asked to sum a file's content" do
+        @checksum.value = :md5lite
+        @checksum.expects(:md5lite_file).with("/foo/bar").returns "yay"
+        @checksum.sum_file("/foo/bar")
+    end
+
+    it "should use :md5 to sum a file when no value is set" do
+        @checksum.expects(:md5_file).with("/foo/bar").returns "yay"
+        @checksum.sum_file("/foo/bar")
+    end
+
+    it "should convert all sums to strings when summing files" do
+        @checksum.value = :mtime
+        @checksum.expects(:mtime_file).with("/foo/bar").returns Time.now
+        lambda { @checksum.sum_file("/foo/bar") }.should_not raise_error
+    end
+
+    it "should return the summed contents of a file with a checksum label" do
+        @resource[:checksum] = :md5
+        @checksum.expects(:md5_file).returns "mysum"
+        @checksum.sum_file("/foo/bar").should == "{md5}mysum"
     end
 end
diff --git a/spec/unit/type/file/content.rb b/spec/unit/type/file/content.rb
index 442de13..1f21009 100755
--- a/spec/unit/type/file/content.rb
+++ b/spec/unit/type/file/content.rb
@@ -5,8 +5,7 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f
 content = Puppet::Type.type(:file).attrclass(:content)
 describe content do
     before do
-        # Wow that's a messy interface to the resource.
-        @resource = stub 'resource', :[] => nil, :[]= => nil, :property => nil, :newattr => nil, :parameter => nil
+        @resource = Puppet::Type.type(:file).new :path => "/foo/bar"
     end
 
     it "should be a subclass of Property" do
@@ -14,45 +13,31 @@ describe content do
     end
 
     describe "when determining the checksum type" do
-        it "should use the type specified in the source checksum if a source is set" do
-            source = mock 'source'
-            source.expects(:checksum).returns "{litemd5}eh"
-
-            @resource.expects(:parameter).with(:source).returns source
-
-            @content = content.new(:resource => @resource)
-            @content.checksum_type.should == :litemd5
+        before do
+            @resource = Puppet::Type.type(:file).new :path => "/foo/bar"
         end
 
-        it "should use the type specified by the checksum parameter if no source is set" do
-            checksum = mock 'checksum'
-            checksum.expects(:checktype).returns :litemd5
-
-            @resource.expects(:parameter).with(:source).returns nil
-            @resource.expects(:parameter).with(:checksum).returns checksum
+        it "should use the type specified in the source checksum if a source is set" do
+            @resource[:source] = "/foo"
+            @resource.parameter(:source).expects(:checksum).returns "{md5lite}eh"
 
             @content = content.new(:resource => @resource)
-            @content.checksum_type.should == :litemd5
+            @content.checksum_type.should == :md5lite
         end
 
-        it "should only return the checksum type from the checksum parameter if the parameter returns a whole checksum" do
-            checksum = mock 'checksum'
-            checksum.expects(:checktype).returns "{md5}something"
-
-            @resource.expects(:parameter).with(:source).returns nil
-            @resource.expects(:parameter).with(:checksum).returns checksum
-
-            @content = content.new(:resource => @resource)
-            @content.checksum_type.should == :md5
-        end
+        it "should use the type specified by the checksum parameter if no source is set" do
+            @resource[:checksum] = :md5lite
 
-        it "should use md5 if neither a source nor a checksum parameter is available" do
             @content = content.new(:resource => @resource)
-            @content.checksum_type.should == :md5
+            @content.checksum_type.should == :md5lite
         end
     end
 
     describe "when determining the actual content to write" do
+        before do
+            @resource = Puppet::Type.type(:file).new :path => "/foo/bar"
+        end
+
         it "should use the set content if available" do
             @content = content.new(:resource => @resource)
             @content.should = "ehness"
@@ -69,9 +54,9 @@ describe content do
             @content.actual_content.should == "scont"
         end
 
-        it "should return nil if no source is available and no content is set" do
+        it "should fail if no source is available and no content is set" do
             @content = content.new(:resource => @resource)
-            @content.actual_content.should be_nil
+            lambda { @content.actual_content }.should raise_error(Puppet::Error)
         end
     end
 
@@ -100,6 +85,16 @@ describe content do
 
             @content.should.must == :absent
         end
+
+        it "should accept a checksum as the desired content" do
+            @content = content.new(:resource => @resource)
+            digest = Digest::MD5.hexdigest("this is some content")
+
+            string = "{md5}#{digest}"
+            @content.should = string
+
+            @content.should.must == string
+        end
     end
 
     describe "when retrieving the current content" do
@@ -130,29 +125,22 @@ describe content do
 
         it "should always return the checksum as a string" do
             @content = content.new(:resource => @resource)
-            @content.stubs(:checksum_type).returns "mtime"
+            @resource[:checksum] = :mtime
 
             stat = mock 'stat', :ftype => "file"
             @resource.expects(:stat).returns stat
 
-            @resource.expects(:[]).with(:path).returns "/my/file"
-
             time = Time.now
-            @content.expects(:mtime_file).with("/my/file").returns time
+            @resource.parameter(:checksum).expects(:mtime_file).with(@resource[:path]).returns time
 
             @content.retrieve.should == "{mtime}%s" % time
         end
 
         it "should return the checksum of the file if it exists and is a normal file" do
             @content = content.new(:resource => @resource)
-            @content.stubs(:checksum_type).returns "md5"
-
             stat = mock 'stat', :ftype => "file"
             @resource.expects(:stat).returns stat
-
-            @resource.expects(:[]).with(:path).returns "/my/file"
-
-            @content.expects(:md5_file).with("/my/file").returns "mysum"
+            @resource.parameter(:checksum).expects(:md5_file).with(@resource[:path]).returns "mysum"
 
             @content.retrieve.should == "{md5}mysum"
         end
@@ -160,11 +148,8 @@ describe content do
 
     describe "when testing whether the content is in sync" do
         before do
-            @resource.stubs(:[]).with(:ensure).returns :file
-            @resource.stubs(:replace?).returns true
-            @resource.stubs(:should_be_file?).returns true
+            @resource[:ensure] = :file
             @content = content.new(:resource => @resource)
-            @content.stubs(:checksum_type).returns "md5"
         end
 
         it "should return true if the resource shouldn't be a regular file" do

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list