diff --git a/lib/hiera/backend/puppet_backend.rb b/lib/hiera/backend/puppet_backend.rb index 49fdabff7..6f0a99188 100644 --- a/lib/hiera/backend/puppet_backend.rb +++ b/lib/hiera/backend/puppet_backend.rb @@ -1,102 +1,103 @@ +require 'hiera/backend' + class Hiera module Backend class Puppet_backend def initialize Hiera.debug("Hiera Puppet backend starting") end def hierarchy(scope, override) begin data_class = Config[:puppet][:datasource] || "data" rescue data_class = "data" end calling_class = scope.resource.name.to_s.downcase calling_module = calling_class.split("::").first hierarchy = Config[:hierarchy] || [calling_class, calling_module] hierarchy = [hierarchy].flatten.map do |klass| klass = Backend.parse_string(klass, scope, { "calling_class" => calling_class, "calling_module" => calling_module } ) next if klass == "" [data_class, klass].join("::") end.compact hierarchy << [calling_class, data_class].join("::") unless calling_module == calling_class hierarchy << [calling_module, data_class].join("::") end hierarchy.insert(0, [data_class, override].join("::")) if override hierarchy end def lookup(key, scope, order_override, resolution_type) answer = nil Hiera.debug("Looking up #{key} in Puppet backend") include_class = Puppet::Parser::Functions.function(:include) loaded_classes = scope.catalog.classes hierarchy(scope, order_override).each do |klass| Hiera.debug("Looking for data in #{klass}") varname = [klass, key].join("::") temp_answer = nil unless loaded_classes.include?(klass) begin if scope.respond_to?(:function_include) scope.function_include([klass]) else scope.real.function_include([klass]) end temp_answer = scope[varname] Hiera.debug("Found data in class #{klass}") rescue end else temp_answer = scope[varname] end - next if temp_answer == :undefined - - if temp_answer + # Note that temp_answer might be define but false. + if temp_answer.nil? + next + else # For array resolution we just append to the array whatever we # find, we then go onto the next file and keep adding to the array. # # For priority searches we break after the first found data item. case resolution_type when :array answer ||= [] answer << Backend.parse_answer(temp_answer, scope) when :hash answer ||= {} answer = Backend.parse_answer(temp_answer, scope).merge answer else answer = Backend.parse_answer(temp_answer, scope) break end end end - answer = nil if answer == :undefined - answer end end end end diff --git a/spec/unit/hiera/backend/puppet_backend_spec.rb b/spec/unit/hiera/backend/puppet_backend_spec.rb index 04ebac3b1..545ef257f 100644 --- a/spec/unit/hiera/backend/puppet_backend_spec.rb +++ b/spec/unit/hiera/backend/puppet_backend_spec.rb @@ -1,140 +1,147 @@ require 'spec_helper' require 'hiera/backend/puppet_backend' - +require 'hiera/scope' describe Hiera::Backend::Puppet_backend do + before do Hiera.stubs(:warn) Hiera.stubs(:debug) Hiera::Backend.stubs(:datasources).yields([]) Puppet::Parser::Functions.stubs(:function).with(:include) @mockresource = mock @mockresource.stubs(:name).returns("ntp::config") @mockscope = mock @mockscope.stubs(:resource).returns(@mockresource) @scope = Hiera::Scope.new(@mockscope) @backend = Hiera::Backend::Puppet_backend.new end describe "#hierarchy" do it "should use the configured datasource" do - Hiera::Config.expects("[]").with(:puppet).returns({:datasource => "rspec"}) - Hiera::Config.expects("[]").with(:hierarchy) - - ["ntp", "ntp::config"].each do |klass| - Hiera::Backend.expects(:parse_string).with(klass, @scope, {"calling_module" => "ntp", "calling_class" => "ntp::config"}).returns(klass) - end + with_config(:puppet => {:datasource => "rspec"}, + :hierarchy => nil) @backend.hierarchy(@scope, nil).should == ["rspec::ntp::config", "rspec::ntp", "ntp::config::rspec", "ntp::rspec"] end it "should not include empty class names" do - Hiera::Config.expects("[]").with(:puppet).returns({:datasource => "rspec"}) - Hiera::Config.expects("[]").with(:hierarchy).returns(["%{foo}", "common"]) + with_config(:puppet => {:datasource => "rspec"}, + :hierarchy => ["%{foo}", "common"]) - Hiera::Backend.expects(:parse_string).with("common", @scope, {"calling_module" => "ntp", "calling_class" => "ntp::config"}).returns("common") - Hiera::Backend.expects(:parse_string).with("%{foo}", @scope, {"calling_module" => "ntp", "calling_class" => "ntp::config"}).returns("") + @mockscope.expects(:lookupvar).with("foo").returns(nil) @backend.hierarchy(@scope, nil).should == ["rspec::common", "ntp::config::rspec", "ntp::rspec"] end it "should allow for an override data source" do - Hiera::Config.expects("[]").with(:puppet).returns({:datasource => "rspec"}) - Hiera::Config.expects("[]").with(:hierarchy) - - ["ntp", "ntp::config"].each do |klass| - Hiera::Backend.expects(:parse_string).with(klass, @scope, {"calling_module" => "ntp", "calling_class" => "ntp::config"}).returns(klass) - end + with_config(:puppet => {:datasource => "rspec"}, + :hierarchy => nil) @backend.hierarchy(@scope, "override").should == ["rspec::override", "rspec::ntp::config", "rspec::ntp", "ntp::config::rspec", "ntp::rspec"] end end describe "#lookup" do it "should attempt to load data from unincluded classes" do - Hiera::Backend.expects(:parse_answer).with("rspec", @scope).returns("rspec") + with_config(:puppet => {:datasource => "rspec"}, + :hierarchy => ["rspec"]) catalog = mock catalog.expects(:classes).returns([]) - @scope.expects(:catalog).returns(catalog) - @scope.expects(:function_include).with(["rspec"]) - @mockscope.expects(:lookupvar).with("rspec::key").returns("rspec") + @mockscope.expects(:catalog).returns(catalog) + @mockscope.expects(:function_include).with(["rspec::rspec"]) + @mockscope.expects(:lookupvar).with("rspec::rspec::key").returns("rspec") - @backend.expects(:hierarchy).with(@scope, nil).returns(["rspec"]) @backend.lookup("key", @scope, nil, nil).should == "rspec" end it "should not load loaded classes" do - Hiera::Backend.expects(:parse_answer).with("rspec", @scope).returns("rspec") + with_config(:puppet => {:datasource => "rspec"}, + :hierarchy => ["rspec"]) + catalog = mock - catalog.expects(:classes).returns(["rspec"]) + catalog.expects(:classes).returns(["rspec::rspec"]) @mockscope.expects(:catalog).returns(catalog) @mockscope.expects(:function_include).never - @mockscope.expects(:lookupvar).with("rspec::key").returns("rspec") + @mockscope.expects(:lookupvar).with("rspec::rspec::key").returns("rspec") - @backend.expects(:hierarchy).with(@scope, nil).returns(["rspec"]) @backend.lookup("key", @scope, nil, nil).should == "rspec" end it "should return the first found data" do - Hiera::Backend.expects(:parse_answer).with("rspec", @scope).returns("rspec") + with_config(:puppet => {:datasource => "rspec"}, + :hierarchy => ["override", "rspec"]) + catalog = mock - catalog.expects(:classes).returns(["rspec", "override"]) + catalog.expects(:classes).returns(["rspec::override", "override::override"]) @mockscope.expects(:catalog).returns(catalog) @mockscope.expects(:function_include).never - @mockscope.expects(:lookupvar).with("override::key").returns("rspec") - @mockscope.expects(:lookupvar).with("rspec::key").never + @mockscope.expects(:lookupvar).with("rspec::override::key").returns("rspec") + @mockscope.expects(:lookupvar).with("rspec::rspec::key").never - @backend.expects(:hierarchy).with(@scope, "override").returns(["override", "rspec"]) @backend.lookup("key", @scope, "override", nil).should == "rspec" end + it "should consider a value of false to be a real value" do + with_config(:puppet => {:datasource => "rspec"}, + :hierarchy => ["override", "rspec"]) + expected_answer = false + + catalog = mock + catalog.expects(:classes).returns(["rspec::override", "override::override"]) + @mockscope.expects(:catalog).returns(catalog) + @mockscope.expects(:lookupvar).with("rspec::override::key").returns(expected_answer) + @mockscope.expects(:lookupvar).with("rspec::rspec::key").never + + @backend.lookup("key", @scope, "override", nil).should == expected_answer + end + it "should return an array of found data for array searches" do - Hiera::Backend.expects(:parse_answer).with("rspec::key", @scope).returns("rspec::key") - Hiera::Backend.expects(:parse_answer).with("test::key", @scope).returns("test::key") catalog = mock catalog.expects(:classes).returns(["rspec", "test"]) @mockscope.expects(:catalog).returns(catalog) @mockscope.expects(:function_include).never @mockscope.expects(:lookupvar).with("rspec::key").returns("rspec::key") @mockscope.expects(:lookupvar).with("test::key").returns("test::key") @backend.expects(:hierarchy).with(@scope, nil).returns(["rspec", "test"]) @backend.lookup("key", @scope, nil, :array).should == ["rspec::key", "test::key"] end - it "should return a hash of found data for hash searches" do - Hiera::Backend.expects(:parse_answer).with("rspec::key", @scope).returns({'rspec'=>'key'}) - Hiera::Backend.expects(:parse_answer).with("test::key", @scope).returns({'test'=>'key'}) catalog = mock catalog.expects(:classes).returns(["rspec", "test"]) @mockscope.expects(:catalog).returns(catalog) @mockscope.expects(:function_include).never - @mockscope.expects(:lookupvar).with("rspec::key").returns("rspec::key") - @mockscope.expects(:lookupvar).with("test::key").returns("test::key") + @mockscope.expects(:lookupvar).with("rspec::key").returns({'rspec'=>'key'}) + @mockscope.expects(:lookupvar).with("test::key").returns({'test'=>'key'}) @backend.expects(:hierarchy).with(@scope, nil).returns(["rspec", "test"]) @backend.lookup("key", @scope, nil, :hash).should == {'rspec'=>'key', 'test'=>'key'} end it "should return a merged hash of found data for hash searches" do - Hiera::Backend.expects(:parse_answer).with("rspec::key", @scope).returns({'rspec'=>'key', 'common'=>'rspec'}) - Hiera::Backend.expects(:parse_answer).with("test::key", @scope).returns({'test'=>'key', 'common'=>'rspec'}) catalog = mock catalog.expects(:classes).returns(["rspec", "test"]) @mockscope.expects(:catalog).returns(catalog) @mockscope.expects(:function_include).never - @mockscope.expects(:lookupvar).with("rspec::key").returns("rspec::key") - @mockscope.expects(:lookupvar).with("test::key").returns("test::key") + @mockscope.expects(:lookupvar).with("rspec::key").returns({'rspec'=>'key', 'common'=>'rspec'}) + @mockscope.expects(:lookupvar).with("test::key").returns({'test'=>'key', 'common'=>'rspec'}) @backend.expects(:hierarchy).with(@scope, nil).returns(["rspec", "test"]) @backend.lookup("key", @scope, nil, :hash).should == {'rspec'=>'key', 'common'=>'rspec', 'test'=>'key'} end end + + def with_config(config) + config.each do |key, value| + Hiera::Config.expects("[]").with(key).returns(value) + end + end end