[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:31:45 UTC 2010


The following commit has been merged in the upstream branch:
commit 58920a0bb95b8579162500856b2e6524ff20168e
Author: Luke Kanies <luke at madstop.com>
Date:   Wed Apr 1 08:31:49 2009 -0400

    Converting File terminus to use formats.
    
    This fixes most of #1943, except the checksum indirection
    still uses this.
    
    This basically always chooses the most recent file when
    finding files, and saves the file with the default format.
    
    Signed-off-by: Luke Kanies <luke at madstop.com>

diff --git a/lib/puppet/indirector/file.rb b/lib/puppet/indirector/file.rb
index 99d95ec..cc7ad9b 100644
--- a/lib/puppet/indirector/file.rb
+++ b/lib/puppet/indirector/file.rb
@@ -1,58 +1,79 @@
 require 'puppet/indirector/terminus'
 
-# An empty terminus type, meant to just return empty objects.
+# Store instances as files, usually serialized using some format.
 class Puppet::Indirector::File < Puppet::Indirector::Terminus
+    # Where do we store our data?
+    def data_directory
+        name = Puppet[:name] == "puppetmasterd" ? :server_datadir : :client_datadir
+
+        File.join(Puppet.settings[name], self.class.indirection_name.to_s)
+    end
+
+    def file_format(path)
+        path =~ /\.(\w+)$/ and return $1
+    end
+
+    def file_path(request)
+        File.join(data_directory, request.key + "." + serialization_format)
+    end
+
+    def latest_path(request)
+        files = Dir.glob(File.join(data_directory, request.key + ".*"))
+        return nil if files.empty?
+
+        # Return the newest file.
+        files.sort { |a, b| File.stat(b).mtime <=> File.stat(a).mtime }[0]
+    end
+
+    def serialization_format
+        model.default_format
+    end
+
     # Remove files on disk.
     def destroy(request)
-        if respond_to?(:path)
-            path = path(request.key)
-        else
-            path = request.key
-        end
-        raise Puppet::Error.new("File %s does not exist; cannot destroy" % [request.key]) unless File.exist?(path)
-
-        Puppet.notice "Removing file %s %s at '%s'" % [model, request.key, path]
         begin
-            File.unlink(path)
+            removed = false
+            Dir.glob(File.join(data_directory, request.key.to_s + ".*")).each do |file|
+                removed = true
+                File.unlink(file)
+            end
         rescue => detail
-            raise Puppet::Error, "Could not remove %s: %s" % [request.key, detail]
+            raise Puppet::Error, "Could not remove #{request.key}: #{detail}"
         end
+
+        raise Puppet::Error, "Could not find files for #{request.key} to remove" unless removed
     end
 
     # Return a model instance for a given file on disk.
     def find(request)
-        if respond_to?(:path)
-            path = path(request.key)
-        else
-            path = request.key
-        end
+        return nil unless path = latest_path(request)
+        format = file_format(path)
 
-        return nil unless File.exist?(path)
+        raise ArgumentError, "File format #{format} is not supported by #{self.class.indirection_name}" unless model.support_format?(format)
 
         begin
-            content = File.read(path)
+            return model.convert_from(format, File.read(path))
         rescue => detail
-            raise Puppet::Error, "Could not retrieve path %s: %s" % [path, detail]
+            raise Puppet::Error, "Could not convert path #{path} into a #{self.class.indirection_name}: #{detail}"
         end
-
-        return model.new(content)
     end
 
     # Save a new file to disk.
     def save(request)
-        if respond_to?(:path)
-            path = path(request.key)
-        else
-            path = request.key
-        end
+        path = file_path(request)
+
         dir = File.dirname(path)
 
-        raise Puppet::Error.new("Cannot save %s; parent directory %s does not exist" % [request.key, dir]) unless File.directory?(dir)
+        raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} does not exist") unless File.directory?(dir)
 
         begin
-            File.open(path, "w") { |f| f.print request.instance.content }
+            File.open(path, "w") { |f| f.print request.instance.render(serialization_format) }
         rescue => detail
-            raise Puppet::Error, "Could not write %s: %s" % [request.key, detail]
+            raise Puppet::Error, "Could not write #{request.key}: #{detail}" % [request.key, detail]
         end
     end
+
+    def path(key)
+        key
+    end
 end
diff --git a/spec/unit/indirector/file.rb b/spec/unit/indirector/file.rb
index c19d8be..4b3532e 100755
--- a/spec/unit/indirector/file.rb
+++ b/spec/unit/indirector/file.rb
@@ -26,136 +26,156 @@ describe Puppet::Indirector::File do
     end
 
     describe Puppet::Indirector::File, " when finding files" do
-
         it "should provide a method to return file contents at a specified path" do
             @searcher.should respond_to(:find)
         end
 
