diff --git a/lib/puppet/type/filebucket.rb b/lib/puppet/type/filebucket.rb index 6fe15ca7e..644231a71 100755 --- a/lib/puppet/type/filebucket.rb +++ b/lib/puppet/type/filebucket.rb @@ -1,102 +1,114 @@ module Puppet require 'puppet/file_bucket/dipper' newtype(:filebucket) do @doc = "A repository for backing up files. If no filebucket is defined, then files will be backed up in their current directory, but the filebucket can be either a host- or site-global repository for backing up. It stores files and returns the MD5 sum, which can later be used to retrieve the file if restoration becomes necessary. A filebucket does not do any work itself; instead, it can be specified as the value of *backup* in a **file** object. Currently, filebuckets are only useful for manual retrieval of accidentally removed files (e.g., you look in the log for the md5 sum and retrieve the file with that sum from the filebucket), but when transactions are fully supported filebuckets will be used to undo transactions. You will normally want to define a single filebucket for your whole network and then use that as the default backup location: # Define the bucket filebucket { 'main': server => puppet, path => false, # Due to a known issue, path must be set to false for remote filebuckets. } # Specify it as the default target File { backup => main } Puppetmaster servers create a filebucket by default, so this will work in a default configuration." newparam(:name) do desc "The name of the filebucket." isnamevar end newparam(:server) do desc "The server providing the remote filebucket. If this is not specified then *path* is checked. If it is set, then the bucket is local. Otherwise the puppetmaster server specified in the config or at the commandline is used. Due to a known issue, you currently must set the `path` attribute to false if you wish to specify a `server` attribute." defaultto { Puppet[:server] } end newparam(:port) do desc "The port on which the remote server is listening. Defaults to the normal Puppet port, %s." % Puppet[:masterport] defaultto { Puppet[:masterport] } end newparam(:path) do desc "The path to the local filebucket. If this is unset, then the bucket is remote. The parameter *server* must can be specified to set the remote server." defaultto { Puppet[:clientbucketdir] } + + validate do |value| + if value.is_a? Array + raise ArgumentError, "You can only have one filebucket path" + end + + if value.is_a? String and not Puppet::Util.absolute_path?(value) + raise ArgumentError, "Filebucket paths must be absolute" + end + + true + end end # Create a default filebucket. def self.mkdefaultbucket new(:name => "puppet", :path => Puppet[:clientbucketdir]) end def bucket mkbucket unless defined?(@bucket) @bucket end private def mkbucket # Default is a local filebucket, if no server is given. # If the default path has been removed, too, then # the puppetmaster is used as default server type = "local" args = {} if self[:path] args[:Path] = self[:path] else args[:Server] = self[:server] args[:Port] = self[:port] end begin @bucket = Puppet::FileBucket::Dipper.new(args) rescue => detail puts detail.backtrace if Puppet[:trace] self.fail("Could not create #{type} filebucket: #{detail}") end @bucket.name = self.name end end end diff --git a/spec/unit/type/filebucket_spec.rb b/spec/unit/type/filebucket_spec.rb index 3c5311184..0603dd5cb 100755 --- a/spec/unit/type/filebucket_spec.rb +++ b/spec/unit/type/filebucket_spec.rb @@ -1,73 +1,101 @@ #!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:filebucket) do describe "when validating attributes" do %w{name server port path}.each do |attr| it "should have a '#{attr}' parameter" do Puppet::Type.type(:filebucket).attrtype(attr.intern).should == :param end end it "should have its 'name' attribute set as its namevar" do Puppet::Type.type(:filebucket).key_attributes.should == [:name] end end it "should use the clientbucketdir as the path by default path" do Puppet.settings[:clientbucketdir] = "/my/bucket" Puppet::Type.type(:filebucket).new(:name => "main")[:path].should == Puppet[:clientbucketdir] end it "should use the masterport as the path by default port" do Puppet.settings[:masterport] = 50 Puppet::Type.type(:filebucket).new(:name => "main")[:port].should == Puppet[:masterport] end it "should use the server as the path by default server" do Puppet.settings[:server] = "myserver" Puppet::Type.type(:filebucket).new(:name => "main")[:server].should == Puppet[:server] end it "be local by default" do bucket = Puppet::Type.type(:filebucket).new :name => "main" bucket.bucket.should be_local end - it "not be local if path is false" do - bucket = Puppet::Type.type(:filebucket).new :name => "main", :path => false + describe "path" do + include PuppetSpec::Files - bucket.bucket.should_not be_local - end + def bucket(hash) + Puppet::Type.type(:filebucket).new({:name => 'main'}.merge(hash)) + end - it "be local if both a path and a server are specified" do - bucket = Puppet::Type.type(:filebucket).new :name => "main", :server => "puppet", :path => "/my/path" + it "should accept false as a value" do + expect { bucket(:path => false) }.not_to raise_error + end - bucket.bucket.should be_local + it "should accept true as a value" do + expect { bucket(:path => true) }.not_to raise_error + end + + it "should fail when given an array of values" do + expect { bucket(:path => ['one', 'two']) }. + to raise_error Puppet::Error, /only have one filebucket path/ + end + + %w{one ../one one/two}.each do |path| + it "should fail if given a relative path of #{path.inspect}" do + expect { bucket(:path => path) }. + to raise_error Puppet::Error, /Filebucket paths must be absolute/ + end + end + + it "should succeed if given an absolute path" do + expect { bucket(:path => make_absolute('/tmp/bucket')) }.not_to raise_error + end + + it "not be local if path is false" do + bucket(:path => false).bucket.should_not be_local + end + + it "be local if both a path and a server are specified" do + bucket(:server => "puppet", :path => "/my/path").bucket.should be_local + end end describe "when creating the filebucket" do before do @bucket = stub 'bucket', :name= => nil end it "should use any provided path" do bucket = Puppet::Type.type(:filebucket).new :name => "main", :path => "/foo/bar" Puppet::FileBucket::Dipper.expects(:new).with(:Path => "/foo/bar").returns @bucket bucket.bucket end it "should use any provided server and port" do bucket = Puppet::Type.type(:filebucket).new :name => "main", :server => "myserv", :port => "myport", :path => false Puppet::FileBucket::Dipper.expects(:new).with(:Server => "myserv", :Port => "myport").returns @bucket bucket.bucket end it "should use the default server if the path is unset and no server is provided" do Puppet.settings[:server] = "myserv" bucket = Puppet::Type.type(:filebucket).new :name => "main", :path => false Puppet::FileBucket::Dipper.expects(:new).with { |args| args[:Server] == "myserv" }.returns @bucket bucket.bucket end end end