From 069f29bf2b348e540c63c12bc203838b02d8a0bf Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Mon, 17 Jan 2011 12:01:13 +1100 Subject: Fixed #2096 - clarified option modification and tested it is working --- lib/puppet/reference/configuration.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/puppet/reference/configuration.rb b/lib/puppet/reference/configuration.rb index e6a8dc20f..c8ff145ba 100644 --- a/lib/puppet/reference/configuration.rb +++ b/lib/puppet/reference/configuration.rb @@ -94,11 +94,11 @@ The file follows INI-style formatting. Here is an example of a very simple Note that boolean parameters must be explicitly specified as `true` or `false` as seen above. -If you need to change file parameters (e.g., reset the mode or owner), do +If you need to change file or directory parameters (e.g., reset the mode or owner), do so within curly braces on the same line: [main] - myfile = /tmp/whatever {owner = root, mode = 644} + vardir = /new/vardir {owner = root, mode = 644} If you're starting out with a fresh configuration, you may wish to let the executable generate a template configuration file for you by invoking -- cgit From 7e7f34237f67ad27534855d1df328c96e30285bf Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Mon, 17 Jan 2011 12:23:29 +1100 Subject: Fixed #1657 - Added note about target file --- lib/puppet/type/host.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index 8ab750459..2666e50ae 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -66,7 +66,7 @@ module Puppet newproperty(:target) do desc "The file in which to store service information. Only used by - those providers that write to disk." + those providers that write to disk. On most systems this defaults to `/etc/hosts`." defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile) @resource.class.defaultprovider.default_target -- cgit From 1fd3600458b8561d33d34369d349ecefee04996b Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Fri, 21 Jan 2011 04:04:45 +1100 Subject: Fixed #3646 - Added documentation for compile and apply to man page --- lib/puppet/util/command_line/puppetmasterd | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/puppet/util/command_line/puppetmasterd b/lib/puppet/util/command_line/puppetmasterd index baf8a7581..445169820 100755 --- a/lib/puppet/util/command_line/puppetmasterd +++ b/lib/puppet/util/command_line/puppetmasterd @@ -9,6 +9,7 @@ # # puppet master [-D|--daemonize|--no-daemonize] [-d|--debug] [-h|--help] # [-l|--logdest |console|syslog] [-v|--verbose] [-V|--version] +# [--compile ] [--apply ] # # = Description # @@ -49,6 +50,14 @@ # version:: # Print the puppet version number and exit. # +# compile:: +# Capability to compile a catalogue and output it in JSON from the Puppet master. Uses +# facts contained in the $vardir/yaml/ directory to compile the catalog. +# +# apply:: +# Capability to apply JSON catalog (such as one generated with --compile). You can either specify +# a JSON file or pipe in JSON from standard input. +# # = Example # # puppet master -- cgit From 70630b903b747db0148cd972b64e5162b8f459cc Mon Sep 17 00:00:00 2001 From: Jesse Wolfe Date: Mon, 18 Oct 2010 15:24:37 -0700 Subject: Fix #3165 Ralsh (bin/puppet resource) can't manage files This is based on the patch submitted by Owen Smith. File management was being blocked by two problems: an obsolete, broken `instances` method for the file type, and a bug in the way resource/ral handled slashes in resource names. This patch makes two changes to Owen's version: 1) our unit tests caught an unexpected ruby quirk: "text/".split("/") and "text/".split("/", 2) do not return the same values. 2) File.instances now reproduces the old behavior of listing files in the root directory. This is now implemented in terms of the existing file recursion feature. --- lib/puppet/indirector/resource/ral.rb | 9 +++++++-- lib/puppet/type/file.rb | 21 ++------------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/lib/puppet/indirector/resource/ral.rb b/lib/puppet/indirector/resource/ral.rb index 1c2ab14ae..bc41d14ae 100644 --- a/lib/puppet/indirector/resource/ral.rb +++ b/lib/puppet/indirector/resource/ral.rb @@ -34,12 +34,17 @@ class Puppet::Resource::Ral < Puppet::Indirector::Code private + # {type,resource}_name: the resource name may contain slashes: + # File["/etc/hosts"]. To handle, assume the type name does + # _not_ have any slashes in it, and split only on the first. + def type_name( request ) - request.key.split('/')[0] + request.key.split('/', 2)[0] end def resource_name( request ) - request.key.split('/')[1] + name = request.key.split('/', 2)[1] + name unless name == "" end def type( request ) diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index eee948cd5..dc0fe7b24 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -290,25 +290,8 @@ Puppet::Type.newtype(:file) do super(path.gsub(/\/+/, '/').sub(/\/$/, '')) end - # List files, but only one level deep. - def self.instances(base = "/") - return [] unless FileTest.directory?(base) - - files = [] - Dir.entries(base).reject { |e| - e == "." or e == ".." - }.each do |name| - path = File.join(base, name) - if obj = self[path] - obj[:audit] = :all - files << obj - else - files << self.new( - :name => path, :audit => :all - ) - end - end - files + def self.instances(base = '/') + return self.new(:name => base, :recurse => true, :recurselimit => 1, :audit => :all).recurse_local.values end @depthfirst = false -- cgit From 18ca97b0d16fae149a1eab04c520421b5eb38969 Mon Sep 17 00:00:00 2001 From: Dan Bode Date: Sat, 8 Jan 2011 17:18:25 -0600 Subject: (#5045) Adds support to resource/type to also accept a param hash The params are added as attributes when the resource is created. Also, even if the class already exists, if params are passed, we still try to create it. Reviewed-by: Matt Robinson --- lib/puppet/resource/type.rb | 14 +++++++++++--- spec/unit/resource/type_spec.rb | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index d40adc145..a31795a1b 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -143,18 +143,26 @@ class Puppet::Resource::Type # classes and nodes. No parameters are be supplied--if this is a # parameterized class, then all parameters take on their default # values. - def ensure_in_catalog(scope) + def ensure_in_catalog(scope, attributes=nil) type == :definition and raise ArgumentError, "Cannot create resources for defined resource types" resource_type = type == :hostclass ? :class : :node # Do nothing if the resource already exists; this makes sure we don't # get multiple copies of the class resource, which helps provide the # singleton nature of classes. - if resource = scope.catalog.resource(resource_type, name) + # we should not do this for classes with attributes + # if attributes are passed, we should still try to create the resource + # even if it exists so that we can fail + # this prevents us from being able to combine param classes with include + if resource = scope.catalog.resource(resource_type, name) and !attributes return resource end - resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self) + if attributes + attributes.each do |k,v| + resource.set_parameter(k,v) + end + end instantiate_resource(scope, resource) scope.compiler.add_resource(scope, resource) resource diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index 7b240bb82..11288f100 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -601,12 +601,37 @@ describe Puppet::Resource::Type do @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end + it "should add specified attributes to the resource" do + @top.ensure_in_catalog(@scope, {'one'=>'1', 'two'=>'2'}) + @compiler.catalog.resource(:class, "top")['one'].should == '1' + @compiler.catalog.resource(:class, "top")['two'].should == '2' + end + + it "should not require params for a param class" do + @top.ensure_in_catalog(@scope, {}) + @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) + end + it "should evaluate the parent class if one exists" do @middle.ensure_in_catalog(@scope) @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end + it "should evaluate the parent class if one exists" do + @middle.ensure_in_catalog(@scope, {}) + + @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) + end + + it "should fail if you try to create duplicate class resources" do + othertop = Puppet::Parser::Resource.new(:class, 'top',:source => @source, :scope => @scope ) + # add the same class resource to the catalog + @compiler.catalog.add_resource(othertop) + @compiler.catalog.expects(:resource).with(:class, 'top').returns true + lambda { @top.ensure_in_catalog(@scope, {}) }.should raise_error(Puppet::Resource::Catalog::DuplicateResourceError) + end + it "should fail to evaluate if a parent class is defined but cannot be found" do othertop = Puppet::Resource::Type.new :hostclass, "something", :parent => "yay" @code.add othertop -- cgit From a2036ea693996cb6ba5eb9f8f52fefa843a320a6 Mon Sep 17 00:00:00 2001 From: Dan Bode Date: Sat, 8 Jan 2011 17:34:19 -0600 Subject: (#5045) External node classifiers should be able to specify params for classes It facilitates the support for param classes from the ENC. It adds support for classes to be passed as a hash to the evaluate_classes method. If a hash of classes is specified, it also evaluates duplicates. I also had to convert the hash to an array for tags to be applied correctly. Reviewed-by: Matt Robinson --- lib/puppet/parser/compiler.rb | 21 ++++++++++++--- spec/unit/parser/compiler_spec.rb | 55 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index c60e1d4fb..3134e03d9 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -139,12 +139,23 @@ class Puppet::Parser::Compiler def evaluate_classes(classes, scope, lazy_evaluate = true) raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source found = [] + param_classes = nil + # if we are a param class, save the classes hash + # and transform classes to be the keys + if classes.class == Hash + param_classes = classes + classes = classes.keys + end classes.each do |name| # If we can find the class, then make a resource that will evaluate it. if klass = scope.find_hostclass(name) - found << name and next if scope.class_scope(klass) - resource = klass.ensure_in_catalog(scope) + if param_classes + resource = klass.ensure_in_catalog(scope, param_classes[name] || {}) + else + found << name and next if scope.class_scope(klass) and !param_classes + resource = klass.ensure_in_catalog(scope) + end # If they've disabled lazy evaluation (which the :include function does), # then evaluate our resource immediately. @@ -432,7 +443,11 @@ class Puppet::Parser::Compiler @resources = [] # Make sure any external node classes are in our class list - @catalog.add_class(*@node.classes) + if @node.classes.class == Hash + @catalog.add_class(*@node.classes.keys) + else + @catalog.add_class(*@node.classes) + end end # Set the node's parameters into the top-scope as variables. diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index 95f3853e2..c1e7c48c2 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -109,6 +109,15 @@ describe Puppet::Parser::Compiler do compiler.classlist.should include("bar") end + it "should transform node class hashes into a class list" do + node = Puppet::Node.new("mynode") + node.classes = {'foo'=>{'one'=>'1'}, 'bar'=>{'two'=>'2'}} + compiler = Puppet::Parser::Compiler.new(node) + + compiler.classlist.should include("foo") + compiler.classlist.should include("bar") + end + it "should add a 'main' stage to the catalog" do @compiler.catalog.resource(:stage, :main).should be_instance_of(Puppet::Parser::Resource) end @@ -185,6 +194,14 @@ describe Puppet::Parser::Compiler do @compiler.class.publicize_methods(:evaluate_node_classes) { @compiler.evaluate_node_classes } end + it "should evaluate any parameterized classes named in the node" do + classes = {'foo'=>{'1'=>'one'}, 'bar'=>{'2'=>'two'}} + @node.stubs(:classes).returns(classes) + @compiler.expects(:evaluate_classes).with(classes, @compiler.topscope) + @compiler.compile + end + + it "should evaluate the main class if it exists" do compile_stub(:evaluate_main) main_class = @known_resource_types.add Puppet::Resource::Type.new(:hostclass, "") @@ -566,6 +583,14 @@ describe Puppet::Parser::Compiler do @scope.expects(:find_hostclass).with("notfound").returns(nil) @compiler.evaluate_classes(%w{notfound}, @scope) end + # I wish it would fail + it "should log when it can't find class" do + klasses = {'foo'=>nil} + @node.classes = klasses + @compiler.topscope.stubs(:find_hostclass).with('foo').returns(nil) + Puppet.expects(:info).with('Could not find class foo for testnode') + @compiler.compile + end end describe "when evaluating found classes" do @@ -586,6 +611,28 @@ describe Puppet::Parser::Compiler do @compiler.evaluate_classes(%w{myclass}, @scope) end + # test that ensure_in_catalog is called for existing classes + it "should ensure each node class hash is in catalog" do + klasses = {'foo'=>{'1'=>'one'}, 'bar'=>{'2'=>'two'}} + @node.classes = klasses + klasses.each do |name, params| + klass = Puppet::Resource::Type.new(:hostclass, name) + @compiler.topscope.stubs(:find_hostclass).with(name).returns(klass) + klass.expects(:ensure_in_catalog).with(@compiler.topscope, params) + end + @compiler.compile + end + + it "should ensure class is in catalog without params" do + @node.classes = klasses = {'foo'=>nil} + foo = Puppet::Resource::Type.new(:hostclass, 'foo') + @compiler.topscope.stubs(:find_hostclass).with('foo').returns(foo) + foo.expects(:ensure_in_catalog).with(@compiler.topscope, {}) + @compiler.compile + end + + + it "should not evaluate the resources created for found classes unless asked" do @compiler.catalog.stubs(:tag) @@ -620,6 +667,14 @@ describe Puppet::Parser::Compiler do @compiler.evaluate_classes(%w{myclass}, @scope, false) end + it "should not skip param classes that have already been evaluated" do + @scope.stubs(:class_scope).with(@class).returns("something") + @node.classes = klasses = {'foo'=>nil} + foo = Puppet::Resource::Type.new(:hostclass, 'foo') + @compiler.topscope.stubs(:find_hostclass).with('foo').returns(foo) + foo.expects(:ensure_in_catalog).with(@compiler.topscope, {}) + @compiler.compile + end it "should skip classes previously evaluated with different capitalization" do @compiler.catalog.stubs(:tag) @scope.stubs(:find_hostclass).with("MyClass").returns(@class) -- cgit From 3cfbd0722c5f64a3ef39a65f53fa4195135e90b4 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Fri, 21 Jan 2011 14:07:32 -0800 Subject: (#5045) Cleaning up some tests and code Renamed some variables to be clearer, made tests use less stubbing, added some additional tests and got rid of some unecessary logic. Paired-with: Dan Bode --- lib/puppet/parser/compiler.rb | 2 +- lib/puppet/resource/type.rb | 12 +++--- spec/unit/parser/compiler_spec.rb | 84 ++++++++++++++++++++++++++------------- spec/unit/resource/type_spec.rb | 11 +++-- 4 files changed, 69 insertions(+), 40 deletions(-) diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index 3134e03d9..fdabd05c9 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -153,7 +153,7 @@ class Puppet::Parser::Compiler if param_classes resource = klass.ensure_in_catalog(scope, param_classes[name] || {}) else - found << name and next if scope.class_scope(klass) and !param_classes + found << name and next if scope.class_scope(klass) resource = klass.ensure_in_catalog(scope) end diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index a31795a1b..92e1ef719 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -143,23 +143,23 @@ class Puppet::Resource::Type # classes and nodes. No parameters are be supplied--if this is a # parameterized class, then all parameters take on their default # values. - def ensure_in_catalog(scope, attributes=nil) + def ensure_in_catalog(scope, parameters=nil) type == :definition and raise ArgumentError, "Cannot create resources for defined resource types" resource_type = type == :hostclass ? :class : :node # Do nothing if the resource already exists; this makes sure we don't # get multiple copies of the class resource, which helps provide the # singleton nature of classes. - # we should not do this for classes with attributes - # if attributes are passed, we should still try to create the resource + # we should not do this for classes with parameters + # if parameters are passed, we should still try to create the resource # even if it exists so that we can fail # this prevents us from being able to combine param classes with include - if resource = scope.catalog.resource(resource_type, name) and !attributes + if resource = scope.catalog.resource(resource_type, name) and !parameters return resource end resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self) - if attributes - attributes.each do |k,v| + if parameters + parameters.each do |k,v| resource.set_parameter(k,v) end end diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index c1e7c48c2..687f2ecb9 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -105,8 +105,7 @@ describe Puppet::Parser::Compiler do node.classes = %w{foo bar} compiler = Puppet::Parser::Compiler.new(node) - compiler.classlist.should include("foo") - compiler.classlist.should include("bar") + compiler.classlist.should =~ ['foo', 'bar'] end it "should transform node class hashes into a class list" do @@ -114,8 +113,7 @@ describe Puppet::Parser::Compiler do node.classes = {'foo'=>{'one'=>'1'}, 'bar'=>{'two'=>'2'}} compiler = Puppet::Parser::Compiler.new(node) - compiler.classlist.should include("foo") - compiler.classlist.should include("bar") + compiler.classlist.should =~ ['foo', 'bar'] end it "should add a 'main' stage to the catalog" do @@ -549,7 +547,7 @@ describe Puppet::Parser::Compiler do @compiler.add_collection(coll) - lambda { @compiler.compile }.should raise_error(Puppet::ParseError) + lambda { @compiler.compile }.should raise_error Puppet::ParseError, 'Failed to realize virtual resources something' end it "should fail when there are unevaluated resource collections that refer to multiple specific resources" do @@ -558,7 +556,7 @@ describe Puppet::Parser::Compiler do @compiler.add_collection(coll) - lambda { @compiler.compile }.should raise_error(Puppet::ParseError) + lambda { @compiler.compile }.should raise_error Puppet::ParseError, 'Failed to realize virtual resources one, two' end end @@ -611,28 +609,68 @@ describe Puppet::Parser::Compiler do @compiler.evaluate_classes(%w{myclass}, @scope) end - # test that ensure_in_catalog is called for existing classes - it "should ensure each node class hash is in catalog" do - klasses = {'foo'=>{'1'=>'one'}, 'bar'=>{'2'=>'two'}} + it "should ensure each node class hash is in catalog and have appropriate parameters" do + klasses = {'foo'=>{'1'=>'one'}, 'bar::foo'=>{'2'=>'two'}, 'bar'=>{'1'=> [1,2,3], '2'=>{'foo'=>'bar'}}} @node.classes = klasses + ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') klasses.each do |name, params| - klass = Puppet::Resource::Type.new(:hostclass, name) - @compiler.topscope.stubs(:find_hostclass).with(name).returns(klass) - klass.expects(:ensure_in_catalog).with(@compiler.topscope, params) + klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) + @compiler.topscope.known_resource_types.add klass end - @compiler.compile + catalog = @compiler.compile + catalog.classes.should =~ ['foo', 'bar::foo', 'settings', 'bar'] + + r1 = catalog.resources.detect {|r| r.title == 'Foo' } + r1.to_hash.should == {:'1' => 'one', :'2' => 'foo'} + r1.tags. should =~ ['class', 'foo'] + + r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } + r2.to_hash.should == {:'1' => 'foo', :'2' => 'two'} + r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] + + r2 = catalog.resources.detect {|r| r.title == 'Bar' } + r2.to_hash.should == {:'1' => [1,2,3], :'2' => {'foo'=>'bar'}} + r2.tags.should =~ ['class', 'bar'] + end + + it "should ensure each node class is in catalog and has appropriate tags" do + klasses = ['bar::foo'] + @node.classes = klasses + ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') + klasses.each do |name| + klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) + @compiler.topscope.known_resource_types.add klass + end + catalog = @compiler.compile + + r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } + r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] + end + + it "should fail if required parameters are missing" do + klass = {'foo'=>{'1'=>'one'}} + @node.classes = klass + klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) + @compiler.topscope.known_resource_types.add klass + lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Must pass 2 to Class[Foo]" + end + + it "should fail if invalid parameters are passed" do + klass = {'foo'=>{'3'=>'one'}} + @node.classes = klass + klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) + @compiler.topscope.known_resource_types.add klass + lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Invalid parameter 3" end it "should ensure class is in catalog without params" do @node.classes = klasses = {'foo'=>nil} foo = Puppet::Resource::Type.new(:hostclass, 'foo') - @compiler.topscope.stubs(:find_hostclass).with('foo').returns(foo) - foo.expects(:ensure_in_catalog).with(@compiler.topscope, {}) - @compiler.compile + @compiler.topscope.known_resource_types.add foo + catalog = @compiler.compile + catalog.classes.should include 'foo' end - - it "should not evaluate the resources created for found classes unless asked" do @compiler.catalog.stubs(:tag) @@ -667,14 +705,6 @@ describe Puppet::Parser::Compiler do @compiler.evaluate_classes(%w{myclass}, @scope, false) end - it "should not skip param classes that have already been evaluated" do - @scope.stubs(:class_scope).with(@class).returns("something") - @node.classes = klasses = {'foo'=>nil} - foo = Puppet::Resource::Type.new(:hostclass, 'foo') - @compiler.topscope.stubs(:find_hostclass).with('foo').returns(foo) - foo.expects(:ensure_in_catalog).with(@compiler.topscope, {}) - @compiler.compile - end it "should skip classes previously evaluated with different capitalization" do @compiler.catalog.stubs(:tag) @scope.stubs(:find_hostclass).with("MyClass").returns(@class) @@ -814,7 +844,7 @@ describe Puppet::Parser::Compiler do it "should fail if the compile is finished and resource overrides have not been applied" do @compiler.add_override(@override) - lambda { @compiler.compile }.should raise_error(Puppet::ParseError) + lambda { @compiler.compile }.should raise_error Puppet::ParseError, 'Could not find resource(s) File[/foo] for overriding' end end end diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index 11288f100..206616ef4 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -496,7 +496,7 @@ describe Puppet::Resource::Type do it "should evaluate the parent's resource" do @type.parent_type(@scope) - + @type.evaluate_code(@resource) @scope.class_scope(@parent_type).should_not be_nil @@ -504,7 +504,7 @@ describe Puppet::Resource::Type do it "should not evaluate the parent's resource if it has already been evaluated" do @parent_resource.evaluate - + @type.parent_type(@scope) @parent_resource.expects(:evaluate).never @@ -545,7 +545,7 @@ describe Puppet::Resource::Type do it "should not evaluate the parent's resource if it has already been evaluated" do @parent_resource.evaluate - + @type.parent_type(@scope) @parent_resource.expects(:evaluate).never @@ -575,7 +575,7 @@ describe Puppet::Resource::Type do @code = Puppet::Resource::TypeCollection.new("env") @code.add @top @code.add @middle - + @node.environment.stubs(:known_resource_types).returns(@code) end @@ -601,7 +601,7 @@ describe Puppet::Resource::Type do @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end - it "should add specified attributes to the resource" do + it "should add specified parameters to the resource" do @top.ensure_in_catalog(@scope, {'one'=>'1', 'two'=>'2'}) @compiler.catalog.resource(:class, "top")['one'].should == '1' @compiler.catalog.resource(:class, "top")['two'].should == '2' @@ -628,7 +628,6 @@ describe Puppet::Resource::Type do othertop = Puppet::Parser::Resource.new(:class, 'top',:source => @source, :scope => @scope ) # add the same class resource to the catalog @compiler.catalog.add_resource(othertop) - @compiler.catalog.expects(:resource).with(:class, 'top').returns true lambda { @top.ensure_in_catalog(@scope, {}) }.should raise_error(Puppet::Resource::Catalog::DuplicateResourceError) end -- cgit From 0084b082df016ad87752ef570cfe50bce0f6048e Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Mon, 24 Jan 2011 13:47:53 -0800 Subject: (#5548) Specify return values of manual status commands in service type description. Reviewed by Matt Robinson. --- lib/puppet/type/service.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index c00f02789..2801f3a78 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -144,10 +144,16 @@ module Puppet specified." end newparam(:status) do - desc "Specify a *status* command manually. If left - unspecified, the status method will be determined - automatically, usually by looking for the service in the - process table." + desc "Specify a *status* command manually. This command must + return 0 if the service is running and a nonzero value otherwise. + Ideally, these return codes should conform to + [the LSB's specification for init script status actions](http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html), + but puppet only considers the difference between 0 and nonzero + to be relevant. + + If left unspecified, the status method will be determined + automatically, usually by looking for the service in the process + table." end newparam(:stop) do -- cgit From 0765afbd2459a60f5ded89a4c34a3bcb3c560399 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 25 Jan 2011 14:03:14 -0800 Subject: Maint: Rename misleading insync? method in file provider This method actually checks whether the file owner is in sync. Renamed to is_owner_insync? Paired-with: Jesse Wolfe --- lib/puppet/provider/file/posix.rb | 2 +- lib/puppet/provider/file/win32.rb | 2 +- lib/puppet/type/file/owner.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/puppet/provider/file/posix.rb b/lib/puppet/provider/file/posix.rb index 6cbf98e9a..415a5af40 100644 --- a/lib/puppet/provider/file/posix.rb +++ b/lib/puppet/provider/file/posix.rb @@ -27,7 +27,7 @@ Puppet::Type.type(:file).provide :posix do end end - def insync?(current, should) + def is_owner_insync?(current, should) return true unless should should.each do |value| diff --git a/lib/puppet/provider/file/win32.rb b/lib/puppet/provider/file/win32.rb index 8ead69a89..23aa491dc 100644 --- a/lib/puppet/provider/file/win32.rb +++ b/lib/puppet/provider/file/win32.rb @@ -14,7 +14,7 @@ Puppet::Type.type(:file).provide :microsoft_windows do id end - def insync?(current, should) + def is_owner_insync?(current, should) return true unless should should.each do |value| diff --git a/lib/puppet/type/file/owner.rb b/lib/puppet/type/file/owner.rb index d473da20e..483cc7fce 100755 --- a/lib/puppet/type/file/owner.rb +++ b/lib/puppet/type/file/owner.rb @@ -6,7 +6,7 @@ module Puppet @event = :file_changed def insync?(current) - provider.insync?(current, @should) + provider.is_owner_insync?(current, @should) end # We want to print names, not numbers -- cgit From 0f9d23617e4115166d6b9e004332dcdf5eccc924 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 25 Jan 2011 14:05:47 -0800 Subject: Maint: Removed dead code from resource harness. Paired-with: Jesse Wolfe --- lib/puppet/transaction/resource_harness.rb | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/lib/puppet/transaction/resource_harness.rb b/lib/puppet/transaction/resource_harness.rb index c1b980632..0abab10a5 100644 --- a/lib/puppet/transaction/resource_harness.rb +++ b/lib/puppet/transaction/resource_harness.rb @@ -175,22 +175,4 @@ class Puppet::Transaction::ResourceHarness return nil unless name = resource[:schedule] resource.catalog.resource(:schedule, name) || resource.fail("Could not find schedule #{name}") end - - private - - def absent_and_not_being_created?(current, param) - current[:ensure] == :absent and param.should.nil? - end - - def ensure_is_insync?(current, param) - param.insync?(current[:ensure]) - end - - def ensure_should_be_absent?(current, param) - param.should == :absent - end - - def param_is_insync?(current, param) - param.insync?(current[param.name]) - end end -- cgit From 67e1bba154accd900b9690d96cec8b050f8082e7 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 25 Jan 2011 14:34:28 -0800 Subject: (#5931) Prevent errors when calling insync? on audited properties Created a method safe_insync? which first checks whether the property has a "should" value of nil, and if so returns true. Most insync? methods were already doing this, but a few were not, leading to bugs if a property was being audited but not set. Types should continue to override the insync? method, but callers of insync? should call safe_insync? instead. Paired-with: Jesse Wolfe --- lib/puppet/property.rb | 17 ++++++++++++++++- lib/puppet/property/keyvalue.rb | 2 -- lib/puppet/property/list.rb | 2 -- lib/puppet/provider/file/posix.rb | 2 -- lib/puppet/provider/file/win32.rb | 2 -- lib/puppet/provider/zone/solaris.rb | 2 +- lib/puppet/transaction/resource_harness.rb | 4 ++-- lib/puppet/type.rb | 4 ++-- lib/puppet/type/cron.rb | 6 +----- lib/puppet/type/file.rb | 2 +- lib/puppet/type/file/content.rb | 1 - lib/puppet/type/file/target.rb | 2 +- lib/puppet/type/mount.rb | 2 +- lib/puppet/type/package.rb | 2 -- lib/puppet/type/service.rb | 2 +- lib/puppet/type/user.rb | 2 -- lib/puppet/type/yumrepo.rb | 4 ++-- lib/puppet/type/zpool.rb | 4 ---- spec/unit/property/keyvalue_spec.rb | 10 +++++----- spec/unit/property/list_spec.rb | 14 +++++++------- spec/unit/type/file/content_spec.rb | 24 ++++++++++++++---------- spec/unit/type/file/ensure_spec.rb | 15 ++++++++------- spec/unit/type/file/group_spec.rb | 10 +++++----- spec/unit/type/file/owner_spec.rb | 14 +++++++------- spec/unit/type/file/selinux_spec.rb | 4 ++-- spec/unit/type/file_spec.rb | 14 ++++++++++++++ spec/unit/type/mount_spec.rb | 8 ++++---- spec/unit/type/ssh_authorized_key_spec.rb | 2 +- spec/unit/type/user_spec.rb | 6 +++--- spec/unit/type/zpool_spec.rb | 24 ++++++++++++------------ 30 files changed, 110 insertions(+), 97 deletions(-) diff --git a/lib/puppet/property.rb b/lib/puppet/property.rb index 84e1a0360..12f496a6e 100644 --- a/lib/puppet/property.rb +++ b/lib/puppet/property.rb @@ -152,9 +152,24 @@ class Puppet::Property < Puppet::Parameter # since we cannot fix it. Otherwise, we expect our should value # to be an array, and if @is matches any of those values, then # we consider it to be in-sync. - def insync?(is) + # + # Don't override this method. + def safe_insync?(is) + # If there is no @should value, consider the property to be in sync. return true unless @should + # Otherwise delegate to the (possibly derived) insync? method. + insync?(is) + end + + def self.method_added(sym) + raise "Puppet::Property#safe_insync? shouldn't be overridden; please override insync? instead" if sym == :safe_insync? + end + + # This method should be overridden by derived classes if necessary + # to provide extra logic to determine whether the property is in + # sync. + def insync?(is) self.devfail "#{self.class.name}'s should is not array" unless @should.is_a?(Array) # an empty array is analogous to no should values diff --git a/lib/puppet/property/keyvalue.rb b/lib/puppet/property/keyvalue.rb index 0181708f9..57d0ea2d9 100644 --- a/lib/puppet/property/keyvalue.rb +++ b/lib/puppet/property/keyvalue.rb @@ -77,8 +77,6 @@ module Puppet end def insync?(is) - return true unless @should - return true unless is (is == self.should) diff --git a/lib/puppet/property/list.rb b/lib/puppet/property/list.rb index dcee85db7..b86dc87f2 100644 --- a/lib/puppet/property/list.rb +++ b/lib/puppet/property/list.rb @@ -66,8 +66,6 @@ module Puppet end def insync?(is) - return true unless @should - return true unless is (prepare_is_for_comparison(is) == self.should) diff --git a/lib/puppet/provider/file/posix.rb b/lib/puppet/provider/file/posix.rb index 415a5af40..f7b8c9797 100644 --- a/lib/puppet/provider/file/posix.rb +++ b/lib/puppet/provider/file/posix.rb @@ -28,8 +28,6 @@ Puppet::Type.type(:file).provide :posix do end def is_owner_insync?(current, should) - return true unless should - should.each do |value| if value =~ /^\d+$/ uid = Integer(value) diff --git a/lib/puppet/provider/file/win32.rb b/lib/puppet/provider/file/win32.rb index 23aa491dc..21e7ca974 100644 --- a/lib/puppet/provider/file/win32.rb +++ b/lib/puppet/provider/file/win32.rb @@ -15,8 +15,6 @@ Puppet::Type.type(:file).provide :microsoft_windows do end def is_owner_insync?(current, should) - return true unless should - should.each do |value| if value =~ /^\d+$/ uid = Integer(value) diff --git a/lib/puppet/provider/zone/solaris.rb b/lib/puppet/provider/zone/solaris.rb index c11444993..f46337b14 100644 --- a/lib/puppet/provider/zone/solaris.rb +++ b/lib/puppet/provider/zone/solaris.rb @@ -40,7 +40,7 @@ Puppet::Type.type(:zone).provide(:solaris) do # Then perform all of our configuration steps. It's annoying # that we need this much internal info on the resource. @resource.send(:properties).each do |property| - str += property.configtext + "\n" if property.is_a? ZoneConfigProperty and ! property.insync?(properties[property.name]) + str += property.configtext + "\n" if property.is_a? ZoneConfigProperty and ! property.safe_insync?(properties[property.name]) end str += "commit\n" diff --git a/lib/puppet/transaction/resource_harness.rb b/lib/puppet/transaction/resource_harness.rb index 0abab10a5..4a3d35e0d 100644 --- a/lib/puppet/transaction/resource_harness.rb +++ b/lib/puppet/transaction/resource_harness.rb @@ -52,13 +52,13 @@ class Puppet::Transaction::ResourceHarness # Update the machine state & create logs/events events = [] ensure_param = resource.parameter(:ensure) - if desired_values[:ensure] && !ensure_param.insync?(current_values[:ensure]) + if desired_values[:ensure] && !ensure_param.safe_insync?(current_values[:ensure]) events << apply_parameter(ensure_param, current_values[:ensure], audited_params.include?(:ensure), historical_values[:ensure]) synced_params << :ensure 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 desired_values[param.name] && !param.insync?(current_values[param.name]) + if desired_values[param.name] && !param.safe_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 diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index ea3944b4e..e03650b54 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -648,7 +648,7 @@ class Type "The is value is not in the is array for '#{property.name}'" end ensureis = is[property] - if property.insync?(ensureis) and property.should == :absent + if property.safe_insync?(ensureis) and property.should == :absent return true end end @@ -660,7 +660,7 @@ class Type end propis = is[property] - unless property.insync?(propis) + unless property.safe_insync?(propis) property.debug("Not in sync: #{propis.inspect} vs #{property.should.inspect}") insync = false #else diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb index 76399d693..4b18e71f9 100755 --- a/lib/puppet/type/cron.rb +++ b/lib/puppet/type/cron.rb @@ -54,11 +54,7 @@ Puppet::Type.newtype(:cron) do # We have to override the parent method, because we consume the entire # "should" array def insync?(is) - if @should - self.is_to_s(is) == self.should_to_s - else - true - end + self.is_to_s(is) == self.should_to_s end # A method used to do parameter input handling. Converts integers diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index eee948cd5..0d69446b4 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -779,7 +779,7 @@ Puppet::Type.newtype(:file) do # Make sure we get a new stat objct expire currentvalue = thing.retrieve - thing.sync unless thing.insync?(currentvalue) + thing.sync unless thing.safe_insync?(currentvalue) end end end diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb index b8f30a9c7..04b917a7e 100755 --- a/lib/puppet/type/file/content.rb +++ b/lib/puppet/type/file/content.rb @@ -96,7 +96,6 @@ module Puppet end return true if ! @resource.replace? - return true unless self.should result = super diff --git a/lib/puppet/type/file/target.rb b/lib/puppet/type/file/target.rb index 9e7229dda..b9fe9213b 100644 --- a/lib/puppet/type/file/target.rb +++ b/lib/puppet/type/file/target.rb @@ -14,7 +14,7 @@ module Puppet # Only call mklink if ensure didn't call us in the first place. currentensure = @resource.property(:ensure).retrieve - mklink if @resource.property(:ensure).insync?(currentensure) + mklink if @resource.property(:ensure).safe_insync?(currentensure) end # Create our link. diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb index d048c90f1..36fb553f5 100755 --- a/lib/puppet/type/mount.rb +++ b/lib/puppet/type/mount.rb @@ -89,7 +89,7 @@ module Puppet if prop.name == :ensure false else - ! prop.insync?(currentvalues[prop]) + ! prop.safe_insync?(currentvalues[prop]) end end.each { |prop| prop.sync }.length @resource.flush if oos > 0 diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb index 51a866332..d73d90dff 100644 --- a/lib/puppet/type/package.rb +++ b/lib/puppet/type/package.rb @@ -109,8 +109,6 @@ module Puppet # Override the parent method, because we've got all kinds of # funky definitions of 'in sync'. def insync?(is) - @should ||= [] - @latest ||= nil @lateststamp ||= (Time.now.to_i - 1000) # Iterate across all of the should values, and see how they diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index c00f02789..973a76c2d 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -73,7 +73,7 @@ module Puppet if property = @resource.property(:enable) val = property.retrieve - property.sync unless property.insync?(val) + property.sync unless property.safe_insync?(val) end event diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index 761d5d71b..5de73e3dd 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -112,8 +112,6 @@ module Puppet end def insync?(is) - return true unless self.should - # We know the 'is' is a number, so we need to convert the 'should' to a number, # too. @should.each do |value| diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb index 160b2164d..9b4c79428 100644 --- a/lib/puppet/type/yumrepo.rb +++ b/lib/puppet/type/yumrepo.rb @@ -7,14 +7,14 @@ module Puppet class IniProperty < Puppet::Property def insync?(is) # A should property of :absent is the same as nil - if is.nil? && (should.nil? || should == :absent) + if is.nil? && should == :absent return true end super(is) end def sync - if insync?(retrieve) + if safe_insync?(retrieve) result = nil else result = set(self.should) diff --git a/lib/puppet/type/zpool.rb b/lib/puppet/type/zpool.rb index 49cce552a..df06522e8 100755 --- a/lib/puppet/type/zpool.rb +++ b/lib/puppet/type/zpool.rb @@ -8,8 +8,6 @@ module Puppet end def insync?(is) - return true unless self.should - return @should == [:absent] if is == :absent flatten_and_sort(is) == flatten_and_sort(@should) @@ -18,8 +16,6 @@ module Puppet class MultiVDev < VDev def insync?(is) - return true unless self.should - return @should == [:absent] if is == :absent return false unless is.length == @should.length diff --git a/spec/unit/property/keyvalue_spec.rb b/spec/unit/property/keyvalue_spec.rb index 7666def56..a44d891d7 100644 --- a/spec/unit/property/keyvalue_spec.rb +++ b/spec/unit/property/keyvalue_spec.rb @@ -134,7 +134,7 @@ describe klass do end end - describe "when calling insync?" do + describe "when calling safe_insync?" do before do @provider = mock("provider") @property.stubs(:provider).returns(@provider) @@ -142,26 +142,26 @@ describe klass do end it "should return true unless @should is defined and not nil" do - @property.insync?("foo") == true + @property.safe_insync?("foo") == true end it "should return true if the passed in values is nil" do @property.should = "foo" - @property.insync?(nil) == true + @property.safe_insync?(nil) == true end it "should return true if hashified should value == (retrieved) value passed in" do @provider.stubs(:prop_name).returns({ :foo => "baz", :bar => "boo" }) @property.should = ["foo=baz", "bar=boo"] @property.expects(:inclusive?).returns(true) - @property.insync?({ :foo => "baz", :bar => "boo" }).must == true + @property.safe_insync?({ :foo => "baz", :bar => "boo" }).must == true end it "should return false if prepared value != should value" do @provider.stubs(:prop_name).returns({ "foo" => "bee", "bar" => "boo" }) @property.should = ["foo=baz", "bar=boo"] @property.expects(:inclusive?).returns(true) - @property.insync?({ "foo" => "bee", "bar" => "boo" }).must == false + @property.safe_insync?({ "foo" => "bee", "bar" => "boo" }).must == false end end end diff --git a/spec/unit/property/list_spec.rb b/spec/unit/property/list_spec.rb index 3e8cc5402..c6c5db10e 100644 --- a/spec/unit/property/list_spec.rb +++ b/spec/unit/property/list_spec.rb @@ -118,39 +118,39 @@ describe list_class do end end - describe "when calling insync?" do + describe "when calling safe_insync?" do it "should return true unless @should is defined and not nil" do - @property.must be_insync("foo") + @property.must be_safe_insync("foo") end it "should return true unless the passed in values is not nil" do @property.should = "foo" - @property.must be_insync(nil) + @property.must be_safe_insync(nil) end it "should call prepare_is_for_comparison with value passed in and should" do @property.should = "foo" @property.expects(:prepare_is_for_comparison).with("bar") @property.expects(:should) - @property.insync?("bar") + @property.safe_insync?("bar") end it "should return true if 'is' value is array of comma delimited should values" do @property.should = "bar,foo" @property.expects(:inclusive?).returns(true) - @property.must be_insync(["bar","foo"]) + @property.must be_safe_insync(["bar","foo"]) end it "should return true if 'is' value is :absent and should value is empty string" do @property.should = "" @property.expects(:inclusive?).returns(true) - @property.must be_insync([]) + @property.must be_safe_insync([]) end it "should return false if prepared value != should value" do @property.should = "bar,baz,foo" @property.expects(:inclusive?).returns(true) - @property.must_not be_insync(["bar","foo"]) + @property.must_not be_safe_insync(["bar","foo"]) end end diff --git a/spec/unit/type/file/content_spec.rb b/spec/unit/type/file/content_spec.rb index cde643fc8..3ec57f00e 100755 --- a/spec/unit/type/file/content_spec.rb +++ b/spec/unit/type/file/content_spec.rb @@ -141,17 +141,20 @@ describe content do it "should return true if the resource shouldn't be a regular file" do @resource.expects(:should_be_file?).returns false - @content.must be_insync("whatever") + @content.should = "foo" + @content.must be_safe_insync("whatever") end it "should return false if the current content is :absent" do - @content.should_not be_insync(:absent) + @content.should = "foo" + @content.should_not be_safe_insync(:absent) end it "should return false if the file should be a file but is not present" do @resource.expects(:should_be_file?).returns true + @content.should = "foo" - @content.should_not be_insync(:absent) + @content.should_not be_safe_insync(:absent) end describe "and the file exists" do @@ -161,12 +164,12 @@ describe content do it "should return false if the current contents are different from the desired content" do @content.should = "some content" - @content.should_not be_insync("other content") + @content.should_not be_safe_insync("other content") end it "should return true if the sum for the current contents is the same as the sum for the desired content" do @content.should = "some content" - @content.must be_insync("{md5}" + Digest::MD5.hexdigest("some content")) + @content.must be_safe_insync("{md5}" + Digest::MD5.hexdigest("some content")) end describe "and Puppet[:show_diff] is set" do @@ -179,14 +182,14 @@ describe content do @content.expects(:diff).returns("my diff").once @content.expects(:print).with("my diff").once - @content.insync?("other content") + @content.safe_insync?("other content") end it "should not display a diff if the sum for the current contents is the same as the sum for the desired content" do @content.should = "some content" @content.expects(:diff).never - @content.insync?("{md5}" + Digest::MD5.hexdigest("some content")) + @content.safe_insync?("{md5}" + Digest::MD5.hexdigest("some content")) end end end @@ -199,17 +202,18 @@ describe content do it "should be insync if the file exists and the content is different" do @resource.stubs(:stat).returns mock('stat') - @content.must be_insync("whatever") + @content.must be_safe_insync("whatever") end it "should be insync if the file exists and the content is right" do @resource.stubs(:stat).returns mock('stat') - @content.must be_insync("something") + @content.must be_safe_insync("something") end it "should not be insync if the file does not exist" do - @content.should_not be_insync(:absent) + @content.should = "foo" + @content.should_not be_safe_insync(:absent) end end end diff --git a/spec/unit/type/file/ensure_spec.rb b/spec/unit/type/file/ensure_spec.rb index ec53ed85a..dbb3a1053 100755 --- a/spec/unit/type/file/ensure_spec.rb +++ b/spec/unit/type/file/ensure_spec.rb @@ -41,44 +41,45 @@ describe property do end it "should always be in sync if replace is 'false' unless the file is missing" do + @ensure.should = :file @resource.expects(:replace?).returns false - @ensure.insync?(:link).should be_true + @ensure.safe_insync?(:link).should be_true end it "should be in sync if :ensure is set to :absent and the file does not exist" do @ensure.should = :absent - @ensure.must be_insync(:absent) + @ensure.must be_safe_insync(:absent) end it "should not be in sync if :ensure is set to :absent and the file exists" do @ensure.should = :absent - @ensure.should_not be_insync(:file) + @ensure.should_not be_safe_insync(:file) end it "should be in sync if a normal file exists and :ensure is set to :present" do @ensure.should = :present - @ensure.must be_insync(:file) + @ensure.must be_safe_insync(:file) end it "should be in sync if a directory exists and :ensure is set to :present" do @ensure.should = :present - @ensure.must be_insync(:directory) + @ensure.must be_safe_insync(:directory) end it "should be in sync if a symlink exists and :ensure is set to :present" do @ensure.should = :present - @ensure.must be_insync(:link) + @ensure.must be_safe_insync(:link) end it "should not be in sync if :ensure is set to :file and a directory exists" do @ensure.should = :file - @ensure.should_not be_insync(:directory) + @ensure.should_not be_safe_insync(:directory) end end end diff --git a/spec/unit/type/file/group_spec.rb b/spec/unit/type/file/group_spec.rb index 2283b57fa..956cd57e7 100755 --- a/spec/unit/type/file/group_spec.rb +++ b/spec/unit/type/file/group_spec.rb @@ -56,19 +56,19 @@ describe property do describe "when determining if the file is in sync" do it "should directly compare the group values if the desired group is an integer" do @group.should = [10] - @group.must be_insync(10) + @group.must be_safe_insync(10) end it "should treat numeric strings as integers" do @group.should = ["10"] - @group.must be_insync(10) + @group.must be_safe_insync(10) end it "should convert the group name to an integer if the desired group is a string" do @group.expects(:gid).with("foo").returns 10 @group.should = %w{foo} - @group.must be_insync(10) + @group.must be_safe_insync(10) end it "should not validate that groups exist when a group is specified as an integer" do @@ -80,12 +80,12 @@ describe property do @group.expects(:gid).with("foo").returns nil @group.should = %w{foo} - lambda { @group.insync?(10) }.should raise_error(Puppet::Error) + lambda { @group.safe_insync?(10) }.should raise_error(Puppet::Error) end it "should return false if the groups are not equal" do @group.should = [10] - @group.should_not be_insync(20) + @group.should_not be_safe_insync(20) end end diff --git a/spec/unit/type/file/owner_spec.rb b/spec/unit/type/file/owner_spec.rb index 8e136a187..bcb8e07d6 100755 --- a/spec/unit/type/file/owner_spec.rb +++ b/spec/unit/type/file/owner_spec.rb @@ -68,7 +68,7 @@ describe property do @provider.expects(:warnonce) @owner.should = [10] - @owner.must be_insync(20) + @owner.must be_safe_insync(20) end end @@ -77,24 +77,24 @@ describe property do end it "should be in sync if 'should' is not provided" do - @owner.must be_insync(10) + @owner.must be_safe_insync(10) end it "should directly compare the owner values if the desired owner is an integer" do @owner.should = [10] - @owner.must be_insync(10) + @owner.must be_safe_insync(10) end it "should treat numeric strings as integers" do @owner.should = ["10"] - @owner.must be_insync(10) + @owner.must be_safe_insync(10) end it "should convert the owner name to an integer if the desired owner is a string" do @provider.expects(:uid).with("foo").returns 10 @owner.should = %w{foo} - @owner.must be_insync(10) + @owner.must be_safe_insync(10) end it "should not validate that users exist when a user is specified as an integer" do @@ -106,12 +106,12 @@ describe property do @provider.expects(:uid).with("foo").returns nil @owner.should = %w{foo} - lambda { @owner.insync?(10) }.should raise_error(Puppet::Error) + lambda { @owner.safe_insync?(10) }.should raise_error(Puppet::Error) end it "should return false if the owners are not equal" do @owner.should = [10] - @owner.should_not be_insync(20) + @owner.should_not be_safe_insync(20) end end diff --git a/spec/unit/type/file/selinux_spec.rb b/spec/unit/type/file/selinux_spec.rb index 1ca59e9e7..043471dec 100644 --- a/spec/unit/type/file/selinux_spec.rb +++ b/spec/unit/type/file/selinux_spec.rb @@ -73,10 +73,10 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f @sel.sync end - it "should do nothing for insync? if no SELinux support" do + it "should do nothing for safe_insync? if no SELinux support" do @sel.should = %{newcontext} @sel.expects(:selinux_support?).returns false - @sel.insync?("oldcontext").should == true + @sel.safe_insync?("oldcontext").should == true end end end diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index 22921d85a..51c27c0e6 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -1065,4 +1065,18 @@ describe Puppet::Type.type(:file) do end end + describe "when auditing" do + it "should not fail if creating a new file if group is not set" do + File.exists?(@path).should == false + file = Puppet::Type::File.new(:name => @path, :audit => "all", :content => "content") + catalog = Puppet::Resource::Catalog.new + catalog.add_resource(file) + + Puppet::Util::Storage.stubs(:store) # to prevent the catalog from trying to write state.yaml + transaction = catalog.apply + + transaction.report.resource_statuses["File[#{@path}]"].failed.should == false + File.exists?(@path).should == true + end + end end diff --git a/spec/unit/type/mount_spec.rb b/spec/unit/type/mount_spec.rb index ce82cb516..0d74042e3 100755 --- a/spec/unit/type/mount_spec.rb +++ b/spec/unit/type/mount_spec.rb @@ -184,22 +184,22 @@ describe Puppet::Type.type(:mount)::Ensure do it "should be insync if it is mounted and should be defined" do @ensure.should = :defined - @ensure.insync?(:mounted).should == true + @ensure.safe_insync?(:mounted).should == true end it "should be insync if it is unmounted and should be defined" do @ensure.should = :defined - @ensure.insync?(:unmounted).should == true + @ensure.safe_insync?(:unmounted).should == true end it "should be insync if it is mounted and should be present" do @ensure.should = :present - @ensure.insync?(:mounted).should == true + @ensure.safe_insync?(:mounted).should == true end it "should be insync if it is unmounted and should be present" do @ensure.should = :present - @ensure.insync?(:unmounted).should == true + @ensure.safe_insync?(:unmounted).should == true end end diff --git a/spec/unit/type/ssh_authorized_key_spec.rb b/spec/unit/type/ssh_authorized_key_spec.rb index a0b435f80..666616c03 100755 --- a/spec/unit/type/ssh_authorized_key_spec.rb +++ b/spec/unit/type/ssh_authorized_key_spec.rb @@ -134,7 +134,7 @@ describe ssh_authorized_key do it "should not raise spurious change events" do resource = @class.new(:name => "Test", :user => "root") target = File.expand_path("~root/.ssh/authorized_keys") - resource.property(:target).insync?(target).should == true + resource.property(:target).safe_insync?(target).should == true end end diff --git a/spec/unit/type/user_spec.rb b/spec/unit/type/user_spec.rb index ccea9ee4c..0c3e2ab2d 100755 --- a/spec/unit/type/user_spec.rb +++ b/spec/unit/type/user_spec.rb @@ -201,21 +201,21 @@ describe user do it "should return true if no 'should' values are set" do @gid = user.attrclass(:gid).new(:resource => @resource) - @gid.must be_insync(500) + @gid.must be_safe_insync(500) end it "should return true if any of the specified groups are equal to the current integer" do Puppet::Util.expects(:gid).with("foo").returns 300 Puppet::Util.expects(:gid).with("bar").returns 500 - @gid.must be_insync(500) + @gid.must be_safe_insync(500) end it "should return false if none of the specified groups are equal to the current integer" do Puppet::Util.expects(:gid).with("foo").returns 300 Puppet::Util.expects(:gid).with("bar").returns 500 - @gid.should_not be_insync(700) + @gid.should_not be_safe_insync(700) end end diff --git a/spec/unit/type/zpool_spec.rb b/spec/unit/type/zpool_spec.rb index db12459ab..be8cb12ba 100755 --- a/spec/unit/type/zpool_spec.rb +++ b/spec/unit/type/zpool_spec.rb @@ -38,27 +38,27 @@ describe vdev_property do it "should be insync if the devices are the same" do @property.should = ["dev1 dev2"] - @property.insync?(["dev2 dev1"]).must be_true + @property.safe_insync?(["dev2 dev1"]).must be_true end it "should be out of sync if the devices are not the same" do @property.should = ["dev1 dev3"] - @property.insync?(["dev2 dev1"]).must be_false + @property.safe_insync?(["dev2 dev1"]).must be_false end it "should be insync if the devices are the same and the should values are comma seperated" do @property.should = ["dev1", "dev2"] - @property.insync?(["dev2 dev1"]).must be_true + @property.safe_insync?(["dev2 dev1"]).must be_true end it "should be out of sync if the device is absent and should has a value" do @property.should = ["dev1", "dev2"] - @property.insync?(:absent).must be_false + @property.safe_insync?(:absent).must be_false end it "should be insync if the device is absent and should is absent" do @property.should = [:absent] - @property.insync?(:absent).must be_true + @property.safe_insync?(:absent).must be_true end end @@ -73,38 +73,38 @@ describe multi_vdev_property do it "should be insync if the devices are the same" do @property.should = ["dev1 dev2"] - @property.insync?(["dev2 dev1"]).must be_true + @property.safe_insync?(["dev2 dev1"]).must be_true end it "should be out of sync if the devices are not the same" do @property.should = ["dev1 dev3"] - @property.insync?(["dev2 dev1"]).must be_false + @property.safe_insync?(["dev2 dev1"]).must be_false end it "should be out of sync if the device is absent and should has a value" do @property.should = ["dev1", "dev2"] - @property.insync?(:absent).must be_false + @property.safe_insync?(:absent).must be_false end it "should be insync if the device is absent and should is absent" do @property.should = [:absent] - @property.insync?(:absent).must be_true + @property.safe_insync?(:absent).must be_true end describe "when there are multiple lists of devices" do it "should be in sync if each group has the same devices" do @property.should = ["dev1 dev2", "dev3 dev4"] - @property.insync?(["dev2 dev1", "dev3 dev4"]).must be_true + @property.safe_insync?(["dev2 dev1", "dev3 dev4"]).must be_true end it "should be out of sync if any group has the different devices" do @property.should = ["dev1 devX", "dev3 dev4"] - @property.insync?(["dev2 dev1", "dev3 dev4"]).must be_false + @property.safe_insync?(["dev2 dev1", "dev3 dev4"]).must be_false end it "should be out of sync if devices are in the wrong group" do @property.should = ["dev1 dev2", "dev3 dev4"] - @property.insync?(["dev2 dev3", "dev1 dev4"]).must be_false + @property.safe_insync?(["dev2 dev3", "dev1 dev4"]).must be_false end end end -- cgit From 7d38ab24fa3740ef53510db143f34ac271aced2d Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Wed, 19 Jan 2011 16:59:53 -0800 Subject: (#5594) Update documentation of exec resource type. The exec resource doc referred to duplicate names being allowed, which stopped being true in 0.24.2. Reviewed by Matt Robinson. --- lib/puppet/type/exec.rb | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb index 606888c75..8019af67e 100755 --- a/lib/puppet/type/exec.rb +++ b/lib/puppet/type/exec.rb @@ -9,41 +9,11 @@ module Puppet commands is to use the checks like `creates` to avoid running the command unless some condition is met. - Note also that you can restrict an `exec` to only run when it receives + Note that you can restrict an `exec` to only run when it receives events by using the `refreshonly` parameter; this is a useful way to have your configuration respond to events with arbitrary commands. - It is worth noting that `exec` is special, in that it is not - currently considered an error to have multiple `exec` instances - with the same name. This was done purely because it had to be this - way in order to get certain functionality, but it complicates things. - In particular, you will not be able to use `exec` instances that - share their commands with other instances as a dependency, since - Puppet has no way of knowing which instance you mean. - - For example: - - # defined in the production class - exec { \"make\": - cwd => \"/prod/build/dir\", - path => \"/usr/bin:/usr/sbin:/bin\" - } - - . etc. . - - # defined in the test class - exec { \"make\": - cwd => \"/test/build/dir\", - path => \"/usr/bin:/usr/sbin:/bin\" - } - - Any other type would throw an error, complaining that you had - the same instance being managed in multiple places, but these are - obviously different images, so `exec` had to be treated specially. - - It is recommended to avoid duplicate names whenever possible. - - Note that if an `exec` receives an event from another resource, + Note also that if an `exec` receives an event from another resource, it will get executed again (or execute the command specified in `refresh`, if there is one). There is a strong tendency to use `exec` to do whatever work Puppet -- cgit From 5d108e8007b76ce62f13c99ed1caedcc0f69c37c Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Fri, 21 Jan 2011 17:21:03 -0800 Subject: (#5944) Improve documentation of defined() function The differences in the way defined() handles different types of entities weren't well-explained. Documentation was also added for the behavior of defined(Node["somenode.domain.com"]). --- lib/puppet/parser/functions/defined.rb | 47 +++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb index 90632af2f..c3efc5f76 100644 --- a/lib/puppet/parser/functions/defined.rb +++ b/lib/puppet/parser/functions/defined.rb @@ -1,10 +1,45 @@ # Test whether a given class or definition is defined -Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Determine whether a given - type is defined, either as a native type or a defined type, or whether a class is defined. - This is useful for checking whether a class is defined and only including it if it is. - This function can also test whether a resource has been defined, using resource references - (e.g., `if defined(File['/tmp/myfile']) { ... }`). This function is unfortunately - dependent on the parse order of the configuration when testing whether a resource is defined.") do |vals| +Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Determine whether + a given type, class, resource, or node is defined, and return + true or false. Accepts class names, type names, resource references, and node + references. + + The `defined` function checks both native and defined types, including types + provided as plugins via modules. Types are checked using their names: + + defined(\"file\") + defined(\"customtype\") + + Classes are also checked using their names: + + defined(\"foo\") + defined(\"foo::bar\") + + Unlike classes and types, resource definitions are checked using resource + references, e.g. `defined( File['/tmp/myfile'] )`. Checking whether a given + resource defined is, unfortunately, dependent on the parse order of the + configuration, and the following code will not work: + + if defined(File['/tmp/foo']) { + notify(\"This configuration includes the /tmp/foo file.\") + } + file {\"/tmp/foo\": + ensure => present, + } + + However, this order requirement refers to parse order only, and ordering of + resources in the configuration graph (e.g. with `begin` or `require`) does not + affect the behavior of `defined`. + + You can also use `defined` to check whether a node is defined using syntax + resembling a resource reference, like `Node[\"testnode.domain.com\"]`. This usage + is not necessarily recommended, and is included here only in the spirit of + completeness. Checking for node definitions behaves differently from the other + uses of `defined`: it will only return true if a definition for the specified + node (the name of which must match exactly) exists in the manifest **AND** the + specified node matches the node whose configuration is being compiled (either + directly or through node inheritance). The `define` function cannot be used to + introspect information returned by an external node classifier. ") do |vals| result = false vals = [vals] unless vals.is_a?(Array) vals.each do |val| -- cgit From 2b9f6535d46eecd60d8997e93dd2b7533b9e5e71 Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Tue, 25 Jan 2011 17:09:25 -0800 Subject: (#5944) Further edits of inline defined() documentation. Fixing use of define/declare; editing for clarity. --- lib/puppet/parser/functions/defined.rb | 55 ++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb index c3efc5f76..deb57a616 100644 --- a/lib/puppet/parser/functions/defined.rb +++ b/lib/puppet/parser/functions/defined.rb @@ -1,45 +1,50 @@ # Test whether a given class or definition is defined Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Determine whether - a given type, class, resource, or node is defined, and return - true or false. Accepts class names, type names, resource references, and node - references. - + a given type or class is defined. This function can also determine whether a + specific resource has been declared. Returns true or false. Accepts class names, + type names, resource references, and node references. + The `defined` function checks both native and defined types, including types - provided as plugins via modules. Types are checked using their names: - + provided as plugins via modules. Types and classes are both checked using their names: + defined(\"file\") defined(\"customtype\") - - Classes are also checked using their names: - defined(\"foo\") defined(\"foo::bar\") - - Unlike classes and types, resource definitions are checked using resource - references, e.g. `defined( File['/tmp/myfile'] )`. Checking whether a given - resource defined is, unfortunately, dependent on the parse order of the - configuration, and the following code will not work: - + + Resource declarations are checked using resource references, e.g. + `defined( File['/tmp/myfile'] )`. Checking whether a given resource + has been declared is, unfortunately, dependent on the parse order of + the configuration, and the following code will not work: + if defined(File['/tmp/foo']) { notify(\"This configuration includes the /tmp/foo file.\") } file {\"/tmp/foo\": ensure => present, } - + However, this order requirement refers to parse order only, and ordering of - resources in the configuration graph (e.g. with `begin` or `require`) does not + resources in the configuration graph (e.g. with `before` or `require`) does not affect the behavior of `defined`. - - You can also use `defined` to check whether a node is defined using syntax + + You can also use `defined` to check whether a node is declared using syntax resembling a resource reference, like `Node[\"testnode.domain.com\"]`. This usage is not necessarily recommended, and is included here only in the spirit of - completeness. Checking for node definitions behaves differently from the other - uses of `defined`: it will only return true if a definition for the specified - node (the name of which must match exactly) exists in the manifest **AND** the - specified node matches the node whose configuration is being compiled (either - directly or through node inheritance). The `define` function cannot be used to - introspect information returned by an external node classifier. ") do |vals| + completeness. Note that: + + * Only the node whose configuration is being compiled is considered declared; + the `define` function will not return information about definitions not currently + being used. + * Node definitions inherited by the current node are considered declared; + however, the default node is never considered declared. + * A node is not considered declared simply by virtue of receiving a + configuration; it must have matched a node definition in the manifest. + * The name used in the node reference must match the name used in the node + definition, even if this is not the node's actual certname. + * Regular expression node definitions cannot be checked for declaration using + `define`, nor can `define` be used to introspect information returned by an + external node classifier.") do |vals| result = false vals = [vals] unless vals.is_a?(Array) vals.each do |val| -- cgit From 86a2a0031fdad032003d053244a3baa04c8f2b81 Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Tue, 25 Jan 2011 17:50:17 -0800 Subject: (#5944) Remove documentation of define() when used on nodes, as it is not a supported use of this function. Final patch in this series reviewed by Dan Bode. --- lib/puppet/parser/functions/defined.rb | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb index deb57a616..2aeaa9ba0 100644 --- a/lib/puppet/parser/functions/defined.rb +++ b/lib/puppet/parser/functions/defined.rb @@ -1,8 +1,8 @@ # Test whether a given class or definition is defined Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Determine whether - a given type or class is defined. This function can also determine whether a + a given class or resource type is defined. This function can also determine whether a specific resource has been declared. Returns true or false. Accepts class names, - type names, resource references, and node references. + type names, and resource references. The `defined` function checks both native and defined types, including types provided as plugins via modules. Types and classes are both checked using their names: @@ -26,25 +26,7 @@ Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Dete However, this order requirement refers to parse order only, and ordering of resources in the configuration graph (e.g. with `before` or `require`) does not - affect the behavior of `defined`. - - You can also use `defined` to check whether a node is declared using syntax - resembling a resource reference, like `Node[\"testnode.domain.com\"]`. This usage - is not necessarily recommended, and is included here only in the spirit of - completeness. Note that: - - * Only the node whose configuration is being compiled is considered declared; - the `define` function will not return information about definitions not currently - being used. - * Node definitions inherited by the current node are considered declared; - however, the default node is never considered declared. - * A node is not considered declared simply by virtue of receiving a - configuration; it must have matched a node definition in the manifest. - * The name used in the node reference must match the name used in the node - definition, even if this is not the node's actual certname. - * Regular expression node definitions cannot be checked for declaration using - `define`, nor can `define` be used to introspect information returned by an - external node classifier.") do |vals| + affect the behavior of `defined`.") do |vals| result = false vals = [vals] unless vals.is_a?(Array) vals.each do |val| -- cgit From f1ab58839b5fc2d311b2c2656e480fb563acd03f Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Wed, 26 Jan 2011 08:54:55 +1100 Subject: Fixed #6009 - nested member list vs directory service group provider The Directory Service group (and user) provider behaves erratically if members is a nested list; this happens with the following manifest: $r = ["root"] $a = ["daemon", "crc"] $n = ["nobody"] group { "testgroup": ensure => present, members => [$r, $a, $n] } This resolves the issue by flattening the list at the time we are using it; while a more general solution might be desirable this resolves the specific issue cleanly enough. Original patch from Clay Caviness. Tests by Daniel Pittman Signed-off-by: Daniel Pittman Signed-off-by: James Turnbull --- .../provider/nameservice/directoryservice.rb | 4 +-- .../provider/nameservice/directoryservice_spec.rb | 38 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100755 spec/unit/provider/nameservice/directoryservice_spec.rb diff --git a/lib/puppet/provider/nameservice/directoryservice.rb b/lib/puppet/provider/nameservice/directoryservice.rb index 965a2aa60..b01880360 100644 --- a/lib/puppet/provider/nameservice/directoryservice.rb +++ b/lib/puppet/provider/nameservice/directoryservice.rb @@ -442,7 +442,7 @@ class DirectoryService < Puppet::Provider::NameService def remove_unwanted_members(current_members, new_members) current_members.each do |member| - if not new_members.include?(member) + if not new_members.flatten.include?(member) cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-d", member, @resource[:name]] begin execute(cmd) @@ -454,7 +454,7 @@ class DirectoryService < Puppet::Provider::NameService end def add_members(current_members, new_members) - new_members.each do |new_member| + new_members.flatten.each do |new_member| if current_members.nil? or not current_members.include?(new_member) cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-a", new_member, @resource[:name]] begin diff --git a/spec/unit/provider/nameservice/directoryservice_spec.rb b/spec/unit/provider/nameservice/directoryservice_spec.rb new file mode 100755 index 000000000..661899db9 --- /dev/null +++ b/spec/unit/provider/nameservice/directoryservice_spec.rb @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +# We use this as a reasonable way to obtain all the support infrastructure. +[:user, :group].each do |type_for_this_round| + provider_class = Puppet::Type.type(type_for_this_round).provider(:directoryservice) + + describe provider_class do + before do + @resource = stub("resource") + @provider = provider_class.new(@resource) + end + + it "[#6009] should handle nested arrays of members" do + current = ["foo", "bar", "baz"] + desired = ["foo", ["quux"], "qorp"] + group = 'example' + + @resource.stubs(:[]).with(:name).returns(group) + @resource.stubs(:[]).with(:auth_membership).returns(true) + @provider.instance_variable_set(:@property_value_cache_hash, + { :members => current }) + + %w{bar baz}.each do |del| + @provider.expects(:execute).once. + with([:dseditgroup, '-o', 'edit', '-n', '.', '-d', del, group]) + end + + %w{quux qorp}.each do |add| + @provider.expects(:execute).once. + with([:dseditgroup, '-o', 'edit', '-n', '.', '-a', add, group]) + end + + expect { @provider.set(:members, desired) }.should_not raise_error + end + end +end -- cgit From d8716416746b4a88c05fa9583a08ba9b5b624787 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Wed, 26 Jan 2011 00:13:47 -0800 Subject: Feature #5855 -- undefined method 'withenv' in FreeBSD package provider. The FreeBSD package provider fails to install when any source is given, yielding instead an 'undefined method' error. This adds tests that prove the bug exists. --- spec/unit/provider/package/freebsd_spec.rb | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100755 spec/unit/provider/package/freebsd_spec.rb diff --git a/spec/unit/provider/package/freebsd_spec.rb b/spec/unit/provider/package/freebsd_spec.rb new file mode 100755 index 000000000..0d38a16cf --- /dev/null +++ b/spec/unit/provider/package/freebsd_spec.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider_class = Puppet::Type.type(:package).provider(:freebsd) + +describe provider_class do + before :each do + # Create a mock resource + @resource = stub 'resource' + + # A catch all; no parameters set + @resource.stubs(:[]).returns(nil) + + # But set name and source + @resource.stubs(:[]).with(:name).returns "mypackage" + @resource.stubs(:[]).with(:ensure).returns :installed + + @provider = provider_class.new + @provider.resource = @resource + end + + it "should have an install method" do + @provider = provider_class.new + @provider.should respond_to(:install) + end + + describe "when installing" do + before :each do + @resource.stubs(:should).with(:ensure).returns(:installed) + end + + it "should install a package from a path to a directory" do + # For better or worse, trailing '/' is needed. --daniel 2011-01-26 + path = '/path/to/directory/' + @resource.stubs(:[]).with(:source).returns(path) + Puppet::Util::Execution.expects(:withenv).once.with({:PKG_PATH => path}).yields + @provider.expects(:pkgadd).once.with("mypackage") + + expect { @provider.install }.should_not raise_error + end + + %w{http https ftp}.each do |protocol| + it "should install a package via #{protocol}" do + # For better or worse, trailing '/' is needed. --daniel 2011-01-26 + path = "#{protocol}://localhost/" + @resource.stubs(:[]).with(:source).returns(path) + Puppet::Util::Execution.expects(:withenv).once.with({:PACKAGESITE => path}).yields + @provider.expects(:pkgadd).once.with('-r', "mypackage") + + expect { @provider.install }.should_not raise_error + end + end + end +end -- cgit From af1c1febd6ae4accf840279539855592705878bf Mon Sep 17 00:00:00 2001 From: fredrik-eriksson Date: Tue, 25 Jan 2011 09:27:54 +0100 Subject: Feature #5855 -- fix withenv call in freebsd package provider Qualify 'withenv' in the provider, since it is part of an entirely different part of puppet, not a method on this provider. This closes #5855. Signed-off-by: fredrik-eriksson Signed-off-by: Daniel Pittman --- lib/puppet/provider/package/freebsd.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/puppet/provider/package/freebsd.rb b/lib/puppet/provider/package/freebsd.rb index 2f012a4ed..e10a20b04 100755 --- a/lib/puppet/provider/package/freebsd.rb +++ b/lib/puppet/provider/package/freebsd.rb @@ -20,11 +20,11 @@ Puppet::Type.type(:package).provide :freebsd, :parent => :openbsd do if @resource[:source] =~ /\/$/ if @resource[:source] =~ /^(ftp|https?):/ - withenv :PACKAGESITE => @resource[:source] do + Puppet::Util::Execution::withenv :PACKAGESITE => @resource[:source] do pkgadd "-r", @resource[:name] end else - withenv :PKG_PATH => @resource[:source] do + Puppet::Util::Execution::withenv :PKG_PATH => @resource[:source] do pkgadd @resource[:name] end end -- cgit From bf44e72b19187dbb4bc696ba8e1b3bc872c32d46 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Fri, 28 Jan 2011 14:52:04 -0800 Subject: Bug #6061 -- verify that negative {min,max}_password_age are accepted. Setting the age value to -1 will disable the specific aging value; we should accept that, but continue to reject null or empty values as invalid. Add tests to verify that this code enforces as expected. --- spec/unit/type/user_spec.rb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spec/unit/type/user_spec.rb b/spec/unit/type/user_spec.rb index 0c3e2ab2d..297134446 100755 --- a/spec/unit/type/user_spec.rb +++ b/spec/unit/type/user_spec.rb @@ -245,6 +245,34 @@ describe user do end end + describe "when managing minimum password age" do + before do + @age = user.attrclass(:password_min_age).new(:resource => @resource) + end + + it "should accept a negative minimum age" do + expect { @age.should = -1 }.should_not raise_error + end + + it "should fail with an empty minimum age" do + expect { @age.should = '' }.should raise_error(Puppet::Error) + end + end + + describe "when managing maximum password age" do + before do + @age = user.attrclass(:password_max_age).new(:resource => @resource) + end + + it "should accept a negative maximum age" do + expect { @age.should = -1 }.should_not raise_error + end + + it "should fail with an empty maximum age" do + expect { @age.should = '' }.should raise_error(Puppet::Error) + end + end + describe "when managing passwords" do before do @password = user.attrclass(:password).new(:resource => @resource, :should => "mypass") -- cgit From c50a48edb19e80d48019b19d852665411d6222e7 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Sat, 29 Jan 2011 04:03:21 +1100 Subject: Fixed #6061 - Allowed -1 as password min/max age This allows setting disabling password aging on Linux and Solaris Signed-off-by: James Turnbull --- lib/puppet/type/user.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index 5de73e3dd..e7389a0d1 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -175,7 +175,7 @@ module Puppet end validate do |value| - if value.to_s !~ /^\d+$/ + if value.to_s !~ /^-?\d+$/ raise ArgumentError, "Password minimum age must be provided as a number" end end @@ -194,7 +194,7 @@ module Puppet end validate do |value| - if value.to_s !~ /^\d+$/ + if value.to_s !~ /^-?\d+$/ raise ArgumentError, "Password maximum age must be provided as a number" end end -- cgit From eb97aa5f7cbf3800a22849f29fad555b0ca042d9 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Mon, 31 Jan 2011 10:50:00 -0800 Subject: Bug #6091 -- test leading double-slash in filenames are allowed. They presently are not; this ensures that we verify that before merging a change that fixes bugs in the area. --- spec/unit/type/file_spec.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index 51c27c0e6..db0fa9f34 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -194,6 +194,23 @@ describe Puppet::Type.type(:file) do file = Puppet::Type::File.new(:path => "/") file[:path].should == "/" end + + it "should accept a double-slash at the start of the path" do + expect { + file = Puppet::Type::File.new(:path => "//tmp/xxx") + # REVISIT: This should be wrong, later. See the next test. + # --daniel 2011-01-31 + file[:path].should == '/tmp/xxx' + }.should_not raise_error + end + + # REVISIT: This is pending, because I don't want to try and audit the + # entire codebase to make sure we get this right. POSIX treats two (and + # exactly two) '/' characters at the start of the path specially. + # + # See sections 3.2 and 4.11, which allow DomainOS to be all special like + # and still have the POSIX branding and all. --daniel 2011-01-31 + it "should preserve the double-slash at the start of the path" end describe "on Microsoft Windows systems" do -- cgit From 878f266fbf8979bcfeab9faef308816fd4a54c50 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Tue, 1 Feb 2011 04:55:26 +1100 Subject: Fixed #6091 - Changed POSIX path matching to allow multiple leading slashes According to http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266: "Multiple successive slashes are considered to be the same as one slash.", so '//tmp/xxx' is a valid POSIX pathname. Thomas Bellman adds: You should probably read section 3.2 then as well: 3.2 Absolute Pathname A pathname beginning with a single or more than two slashes; see also Pathname. Note that a pathname starting with exactly two slashes is *not* an absolute pathname according to Posix. And 4.11 (Pathname Resolution) says: A pathname that begins with two successive slashes may be interpreted in an implementation-defined manner, although more than two leading slashes shall be treated as a single slash. Posix has this rule to accomodate DomainOS, which was a Unix- like OS from Apollo, where paths on the form "//foo/bar/gazonk" meant the file "/bar/gazonk" on the machine named "foo". You may recognize this format from URLs, or MS Windows SMB paths (with backslashes instead of forward slashes). This ignores that complication, since none of our supported platforms treat the '//' form as significant. Signed-off-by: James Turnbull Signed-off-by: Daniel Pittman Signed-off-by: Rick Bradley --- lib/puppet/type/file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 0d69446b4..a91e7a504 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -34,7 +34,7 @@ Puppet::Type.newtype(:file) do validate do |value| # accept various path syntaxes: lone slash, posix, win32, unc - unless (Puppet.features.posix? and (value =~ /^\/$/ or value =~ /^\/[^\/]/)) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/)) + unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/)) fail Puppet::Error, "File paths must be fully qualified, not '#{value}'" end end -- cgit From 2f74d83f22e05564a136c08dd0cc73dcd700f214 Mon Sep 17 00:00:00 2001 From: Rick Bradley Date: Mon, 31 Jan 2011 13:53:27 -0800 Subject: Spec for #5681 to allow parsing of AIX mount output in mount provider This also adds a fixture file containing the AIX mount output as submitted by the ticket author. --- spec/fixtures/unit/provider/mount/mount-output.aix.txt | 7 +++++++ spec/unit/provider/mount_spec.rb | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 spec/fixtures/unit/provider/mount/mount-output.aix.txt diff --git a/spec/fixtures/unit/provider/mount/mount-output.aix.txt b/spec/fixtures/unit/provider/mount/mount-output.aix.txt new file mode 100644 index 000000000..54edb9c1c --- /dev/null +++ b/spec/fixtures/unit/provider/mount/mount-output.aix.txt @@ -0,0 +1,7 @@ +/dev/hd4 / jfs2 Nov 11 12:11 rw,log=/dev/hd8 +/dev/hd2 /usr jfs2 Nov 11 12:11 rw,log=/dev/hd8 +/dev/hd9var /var jfs2 Nov 11 12:11 rw,log=/dev/hd8 +/dev/hd3 /tmp jfs2 Nov 11 12:11 rw,log=/dev/hd8 +/dev/hd1 /home jfs2 Nov 11 12:11 rw,log=/dev/hd8 +/proc /proc procfs Nov 11 12:11 rw +/dev/hd10opt /opt jfs2 Nov 11 12:11 rw,log=/dev/hd8 diff --git a/spec/unit/provider/mount_spec.rb b/spec/unit/provider/mount_spec.rb index b034214ee..f567a4a40 100755 --- a/spec/unit/provider/mount_spec.rb +++ b/spec/unit/provider/mount_spec.rb @@ -120,6 +120,14 @@ describe Puppet::Provider::Mount do @mounter.should be_mounted end + it "should match mounted devices if the operating system is AIX" do + Facter.stubs(:value).with("operatingsystem").returns("AIX") + mount_data = File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'unit', 'provider', 'mount', 'mount-output.aix.txt')) + @mounter.expects(:mountcmd).returns(mount_data) + + @mounter.should be_mounted + end + it "should match ' on ' if the operating system is not Darwin, Solaris, or HP-UX" do Facter.stubs(:value).with("operatingsystem").returns("Debian") @mounter.expects(:mountcmd).returns("/dev/dsk/whatever on / and stuff\n/dev/other/disk on /var and stuff") -- cgit From 139760bfa7d79464d5ee092ff4e952138a29b760 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Mon, 31 Jan 2011 14:00:33 -0800 Subject: Bug #5681 -- parse AIX mount command output. - Modified the Puppet::Provider::Mount (lib/puppet/provider/mount.rb) to parse AIX mount command output - Modified lib/puppet/type/mount.rb to set remount to false by default in AIX and fix small typo --- lib/puppet/provider/mount.rb | 2 ++ lib/puppet/type/mount.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/puppet/provider/mount.rb b/lib/puppet/provider/mount.rb index 8c7b24bd4..6a7c72cdc 100644 --- a/lib/puppet/provider/mount.rb +++ b/lib/puppet/provider/mount.rb @@ -43,6 +43,8 @@ module Puppet::Provider::Mount line =~ / on #{name} / or line =~ %r{ on /private/var/automount#{name}} when "Solaris", "HP-UX" line =~ /^#{name} on / + when "AIX" + line =~ /^[^\s]*\s+[^\s]+\s+#{name}\s/ else line =~ / on #{name} / end diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb index 36fb553f5..da9a70bdf 100755 --- a/lib/puppet/type/mount.rb +++ b/lib/puppet/type/mount.rb @@ -200,7 +200,7 @@ module Puppet newvalues(:true, :false) defaultto do case Facter.value(:operatingsystem) - when "FreeBSD", "Darwin" + when "FreeBSD", "Darwin", "AIX" false else true -- cgit From 50c12e55b6f8462f6904ae061e661d1d10c7590a Mon Sep 17 00:00:00 2001 From: Rick Bradley Date: Mon, 31 Jan 2011 14:03:16 -0800 Subject: bug #5681 -- code fix to handle AIX mount output Making a simplified fix to find mount name in AIX mount command output. --- lib/puppet/provider/mount.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/provider/mount.rb b/lib/puppet/provider/mount.rb index 6a7c72cdc..c979f742f 100644 --- a/lib/puppet/provider/mount.rb +++ b/lib/puppet/provider/mount.rb @@ -44,7 +44,7 @@ module Puppet::Provider::Mount when "Solaris", "HP-UX" line =~ /^#{name} on / when "AIX" - line =~ /^[^\s]*\s+[^\s]+\s+#{name}\s/ + line.split(/\s+/)[1] == name else line =~ / on #{name} / end -- cgit From 3a125d486ba4555796840a93a01ca5055eb9e157 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Mon, 31 Jan 2011 16:00:37 -0800 Subject: Bug #5755 -- ZAML generates extra newline in some hash backreferences. This data structure generates YAML with an extra newline that violates the syntax rules and all: list = [1] { :a => list, :b => list }.to_yaml This breaks real client use of the YAML catalogs, not to mention our own use of cached catalogs... --- lib/puppet/util/zaml.rb | 7 +++---- spec/unit/util/zaml_spec.rb | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/puppet/util/zaml.rb b/lib/puppet/util/zaml.rb index 9fda5ae3b..6ac956565 100644 --- a/lib/puppet/util/zaml.rb +++ b/lib/puppet/util/zaml.rb @@ -59,13 +59,12 @@ class ZAML @@previously_emitted_object = {} @@next_free_label_number = 0 end - def initialize(obj,indent) - @indent = indent + def initialize(obj) @this_label_number = nil @@previously_emitted_object[obj.object_id] = self end def to_s - @this_label_number ? ('&id%03d%s' % [@this_label_number, @indent]) : '' + @this_label_number ? ('&id%03d ' % @this_label_number) : '' end def reference @this_label_number ||= (@@next_free_label_number += 1) @@ -76,7 +75,7 @@ class ZAML end end def new_label_for(obj) - Label.new(obj,(Hash === obj || Array === obj) ? "#{@indent || "\n"} " : ' ') + Label.new(obj) end def first_time_only(obj) if label = Label.for(obj) diff --git a/spec/unit/util/zaml_spec.rb b/spec/unit/util/zaml_spec.rb index f2bcefe01..59590c571 100755 --- a/spec/unit/util/zaml_spec.rb +++ b/spec/unit/util/zaml_spec.rb @@ -35,5 +35,26 @@ describe "Pure ruby yaml implementation" do lambda { YAML.load(o.to_yaml) }.should_not raise_error end } + + it "should handle references to Array in Hash values correctly" do + list = [1] + data = { "one" => list, "two" => list } + data.to_yaml.should == "--- \n two: &id001 \n - 1\n one: *id001" + expect { YAML.load(data.to_yaml).should == data }.should_not raise_error + end + + it "should handle references to Hash in Hash values correctly" do + hash = { 1 => 1 } + data = { "one" => hash, "two" => hash } + data.to_yaml.should == "--- \n two: &id001 \n 1: 1\n one: *id001" + expect { YAML.load(data.to_yaml).should == data }.should_not raise_error + end + + it "should handle references to Scalar in Hash" do + str = "hello" + data = { "one" => str, "two" => str } + data.to_yaml.should == "--- \n two: &id001 hello\n one: *id001" + expect { YAML.load(data.to_yaml).should == data }.should_not raise_error + end end -- cgit From 6c93eb2c142e346077c49ef78a5fcf675eeb2698 Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 1 Feb 2011 14:37:34 -0800 Subject: Remove order dependency when specifying source and checksum on File type If source was specified after setting the checksum, it would cause the checksum to be set back to :md5. This was completely unnecessary, because the checksum has its own default of :md5. Paired-with: Jesse Wolfe --- lib/puppet/type/file/source.rb | 1 - spec/unit/type/file_spec.rb | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 7d03de2b0..bc464e1c3 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -169,7 +169,6 @@ module Puppet checks.delete(:checksum) resource[:audit] = checks - resource[:checksum] = :md5 unless resource.property(:checksum) end def local? diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index db0fa9f34..944bd6bac 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -1096,4 +1096,19 @@ describe Puppet::Type.type(:file) do File.exists?(@path).should == true end end + + describe "when specifying both source and checksum" do + it 'should use the specified checksum when source is first' do + @file[:source] = '/foo' + @file[:checksum] = :md5lite + + @file[:checksum].should be :md5lite + end + it 'should use the specified checksum when source is last' do + @file[:checksum] = :md5lite + @file[:source] = '/foo' + + @file[:checksum].should be :md5lite + end + end end -- cgit From 3398139f29d26c337476ee36c63d07080c442058 Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 1 Feb 2011 14:40:21 -0800 Subject: Remove invalid "timestamp" and "time", and add missing "ctime" File checksum types. 'timestamp', and 'time' have been invalid since well before 2.6.0, so do not add them to the list of valid checksum types. 'ctime' was missing from the list of valid checksum types, so add it. Paired-with: Jesse Wolfe --- lib/puppet/type/file/checksum.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/type/file/checksum.rb b/lib/puppet/type/file/checksum.rb index 732460738..5586b1383 100755 --- a/lib/puppet/type/file/checksum.rb +++ b/lib/puppet/type/file/checksum.rb @@ -9,7 +9,7 @@ Puppet::Type.type(:file).newparam(:checksum) do The default checksum parameter, if checksums are enabled, is md5." - newvalues "md5", "md5lite", "timestamp", "mtime", "time", "none" + newvalues "md5", "md5lite", "mtime", "ctime", "none" defaultto :md5 -- cgit From d6572921832cc0df22e13d55c3bc090b74155b91 Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 1 Feb 2011 14:55:25 -0800 Subject: Rename variable used in File type validation to be more clear The 'count' variable is used to keep track of how many 'creator' parameters are set on the Type in order to raise an exception if this is greater than one. Be explicit about this. Paired-with: Jesse Wolfe --- lib/puppet/type/file.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index a91e7a504..7c4280bee 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -273,12 +273,12 @@ Puppet::Type.newtype(:file) do CREATORS = [:content, :source, :target] validate do - count = 0 + creator_count = 0 CREATORS.each do |param| - count += 1 if self.should(param) + creator_count += 1 if self.should(param) end - count += 1 if @parameters.include?(:source) - self.fail "You cannot specify more than one of #{CREATORS.collect { |p| p.to_s}.join(", ")}" if count > 1 + creator_count += 1 if @parameters.include?(:source) + self.fail "You cannot specify more than one of #{CREATORS.collect { |p| p.to_s}.join(", ")}" if creator_count > 1 self.fail "You cannot specify a remote recursion without a source" if !self[:source] and self[:recurse] == :remote -- cgit From 76788f80aab15e5ef6487788132b87ecc6ddd9ac Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 1 Feb 2011 14:43:47 -0800 Subject: (#5566) Treat source only File checksums as syntax errors when used with content Certain checksum types (ctime, mtime) only make sense when used with the 'source' File parameter, since there is no way to check them on raw strings. Given the limitations of the current checksumming implementations, it is likely to introduce unexpected behavior when using the 'none' checksum type and either one of the 'source', and 'content' File parameters. Because of this, it is now a syntax error to use a checksum of 'none' with either parameter. Paired-with: Jesse Wolfe --- lib/puppet/type/file.rb | 7 +++++ lib/puppet/util/checksums.rb | 14 ++++++++- spec/unit/type/file_spec.rb | 69 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 7c4280bee..c66a53c5e 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -271,6 +271,7 @@ Puppet::Type.newtype(:file) do end CREATORS = [:content, :source, :target] + SOURCE_ONLY_CHECKSUMS = [:none, :ctime, :mtime] validate do creator_count = 0 @@ -282,6 +283,12 @@ Puppet::Type.newtype(:file) do self.fail "You cannot specify a remote recursion without a source" if !self[:source] and self[:recurse] == :remote + self.fail "You cannot specify source when using checksum 'none'" if self[:checksum] == :none && !self[:source].nil? + + SOURCE_ONLY_CHECKSUMS.each do |checksum_type| + self.fail "You cannot specify content when using checksum '#{checksum_type}'" if self[:checksum] == checksum_type && !self[:content].nil? + end + self.warning "Possible error: recurselimit is set but not recurse, no recursion will happen" if !self[:recurse] and self[:recurselimit] end diff --git a/lib/puppet/util/checksums.rb b/lib/puppet/util/checksums.rb index 6fdf14ecf..e129301e6 100644 --- a/lib/puppet/util/checksums.rb +++ b/lib/puppet/util/checksums.rb @@ -68,7 +68,9 @@ module Puppet::Util::Checksums nil end - alias :ctime_stream :mtime_stream + def mtime(content) + "" + end # Calculate a checksum using Digest::SHA1. def sha1(content) @@ -108,6 +110,12 @@ module Puppet::Util::Checksums File.stat(filename).send(:ctime) end + alias :ctime_stream :mtime_stream + + def ctime(content) + "" + end + # Return a "no checksum" def none_file(filename) "" @@ -119,6 +127,10 @@ module Puppet::Util::Checksums "" end + def none(content) + "" + end + private # Perform an incremental checksum on a file. diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index 944bd6bac..698dff52a 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -823,6 +823,75 @@ describe Puppet::Type.type(:file) do end end + describe "when specifying both source, and content properties" do + before do + @file[:source] = '/one' + @file[:content] = 'file contents' + end + + it "should raise an exception" do + lambda {@file.validate }.should raise_error(/You cannot specify more than one of/) + end + end + + describe "when using source" do + before do + @file[:source] = '/one' + end + Puppet::Type::File::ParameterChecksum.value_collection.values.reject {|v| v == :none}.each do |checksum_type| + describe "with checksum '#{checksum_type}'" do + before do + @file[:checksum] = checksum_type + end + + it 'should validate' do + + lambda { @file.validate }.should_not raise_error + end + end + end + + describe "with checksum 'none'" do + before do + @file[:checksum] = :none + end + + it 'should raise an exception when validating' do + lambda { @file.validate }.should raise_error(/You cannot specify source when using checksum 'none'/) + end + end + end + + describe "when using content" do + SOURCE_ONLY_CHECKSUMS = [:none, :ctime, :mtime] + + before do + @file[:content] = 'file contents' + end + + (Puppet::Type::File::ParameterChecksum.value_collection.values - SOURCE_ONLY_CHECKSUMS).each do |checksum_type| + describe "with checksum '#{checksum_type}'" do + before do + @file[:checksum] = checksum_type + end + + it 'should validate' do + lambda { @file.validate }.should_not raise_error + end + end + end + + SOURCE_ONLY_CHECKSUMS.each do |checksum_type| + describe "with checksum '#{checksum_type}'" do + it 'should raise an exception when validating' do + @file[:checksum] = checksum_type + + lambda { @file.validate }.should raise_error(/You cannot specify content when using checksum '#{checksum_type}'/) + end + end + end + end + describe "when returning resources with :eval_generate" do before do @graph = stub 'graph', :add_edge => nil -- cgit From 530496b00d488da72b1e4e08806ccae27bee012a Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 1 Feb 2011 15:18:00 -0800 Subject: Remove already initialized constant warning from file_spec.rb tests rspec pulls constants from the implementation into the test, so we don't need to redefine it. Reviewed-by: Jesse Wolfe --- spec/unit/type/file_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index 698dff52a..27d6727f3 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -863,8 +863,6 @@ describe Puppet::Type.type(:file) do end describe "when using content" do - SOURCE_ONLY_CHECKSUMS = [:none, :ctime, :mtime] - before do @file[:content] = 'file contents' end -- cgit From fd73874147a1aaa3a047f904a0bc1ae67780a2e4 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Tue, 1 Feb 2011 15:30:28 -0800 Subject: (#6107) Fix an error when auditing a file with empty content The manifest: file { "/tmp/foo" : ensure => present, audit => content, } produced the error: err: /Stage[main]//File[/tmp/foo]/ensure: change from absent to present failed: Could not retrieve content for from filebucket: private method `sub' called for nil:NilClass at /Users/matthewrobinson/work/puppet/test.pp:4 This was due to logic in content assuming that if you didn't specify content while you were auditing it you must have specified a source. The code paths in the file type badly need a cleanup so that these sorts of errors aren't so difficult to track down and things are easier to test. Paired-with: Daniel Pittman --- lib/puppet/type/file/content.rb | 2 ++ spec/unit/type/file/content_spec.rb | 49 +++++++++++++++++++++++++++++++++++++ spec/unit/type/file_spec.rb | 12 +++++++++ 3 files changed, 63 insertions(+) diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb index 04b917a7e..cf924f371 100755 --- a/lib/puppet/type/file/content.rb +++ b/lib/puppet/type/file/content.rb @@ -167,6 +167,8 @@ module Puppet def each_chunk_from(source_or_content) if source_or_content.is_a?(String) yield source_or_content + elsif source_or_content.nil? && resource.parameter(:ensure) && [:present, :file].include?(resource.parameter(:ensure).value) + yield '' elsif source_or_content.nil? yield read_file_from_filebucket elsif self.class.standalone? diff --git a/spec/unit/type/file/content_spec.rb b/spec/unit/type/file/content_spec.rb index 3ec57f00e..9178c94bf 100755 --- a/spec/unit/type/file/content_spec.rb +++ b/spec/unit/type/file/content_spec.rb @@ -461,5 +461,54 @@ describe content do describe "from a filebucket" do end + + # These are testing the implementation rather than the desired behaviour; while that bites, there are a whole + # pile of other methods in the File type that depend on intimate details of this implementation and vice-versa. + # If these blow up, you are gonna have to review the callers to make sure they don't explode! --daniel 2011-02-01 + describe "each_chunk_from should work" do + before do + @content = content.new(:resource => @resource) + end + + it "when content is a string" do + @content.each_chunk_from('i_am_a_string') { |chunk| chunk.should == 'i_am_a_string' } + end + + it "when no content, source, but ensure present" do + @resource[:ensure] = :present + @content.each_chunk_from(nil) { |chunk| chunk.should == '' } + end + + it "when no content, source, but ensure file" do + @resource[:ensure] = :file + @content.each_chunk_from(nil) { |chunk| chunk.should == '' } + end + + it "when no content or source" do + @content.expects(:read_file_from_filebucket).once.returns('im_a_filebucket') + @content.each_chunk_from(nil) { |chunk| chunk.should == 'im_a_filebucket' } + end + + it "when running as puppet apply" do + @content.class.expects(:standalone?).returns true + source_or_content = stubs('source_or_content') + source_or_content.expects(:content).once.returns :whoo + @content.each_chunk_from(source_or_content) { |chunk| chunk.should == :whoo } + end + + it "when running from source with a local file" do + source_or_content = stubs('source_or_content') + source_or_content.expects(:local?).returns true + @content.expects(:chunk_file_from_disk).with(source_or_content).once.yields 'woot' + @content.each_chunk_from(source_or_content) { |chunk| chunk.should == 'woot' } + end + + it "when running from source with a remote file" do + source_or_content = stubs('source_or_content') + source_or_content.expects(:local?).returns false + @content.expects(:chunk_file_from_source).with(source_or_content).once.yields 'woot' + @content.each_chunk_from(source_or_content) { |chunk| chunk.should == 'woot' } + end + end end end diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index db0fa9f34..d5cde5f9b 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -1095,5 +1095,17 @@ describe Puppet::Type.type(:file) do transaction.report.resource_statuses["File[#{@path}]"].failed.should == false File.exists?(@path).should == true end + + it "should not log errors if creating a new file with ensure present and no content" do + File.exists?(@path).should == false + file = Puppet::Type::File.new(:name => @path, :audit => "content", :ensure => "present") + catalog = Puppet::Resource::Catalog.new + catalog.add_resource(file) + + Puppet::Util::Storage.stubs(:store) # to prevent the catalog from trying to write state.yaml + + catalog.apply + @logs.reject {|l| l.level == :notice }.should be_empty + end end end -- cgit From ce5a2bf3ba66d5ce723a6887580b008e8ba4104b Mon Sep 17 00:00:00 2001 From: Dan Bode Date: Sun, 24 Oct 2010 00:49:03 -0500 Subject: (#5061) - allow special hostclass/define variables to be evaluated as defaults. I have always been annoyed that special variables for defines and hostclasses can not be evaluated as param defaults. Special variables are: $name, $title, $module_name. Code example: class x ( foo = $name ) { notice($foo)} should print x, and with my patch, it does. Reviewed-by: Paul Berry --- lib/puppet/resource/type.rb | 26 +++++++++++++------------- spec/unit/resource/type_spec.rb | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index d40adc145..c19a28c35 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -222,6 +222,19 @@ class Puppet::Resource::Type set[param] = true end + if @type == :hostclass + scope.setvar("title", resource.title.to_s.downcase) unless set.include? :title + scope.setvar("name", resource.name.to_s.downcase ) unless set.include? :name + else + scope.setvar("title", resource.title ) unless set.include? :title + scope.setvar("name", resource.name ) unless set.include? :name + end + scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name + + if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name) + scope.setvar("caller_module_name", caller_name) + end + scope.class_set(self.name,scope) if hostclass? or node? # Verify that all required arguments are either present or # have been provided with defaults. arguments.each do |param, default| @@ -238,19 +251,6 @@ class Puppet::Resource::Type resource[param] = value end - if @type == :hostclass - scope.setvar("title", resource.title.to_s.downcase) unless set.include? :title - scope.setvar("name", resource.name.to_s.downcase ) unless set.include? :name - else - scope.setvar("title", resource.title ) unless set.include? :title - scope.setvar("name", resource.name ) unless set.include? :name - end - scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name - - if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name) - scope.setvar("caller_module_name", caller_name) - end - scope.class_set(self.name,scope) if hostclass? or node? end # Create a new subscope in which to evaluate our code. diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index 7b240bb82..dc4d03259 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -261,6 +261,28 @@ describe Puppet::Resource::Type do @type = Puppet::Resource::Type.new(:hostclass, "foo") end + ['module_name', 'name', 'title'].each do |variable| + it "should allow #{variable} to be evaluated as param default" do + @type.module_name = "bar" + var = Puppet::Parser::AST::Variable.new({'value' => variable}) + @type.set_arguments :foo => var + @type.set_resource_parameters(@resource, @scope) + @scope.lookupvar('foo').should == 'bar' + end + end + + # this test is to clarify a crazy edge case + # if you specify these special names as params, the resource + # will override the special variables + it "resource should override defaults" do + @type.set_arguments :name => nil + @resource[:name] = 'foobar' + var = Puppet::Parser::AST::Variable.new({'value' => 'name'}) + @type.set_arguments :foo => var + @type.set_resource_parameters(@resource, @scope) + @scope.lookupvar('foo').should == 'foobar' + end + it "should set each of the resource's parameters as variables in the scope" do @type.set_arguments :foo => nil, :boo => nil @resource[:foo] = "bar" -- cgit From f279f2c24ad1c87940eca3592f4c6e2f5676c694 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Mon, 17 Jan 2011 11:21:02 +1100 Subject: Fixed #4968 - Updated list of options turned on by --test in documentation Reviewed-by: Jacob Helwig Reviewed-by: Jesse Wolfe --- lib/puppet/util/command_line/puppetd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/puppet/util/command_line/puppetd b/lib/puppet/util/command_line/puppetd index cb8589c5f..7d78ce90f 100755 --- a/lib/puppet/util/command_line/puppetd +++ b/lib/puppet/util/command_line/puppetd @@ -150,7 +150,8 @@ # # test:: # Enable the most common options used for testing. These are +onetime+, -# +verbose+, +ignorecache, +no-daemonize+, and +no-usecacheonfailure+. +# +verbose+, +ignorecache, +no-daemonize+, +no-usecacheonfailure+, +# +detailed-exit-codes+, +no-splay+, and +show_diff+. # # noop:: # Use +noop+ mode where the daemon runs in a no-op or dry-run mode. This is useful -- cgit