This patch introduces a new language construct:
Resource <| |> { parameter_override }This construct allows to override resource parameters after the resource is collected by a collector. Note: the override still have to be issued in a child scope of the original resource as with regular override Signed-off-by: Brice Figureau <[email protected]> --- lib/puppet/parser/ast/collection.rb | 31 + lib/puppet/parser/collector.rb | 35 +- lib/puppet/parser/grammar.ra | 22 +- lib/puppet/parser/parser.rb | 1455 +++++++++++++++-------------- spec/unit/parser/ast/collection.rb | 63 ++ spec/unit/parser/collector.rb | 84 ++ test/data/snippets/collection_override.pp | 8 + test/language/snippets.rb | 6 + 8 files changed, 996 insertions(+), 708 deletions(-) create mode 100755 spec/unit/parser/ast/collection.rb create mode 100644 test/data/snippets/collection_override.pp diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index a51b9b4..db978c4 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -7,6 +7,7 @@ require 'puppet/parser/collector' class Puppet::Parser::AST class Collection < AST::Branch attr_accessor :type, :query, :form + attr_reader :override associates_doc @@ -22,7 +23,37 @@ class Collection < AST::Branch scope.compiler.add_collection(newcoll) + add_override(newcoll, scope) if @override + newcoll end + + # Handle our parameter ourselves + def override=(override) + if override.is_a?(AST::ASTArray) + @override = override + else + @override = AST::ASTArray.new( + :line => override.line, + :file => override.file, + :children => [override] + ) + end + end + + def add_override(collection, scope) + params = @override.collect do |param| + param.safeevaluate(scope) + end + + collection.add_override( + :params => params, + :file => @file, + :line => @line, + :source => scope.source, + :scope => scope + ) + end + end end diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index 1dd1eb9..7dc1f72 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -1,9 +1,10 @@ # An object that collects stored objects from the central cache and returns # them to the current host, yo. class Puppet::Parser::Collector - attr_accessor :type, :scope, :vquery, :equery, :form, :resources, :collected + attr_accessor :type, :scope, :vquery, :equery, :form, :resources, :collected, :overrides # Call the collection method, mark all of the returned objects as non-virtual, + # and optionnaly apply overrides on them. # The collector can also delete himself from the compiler if there is no more # resources to collect (valid only for resource fixed-set collector # which get their resources from +collect_resources+ and not from the catalog) @@ -29,6 +30,8 @@ class Puppet::Parser::Collector end end + apply_overrides(objects) if @overrides + # filter out object that already have been collected by ourself # which can happen if we are called several times and we collect catalog # resources @@ -58,8 +61,38 @@ class Puppet::Parser::Collector @form = form end + # add a resource override to the soon to be exported/realized resources + def add_override(hash) + unless hash[:params] + raise ArgumentError, "Exported resource try to override without parameters" + end + + # schedule an override for an upcoming collection + @overrides = hash + end + private + def apply_overrides(objects) + # tell the compiler we have some override for him unless we already + # collected those resources + objects.each do |res| + unless @collected.include?(res.ref) + res = Puppet::Parser::Resource.new( + :type => res.type, + :title => res.title, + :params => overrides[:params], + :file => overrides[:file], + :line => overrides[:line], + :source => overrides[:source], + :scope => overrides[:scope] + ) + + scope.compiler.add_override(res) + end + end + end + # Create our active record query. def build_active_record_query Puppet::Rails.init unless ActiveRecord::Base.connected? diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra index 67303ab..9da2999 100644 --- a/lib/puppet/parser/grammar.ra +++ b/lib/puppet/parser/grammar.ra @@ -195,7 +195,27 @@ at: AT { result = :virtual } # A collection statement. Currently supports no arguments at all, but eventually # will, I assume. -collection: classref collectrhand { +collection: classref collectrhand LBRACE anyparams endcomma RBRACE { + if val[0] =~ /^[a-z]/ + Puppet.warning addcontext("Collection names must now be capitalized") + end + type = val[0].downcase + args = {:type => type} + + if val[1].is_a?(AST::CollExpr) + args[:query] = val[1] + args[:query].type = type + args[:form] = args[:query].form + else + args[:form] = val[1] + end + if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") + end + args[:override] = val[3] + result = ast AST::Collection, args +} + | classref collectrhand { if val[0] =~ /^[a-z]/ Puppet.warning addcontext("Collection names must now be capitalized") end diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb index 60a849c..c0b5435 100644 --- a/lib/puppet/parser/parser.rb +++ b/lib/puppet/parser/parser.rb [patch elided] diff --git a/spec/unit/parser/ast/collection.rb b/spec/unit/parser/ast/collection.rb new file mode 100755 index 0000000..c141bd7 --- /dev/null +++ b/spec/unit/parser/ast/collection.rb @@ -0,0 +1,63 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Collection do + before :each do + @scope = stub_everything 'scope' + @compiler = stub_everything 'compile' + @scope.stubs(:compiler).returns(@compiler) + + @overrides = stub_everything 'overrides' + @overrides.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) + + end + + it "should evaluate its query" do + query = mock 'query' + collection = Puppet::Parser::AST::Collection.new :query => query, :form => :virtual + + query.expects(:safeevaluate).with(@scope) + + collection.evaluate(@scope) + end + + it "should instantiate a Collector for this type" do + collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "test" + + Puppet::Parser::Collector.expects(:new).with(@scope, "test", nil, nil, :virtual) + + collection.evaluate(@scope) + end + + it "should tell the compiler about this collector" do + collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "test" + Puppet::Parser::Collector.stubs(:new).returns("whatever") + + @compiler.expects(:add_collection).with("whatever") + + collection.evaluate(@scope) + end + + it "should evaluate overriden paramaters" do + collector = stub_everything 'collector' + collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "test", :override => @overrides + Puppet::Parser::Collector.stubs(:new).returns(collector) + + @overrides.expects(:safeevaluate).with(@scope) + + collection.evaluate(@scope) + end + + it "should tell the collector about overrides" do + collector = mock 'collector' + collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "test", :override => @overrides + Puppet::Parser::Collector.stubs(:new).returns(collector) + + collector.expects(:add_override) + + collection.evaluate(@scope) + end + + +end diff --git a/spec/unit/parser/collector.rb b/spec/unit/parser/collector.rb index 56c684c..b0c23f6 100755 --- a/spec/unit/parser/collector.rb +++ b/spec/unit/parser/collector.rb @@ -39,6 +39,14 @@ describe Puppet::Parser::Collector, "when initializing" do @collector = Puppet::Parser::Collector.new(@scope, "resource::type", @equery, @vquery, @form) @collector.type.should == "Resource::Type" end + + it "should accept an optional resource override" do + @collector = Puppet::Parser::Collector.new(@scope, "resource::type", @equery, @vquery, @form) + override = { :params => "whatever" } + @collector.add_override(override) + @collector.overrides.should equal(override) + end + end describe Puppet::Parser::Collector, "when collecting specific virtual resources" do @@ -167,6 +175,38 @@ describe Puppet::Parser::Collector, "when collecting virtual and catalog resourc @collector.evaluate.should == [one] end + it "should create a resource with overriden parameters" do + one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" + param = stub 'param' + @compiler.stubs(:add_override) + + @compiler.expects(:resources).returns([one]) + + @collector.add_override(:params => param ) + Puppet::Parser::Resource.expects(:new).with { |h| + h[:params] == param + } + + @collector.evaluate + end + + it "should not override already overriden resources for this same collection in a previous run" do + one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" + param = stub 'param' + @compiler.stubs(:add_override) + + @compiler.expects(:resources).at_least(2).returns([one]) + + @collector.add_override(:params => param ) + Puppet::Parser::Resource.expects(:new).once.with { |h| + h[:params] == param + } + + @collector.evaluate + + @collector.evaluate + end + it "should not return resources that were collected in a previous run of this collector" do one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" @compiler.stubs(:resources).returns([one]) @@ -176,6 +216,21 @@ describe Puppet::Parser::Collector, "when collecting virtual and catalog resourc @collector.evaluate.should be_false end + + it "should tell the compiler about the overriden resources" do + one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" + param = stub 'param' + + one.expects(:virtual=).with(false) + @compiler.expects(:resources).returns([one]) + @collector.add_override(:params => param ) + Puppet::Parser::Resource.stubs(:new).returns("whatever") + + @compiler.expects(:add_override).with("whatever") + + @collector.evaluate + end + it "should not return or mark non-matching resources" do @collector.vquery = proc { |res| res.name == :one } @@ -282,6 +337,35 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do @collector.evaluate.should == [resource] end + it "should override all exported collected resources if collector has an override" do + stub_rails() + Puppet::Rails::Host.stubs(:find_by_name).returns(nil) + + one = stub 'one', :restype => "Mytype", :title => "one", :virtual? => true, :exported? => true, :ref => "one" + Puppet::Rails::Resource.stubs(:find).returns([one]) + + resource = mock 'resource' + one.expects(:to_resource).with(@scope).returns(resource) + resource.stubs(:exported=) + resource.stubs(:virtual=) + resource.stubs(:ref) + resource.stubs(:title) + + @compiler.stubs(:resources).returns([]) + @scope.stubs(:findresource).returns(nil) + + param = stub 'param' + @compiler.stubs(:add_override) + @compiler.stubs(:add_resource) + + @collector.add_override(:params => param ) + Puppet::Parser::Resource.expects(:new).once.with { |h| + h[:params] == param + } + + @collector.evaluate + end + it "should store converted resources in the compile's resource list" do stub_rails() Puppet::Rails::Host.stubs(:find_by_name).returns(nil) diff --git a/test/data/snippets/collection_override.pp b/test/data/snippets/collection_override.pp new file mode 100644 index 0000000..b1b39ab --- /dev/null +++ b/test/data/snippets/collection_override.pp @@ -0,0 +1,8 @@ +...@file { + "/tmp/collection": + content => "whatever" +} + +File<| |> { + mode => 0600 +} diff --git a/test/language/snippets.rb b/test/language/snippets.rb index a1d0f5d..c52409e 100755 --- a/test/language/snippets.rb +++ b/test/language/snippets.rb @@ -475,6 +475,12 @@ class TestSnippets < Test::Unit::TestCase assert_not_file("/tmp/multilinecomments","Did create a commented resource"); end + def snippet_collection_override + path = "/tmp/collection" + assert_file(path) + assert_mode_equal(0600, path) + end + # Iterate across each of the snippets and create a test. Dir.entries(snippetdir).sort.each { |file| next if file =~ /^\./ -- 1.6.0.2 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en -~----------~----~----~----~------~----~------~--~---