-        it "should return file contents as an instance of the model" do
-            content = "my content"
+        it "should use the server data directory plus the indirection name if the process name is 'puppetmasterd'" do
+            Puppet.settings.expects(:value).with(:name).returns "puppetmasterd"
+            Puppet.settings.expects(:value).with(:server_datadir).returns "/my/dir"
+
+            @searcher.data_directory.should == File.join("/my/dir", "mystuff")
+        end
 
-            file = mock 'file'
-            @model.expects(:new).with(content).returns(file)
+        it "should use the client data directory plus the indirection name if the process name is not 'puppetmasterd'" do
+            Puppet.settings.expects(:value).with(:name).returns "puppetd"
+            Puppet.settings.expects(:value).with(:client_datadir).returns "/my/dir"
 
-            File.expects(:exist?).with(@path).returns(true)
-            File.expects(:read).with(@path).returns(content)
-            @searcher.find(@request)
+            @searcher.data_directory.should == File.join("/my/dir", "mystuff")
         end
 
-        it "should create the model instance with the content as the only argument to initialization" do
-            content = "my content"
+        it "should use the newest file in the data directory matching the indirection key without extension" do
+            @searcher.expects(:data_directory).returns "/data/dir"
+            @request.stubs(:key).returns "foo"
+            Dir.expects(:glob).with("/data/dir/foo.*").returns %w{/data1.stuff /data2.stuff}
 
-            file = mock 'file'
-            @model.expects(:new).with(content).returns(file)
+            stat1 = stub 'data1', :mtime => (Time.now - 5)
+            stat2 = stub 'data2', :mtime => Time.now
+            File.expects(:stat).with("/data1.stuff").returns stat1
+            File.expects(:stat).with("/data2.stuff").returns stat2
 
-            File.expects(:exist?).with(@path).returns(true)
-            File.expects(:read).with(@path).returns(content)
-            @searcher.find(@request).should equal(file)
+            @searcher.latest_path(@request).should == "/data2.stuff"
         end
 
-        it "should return nil if no file is found" do
-            File.expects(:exist?).with(@path).returns(false)
+        it "should return nil when no files are found" do
+            @searcher.stubs(:latest_path).returns nil
+
             @searcher.find(@request).should be_nil
         end
 
-        it "should fail intelligently if a found file cannot be read" do
-            File.expects(:exist?).with(@path).returns(true)
-            File.expects(:read).with(@path).raises(RuntimeError)
-            proc { @searcher.find(@request) }.should raise_error(Puppet::Error)
+        it "should determine the file format from the file extension" do
+            @searcher.file_format("/data2.pson").should == "pson"
         end
 
-        it "should use the path() method to calculate the path if it exists" do
-            @searcher.meta_def(:path) do |name|
-                name.upcase
-            end
+        it "should fail if the model does not support the file format" do
+            @searcher.stubs(:latest_path).returns "/my/file.pson"
 
-            File.expects(:exist?).with(@path.upcase).returns(false)
-            @searcher.find(@request)
+            @model.expects(:support_format?).with("pson").returns false
+
+            lambda { @searcher.find(@request) }.should raise_error(ArgumentError)
         end
     end
 
     describe Puppet::Indirector::File, " when saving files" do
         before do
             @content = "my content"
-            @file = stub 'file', :content => @content, :path => @path, :name => @path
+            @file = stub 'file', :content => @content, :path => @path, :name => @path, :render => "mydata"
             @request.stubs(:instance).returns @file
         end
 
         it "should provide a method to save file contents at a specified path" do
-            filehandle = mock 'file'
-            File.expects(:directory?).with(@dir).returns(true)
-            File.expects(:open).with(@path, "w").yields(filehandle)
-            filehandle.expects(:print).with(@content)
+            @searcher.should respond_to(:save)
+        end
 
-            @searcher.save(@request)
+        it "should choose the file extension based on the default format of the model" do
+            @model.expects(:default_format).returns "pson"
+
+            @searcher.serialization_format.should == "pson"
         end
 
-        it "should fail intelligently if the file's parent directory does not exist" do
-            File.expects(:directory?).with(@dir).returns(false)
+        it "should place the file in the data directory, named after the indirection, key, and format" do
+            @searcher.stubs(:data_directory).returns "/my/dir"
+            @searcher.stubs(:serialization_format).returns "pson"
 
-            proc { @searcher.save(@request) }.should raise_error(Puppet::Error)
+            @request.stubs(:key).returns "foo"
+            @searcher.file_path(@request).should == File.join("/my/dir", "foo.pson")
         end
 
