Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 93 additions & 2 deletions lib/puppet/indirector/data_binding/hiera.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,99 @@
# frozen_string_literal: true

require_relative '../../../puppet/indirector/hiera'
require_relative '../../../puppet/indirector/code'
require 'hiera/scope'

class Puppet::DataBinding::Hiera < Puppet::Indirector::Hiera
class Puppet::DataBinding::Hiera < Puppet::Indirector::Code
desc "Retrieve data using Hiera."

def initialize(*args)
unless Puppet.features.hiera?
# TRANSLATORS "Hiera" is the name of a code library and should not be translated
raise _("Hiera terminus not supported without hiera library")
end

super
end

if defined?(::Psych::SyntaxError)
DATA_BINDING_EXCEPTIONS = [::StandardError, ::Psych::SyntaxError]
else
DATA_BINDING_EXCEPTIONS = [::StandardError]
end

def find(request)
not_found = Object.new
options = request.options
Puppet.debug { "Performing a hiera indirector lookup of #{request.key} with options #{options.inspect}" }
value = hiera.lookup(request.key, not_found, Hiera::Scope.new(options[:variables]), nil, convert_merge(options[:merge]))
throw :no_such_key if value.equal?(not_found)
value
rescue *DATA_BINDING_EXCEPTIONS => detail
error = Puppet::DataBinding::LookupError.new("DataBinding 'hiera': #{detail.message}")
error.set_backtrace(detail.backtrace)
raise error
end

private

# Converts a lookup 'merge' parameter argument into a Hiera 'resolution_type' argument.
#
# @param merge [String,Hash,nil] The lookup 'merge' argument
# @return [Symbol,Hash,nil] The Hiera 'resolution_type'
def convert_merge(merge)
case merge
when nil, 'first'
# Nil is OK. Defaults to Hiera :priority
nil
when Puppet::Pops::MergeStrategy
convert_merge(merge.configuration)
when 'unique'
# Equivalent to Hiera :array
:array
when 'hash'
# Equivalent to Hiera :hash with default :native merge behavior. A Hash must be passed here
# to override possible Hiera deep merge config settings.
{ :behavior => :native }
when 'deep'
# Equivalent to Hiera :hash with :deeper merge behavior.
{ :behavior => :deeper }
when Hash
strategy = merge['strategy']
if strategy == 'deep'
result = { :behavior => :deeper }
# Remaining entries must have symbolic keys
merge.each_pair { |k, v| result[k.to_sym] = v unless k == 'strategy' }
result
else
convert_merge(strategy)
end
else
# TRANSLATORS "merge" is a parameter name and should not be translated
raise Puppet::DataBinding::LookupError, _("Unrecognized value for request 'merge' parameter: '%{merge}'") % { merge: merge }
end
end

public

def self.hiera_config
hiera_config = Puppet.settings[:hiera_config]
config = {}

if Puppet::FileSystem.exist?(hiera_config)
config = Hiera::Config.load(hiera_config)
else
Puppet.warning _("Config file %{hiera_config} not found, using Hiera defaults") % { hiera_config: hiera_config }
end

config[:logger] = 'puppet'
config
end

def self.hiera
@hiera ||= Hiera.new(:config => hiera_config)
end

def hiera
self.class.hiera
end
end
101 changes: 0 additions & 101 deletions lib/puppet/indirector/hiera.rb

This file was deleted.

8 changes: 2 additions & 6 deletions spec/integration/data_binding_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
require 'spec_helper'
require 'puppet/indirector/hiera'

require 'puppet_spec/compiler'
require 'puppet/indirector/data_binding/hiera'

Expand Down Expand Up @@ -53,10 +51,8 @@
}}

before do
# Drop all occurances of cached hiera instances. This will reset @hiera in Puppet::Indirector::Hiera, Testing::DataBinding::Hiera,
# and Puppet::DataBinding::Hiera. Different classes are active as indirection depending on configuration
ObjectSpace.each_object(Class).select {|klass| klass <= Puppet::Indirector::Hiera }.each { |klass| klass.instance_variable_set(:@hiera, nil) }
Puppet[:data_binding_terminus] = 'hiera'
# Reset the cached hiera instance on the terminus class
Puppet::DataBinding::Hiera.instance_variable_set(:@hiera, nil)
Puppet[:modulepath] = dir
end

Expand Down
69 changes: 69 additions & 0 deletions spec/unit/indirector/data_binding/hiera_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,73 @@
end

it_should_behave_like "Hiera indirection", Puppet::DataBinding::Hiera, my_fixture_dir

describe "#find", :if => Puppet.features.hiera? do
let(:data_binder) { described_class.new }
let(:hiera) { double('hiera') }

def request(key, options = {})
Puppet::Indirector::Request.new(:hiera, :find, key, nil, options)
end

before do
allow(described_class).to receive(:hiera).and_return(hiera)
end

it "throws :no_such_key when hiera returns the not_found sentinel" do
# Returning the default argument signals "not found" to the find method
allow(hiera).to receive(:lookup) { |_key, default, *_| default }
expect { data_binder.find(request('missing')) }.to throw_symbol(:no_such_key)
end
end

describe "#convert_merge", :if => Puppet.features.hiera? do
let(:data_binder) { described_class.new }

def convert(merge)
data_binder.send(:convert_merge, merge)
end

it "returns nil for nil" do
expect(convert(nil)).to be_nil
end

it "returns nil for 'first'" do
expect(convert('first')).to be_nil
end

it "returns :array for 'unique'" do
expect(convert('unique')).to eq(:array)
end

it "returns native hash behavior for 'hash'" do
expect(convert('hash')).to eq({ :behavior => :native })
end

it "returns deeper hash behavior for 'deep'" do
expect(convert('deep')).to eq({ :behavior => :deeper })
end

it "delegates to the strategy's configuration when given a MergeStrategy" do
strategy = instance_double(Puppet::Pops::MergeStrategy, :configuration => 'unique')
expect(convert(strategy)).to eq(:array)
end

it "returns deeper hash behavior for a Hash with strategy 'deep'" do
expect(convert({ 'strategy' => 'deep' })).to eq({ :behavior => :deeper })
end

it "forwards extra keys alongside deeper behavior for a Hash with strategy 'deep'" do
result = convert({ 'strategy' => 'deep', 'knockout_prefix' => '--' })
expect(result).to eq({ :behavior => :deeper, :knockout_prefix => '--' })
end

it "delegates to the string strategy for a Hash with a non-deep strategy" do
expect(convert({ 'strategy' => 'unique' })).to eq(:array)
end

it "raises LookupError for an unrecognized merge value" do
expect { convert('bogus') }.to raise_error(Puppet::DataBinding::LookupError, /Unrecognized value.*bogus/)
end
end
end
22 changes: 0 additions & 22 deletions spec/unit/indirector/hiera_spec.rb

This file was deleted.