-        it "should fail intelligently if a file cannot be written" do
-            filehandle = mock 'file'
-            File.expects(:directory?).with(@dir).returns(true)
-            File.expects(:open).with(@path, "w").yields(filehandle)
-            filehandle.expects(:print).with(@content).raises(ArgumentError)
+        it "should fail intelligently if the file's parent directory does not exist" do
+            @searcher.stubs(:file_path).returns "/my/dir/file.pson"
+            @searcher.stubs(:serialization_format).returns "pson"
+
+            @request.stubs(:key).returns "foo"
+            File.expects(:directory?).with(File.join("/my/dir")).returns(false)
 
             proc { @searcher.save(@request) }.should raise_error(Puppet::Error)
         end
 
-        it "should use the path() method to calculate the path if it exists" do
-            @searcher.meta_def(:path) do |name|
-                name.upcase
-            end
+        it "should render the instance using the file format and print it to the file path" do
+            @searcher.stubs(:file_path).returns "/my/file.pson"
+            @searcher.stubs(:serialization_format).returns "pson"
+
+            File.stubs(:directory?).returns true
+
+            @request.instance.expects(:render).with("pson").returns "data"
 
-            # Reset the key to something without a parent dir, so no checks are necessary
-            @request.stubs(:key).returns "/my"
+            fh = mock 'filehandle'
+            File.expects(:open).with("/my/file.pson", "w").yields fh
+            fh.expects(:print).with("data")
 
-            File.expects(:open).with("/MY", "w")
             @searcher.save(@request)
         end
+
+        it "should fail intelligently if a file cannot be written" do
+            filehandle = mock 'file'
+            File.stubs(:directory?).returns(true)
+            File.stubs(:open).yields(filehandle)
+            filehandle.expects(:print).raises(ArgumentError)
+
+            @searcher.stubs(:file_path).returns "/my/file.pson"
+            @model.stubs(:default_format).returns "pson"
+
+            @instance.stubs(:render).returns "stuff"
+
+            proc { @searcher.save(@request) }.should raise_error(Puppet::Error)
+        end
     end
 
     describe Puppet::Indirector::File, " when removing files" do
+        it "should provide a method to remove files" do
+            @searcher.should respond_to(:destroy)
+        end
 
-        it "should provide a method to remove files at a specified path" do
-            File.expects(:exist?).with(@path).returns(true)
-            File.expects(:unlink).with(@path)
+        it "should remove files in all formats found in the data directory that match the request key" do
+            @searcher.stubs(:data_directory).returns "/my/dir"
+            @request.stubs(:key).returns "me"
 
-            @searcher.destroy(@request)
-        end
+            Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one /two}
 
-        it "should throw an exception if the file is not found" do
-            File.expects(:exist?).with(@path).returns(false)
+            File.expects(:unlink).with("/one")
+            File.expects(:unlink).with("/two")
 
-            proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error)
+            @searcher.destroy(@request)
         end
 
-        it "should fail intelligently if the file cannot be removed" do
-            File.expects(:exist?).with(@path).returns(true)
-            File.expects(:unlink).with(@path).raises(ArgumentError)
+        it "should throw an exception if no file is found" do
+            @searcher.stubs(:data_directory).returns "/my/dir"
+            @request.stubs(:key).returns "me"
+
+            Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns []
 
             proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error)
         end
 
-        it "should log that is removing the file" do
-            File.expects(:exist?).returns(true)
-            File.expects(:unlink)
-            Puppet.expects(:notice)
-            @searcher.destroy(@request)
-        end
+        it "should fail intelligently if a file cannot be removed" do
+            @searcher.stubs(:data_directory).returns "/my/dir"
+            @request.stubs(:key).returns "me"
 
-        it "should use the path() method to calculate the path if it exists" do
-            @searcher.meta_def(:path) do |thing|
-                thing.to_s.upcase
-            end
+            Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one}
 
-            File.expects(:exist?).with("/MY/FILE").returns(true)
-            File.expects(:unlink).with("/MY/FILE")
+            File.expects(:unlink).with("/one").raises ArgumentError
 
-            @searcher.destroy(@request)
+            proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error)
         end
     end
 end
diff --git a/spec/unit/indirector/yaml.rb b/spec/unit/indirector/yaml.rb
index 7536fbc..a461b0c 100755
--- a/spec/unit/indirector/yaml.rb
+++ b/spec/unit/indirector/yaml.rb
@@ -27,10 +27,10 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do
     end
 
     describe Puppet::Indirector::Yaml, " when choosing file location" do
-        it "should use the yamldir if the process name is 'puppetmasterd'" do
+        it "should use the server_datadir if the process name is 'puppetmasterd'" do
             Puppet.settings.expects(:value).with(:name).returns "puppetmasterd"
-            Puppet.settings.expects(:value).with(:yamldir).returns "/main/yaml/dir"
-            @store.path(:me).should =~ %r{^/main/yaml/dir}
+            Puppet.settings.expects(:value).with(:server_datadir).returns "/server/data/dir"
+            @store.path(:me).should =~ %r{^/server/data/dir}
         end
 
         it "should use the client yamldir if the process name is not 'puppetmasterd'" do

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list