hiera 1.3.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/README.md +47 -10
- data/bin/hiera +48 -27
- data/lib/hiera/backend/json_backend.rb +9 -7
- data/lib/hiera/backend/yaml_backend.rb +17 -14
- data/lib/hiera/backend.rb +163 -44
- data/lib/hiera/config.rb +1 -3
- data/lib/hiera/interpolate.rb +64 -14
- data/lib/hiera/util.rb +5 -5
- data/lib/hiera/version.rb +1 -1
- data/lib/hiera.rb +55 -3
- data/spec/spec_helper.rb +23 -0
- data/spec/unit/backend/json_backend_spec.rb +9 -9
- data/spec/unit/backend/yaml_backend_spec.rb +62 -73
- data/spec/unit/backend_spec.rb +192 -32
- data/spec/unit/config_spec.rb +17 -2
- data/spec/unit/fixtures/interpolate/config/hiera.yaml +6 -0
- data/spec/unit/fixtures/interpolate/data/niltest.yaml +2 -0
- data/spec/unit/fixtures/interpolate/data/recursive.yaml +3 -0
- data/spec/unit/fixtures/override/config/hiera.yaml +5 -0
- data/spec/unit/fixtures/override/data/alternate.yaml +1 -0
- data/spec/unit/fixtures/override/data/common.yaml +2 -0
- data/spec/unit/interpolate_spec.rb +36 -0
- data/spec/unit/util_spec.rb +4 -4
- metadata +51 -41
data/lib/hiera/interpolate.rb
CHANGED
@@ -1,28 +1,71 @@
|
|
1
1
|
require 'hiera/backend'
|
2
|
+
require 'hiera/recursive_guard'
|
3
|
+
|
4
|
+
|
5
|
+
class Hiera::InterpolationInvalidValue < StandardError; end
|
2
6
|
|
3
7
|
class Hiera::Interpolate
|
4
8
|
class << self
|
5
9
|
INTERPOLATION = /%\{([^\}]*)\}/
|
6
|
-
METHOD_INTERPOLATION = /%\{(scope|hiera)\(['"]([^"']*)["']\)\}/
|
10
|
+
METHOD_INTERPOLATION = /%\{(scope|hiera|literal|alias)\(['"]([^"']*)["']\)\}/
|
11
|
+
|
12
|
+
def interpolate(data, scope, extra_data, context)
|
13
|
+
if data.is_a?(String)
|
14
|
+
# Wrapping do_interpolation in a gsub block ensures we process
|
15
|
+
# each interpolation site in isolation using separate recursion guards.
|
16
|
+
context ||= {}
|
17
|
+
new_context = context.clone
|
18
|
+
new_context[:recurse_guard] ||= Hiera::RecursiveGuard.new
|
19
|
+
data.gsub(INTERPOLATION) do |match|
|
20
|
+
interp_val = do_interpolation(match, scope, extra_data, new_context)
|
7
21
|
|
8
|
-
|
22
|
+
# Get interp method in case we are aliasing
|
23
|
+
if data.is_a?(String) && (match = data.match(INTERPOLATION))
|
24
|
+
interpolate_method, key = get_interpolation_method_and_key(data)
|
25
|
+
else
|
26
|
+
interpolate_method = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
if ( (interpolate_method == :alias_interpolate) and (!interp_val.is_a?(String)) )
|
30
|
+
if data.match("^#{INTERPOLATION}$")
|
31
|
+
return interp_val
|
32
|
+
else
|
33
|
+
raise Hiera::InterpolationInvalidValue, "Cannot call alias in the string context"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
interp_val
|
37
|
+
end
|
38
|
+
end
|
39
|
+
else
|
40
|
+
data
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def do_interpolation(data, scope, extra_data, context)
|
9
45
|
if data.is_a?(String) && (match = data.match(INTERPOLATION))
|
10
46
|
interpolation_variable = match[1]
|
11
|
-
recurse_guard.check(interpolation_variable) do
|
47
|
+
context[:recurse_guard].check(interpolation_variable) do
|
12
48
|
interpolate_method, key = get_interpolation_method_and_key(data)
|
13
|
-
interpolated_data = send(interpolate_method, data, key, scope, extra_data)
|
14
|
-
|
49
|
+
interpolated_data = send(interpolate_method, data, key, scope, extra_data, context)
|
50
|
+
|
51
|
+
# Halt recursion if we encounter a literal.
|
52
|
+
return interpolated_data if interpolate_method == :literal_interpolate
|
53
|
+
|
54
|
+
do_interpolation(interpolated_data, scope, extra_data, context)
|
15
55
|
end
|
16
56
|
else
|
17
57
|
data
|
18
58
|
end
|
19
59
|
end
|
60
|
+
private :do_interpolation
|
20
61
|
|
21
62
|
def get_interpolation_method_and_key(data)
|
22
63
|
if (match = data.match(METHOD_INTERPOLATION))
|
23
64
|
case match[1]
|
24
65
|
when 'hiera' then [:hiera_interpolate, match[2]]
|
25
66
|
when 'scope' then [:scope_interpolate, match[2]]
|
67
|
+
when 'literal' then [:literal_interpolate, match[2]]
|
68
|
+
when 'alias' then [:alias_interpolate, match[2]]
|
26
69
|
end
|
27
70
|
elsif (match = data.match(INTERPOLATION))
|
28
71
|
[:scope_interpolate, match[1]]
|
@@ -30,19 +73,26 @@ class Hiera::Interpolate
|
|
30
73
|
end
|
31
74
|
private :get_interpolation_method_and_key
|
32
75
|
|
33
|
-
def scope_interpolate(data, key, scope, extra_data)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
data.sub(INTERPOLATION, value.to_s)
|
76
|
+
def scope_interpolate(data, key, scope, extra_data, context)
|
77
|
+
segments = key.split('.')
|
78
|
+
catch(:no_such_key) { return Hiera::Backend.qualified_lookup(segments, scope) }
|
79
|
+
catch(:no_such_key) { Hiera::Backend.qualified_lookup(segments, extra_data) }
|
39
80
|
end
|
40
81
|
private :scope_interpolate
|
41
82
|
|
42
|
-
def hiera_interpolate(data, key, scope, extra_data)
|
43
|
-
|
44
|
-
data.sub(METHOD_INTERPOLATION, value)
|
83
|
+
def hiera_interpolate(data, key, scope, extra_data, context)
|
84
|
+
Hiera::Backend.lookup(key, nil, scope, context[:order_override], :priority, context)
|
45
85
|
end
|
46
86
|
private :hiera_interpolate
|
87
|
+
|
88
|
+
def literal_interpolate(data, key, scope, extra_data, context)
|
89
|
+
key
|
90
|
+
end
|
91
|
+
private :literal_interpolate
|
92
|
+
|
93
|
+
def alias_interpolate(data, key, scope, extra_data, context)
|
94
|
+
Hiera::Backend.lookup(key, nil, scope, context[:order_override], :priority, context)
|
95
|
+
end
|
96
|
+
private :alias_interpolate
|
47
97
|
end
|
48
98
|
end
|
data/lib/hiera/util.rb
CHANGED
@@ -9,7 +9,7 @@ class Hiera
|
|
9
9
|
|
10
10
|
def microsoft_windows?
|
11
11
|
return false unless file_alt_separator
|
12
|
-
|
12
|
+
|
13
13
|
begin
|
14
14
|
require 'win32/dir'
|
15
15
|
true
|
@@ -21,17 +21,17 @@ class Hiera
|
|
21
21
|
|
22
22
|
def config_dir
|
23
23
|
if microsoft_windows?
|
24
|
-
File.join(common_appdata, 'PuppetLabs', '
|
24
|
+
File.join(common_appdata, 'PuppetLabs', 'code')
|
25
25
|
else
|
26
|
-
'/etc'
|
26
|
+
'/etc/puppetlabs/code'
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
def var_dir
|
31
31
|
if microsoft_windows?
|
32
|
-
File.join(common_appdata, 'PuppetLabs', '
|
32
|
+
File.join(common_appdata, 'PuppetLabs', 'code', 'hieradata')
|
33
33
|
else
|
34
|
-
'/
|
34
|
+
'/etc/puppetlabs/code/hieradata'
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
data/lib/hiera/version.rb
CHANGED
data/lib/hiera.rb
CHANGED
@@ -49,15 +49,67 @@ class Hiera
|
|
49
49
|
|
50
50
|
# Calls the backends to do the actual lookup.
|
51
51
|
#
|
52
|
-
# The
|
52
|
+
# The _scope_ can be anything that responds to `[]`, if you have input
|
53
53
|
# data like a Puppet Scope that does not you can wrap that data in a
|
54
|
-
# class that has a [] method that fetches the data from your source.
|
54
|
+
# class that has a `[]` method that fetches the data from your source.
|
55
55
|
# See hiera-puppet for an example of this.
|
56
56
|
#
|
57
57
|
# The order-override will insert as first in the hierarchy a data source
|
58
58
|
# of your choice.
|
59
|
+
#
|
60
|
+
# Possible values for the _resolution_type_ parameter:
|
61
|
+
#
|
62
|
+
# - _:priority_ - This is the default. First found value is returned and no merge is performed
|
63
|
+
# - _:array_ - An array merge lookup assembles a value from every matching level of the hierarchy. It retrieves all
|
64
|
+
# of the (string or array) values for a given key, then flattens them into a single array of unique values.
|
65
|
+
# If _priority_ lookup can be thought of as a “default with overrides” pattern, _array_ merge lookup can be though
|
66
|
+
# of as “default with additions.”
|
67
|
+
# - _:hash_ - A hash merge lookup assembles a value from every matching level of the hierarchy. It retrieves all of
|
68
|
+
# the (hash) values for a given key, then merges the hashes into a single hash. Hash merge lookups will fail with
|
69
|
+
# an error if any of the values found in the data sources are strings or arrays. It only works when every value
|
70
|
+
# found is a hash. The actual merge behavior is determined by looking up the keys `:merge_behavior` and
|
71
|
+
# `:deep_merge_options` in the Hiera config. `:merge_behavior` can be set to `:deep`, :deeper` or `:native`
|
72
|
+
# (explained in detail below).
|
73
|
+
# - _{ deep merge options }_ - Configured values for `:merge_behavior` and `:deep_merge_options`will be completely
|
74
|
+
# ignored. Instead the _resolution_type_ will be a `:hash` merge where the `:merge_behavior` will be the value
|
75
|
+
# keyed by `:behavior` in the given hash and the `:deep_merge_options` will be the remaining top level entries of
|
76
|
+
# that same hash.
|
77
|
+
#
|
78
|
+
# Valid behaviors for the _:hash_ resolution type:
|
79
|
+
#
|
80
|
+
# - _native_ - Performs a simple hash-merge by overwriting keys of lower lookup priority.
|
81
|
+
# - _deeper_ - In a deeper hash merge, Hiera recursively merges keys and values in each source hash. For each key,
|
82
|
+
# if the value is:
|
83
|
+
# - only present in one source hash, it goes into the final hash.
|
84
|
+
# - a string/number/boolean and exists in two or more source hashes, the highest priority value goes into
|
85
|
+
# the final hash.
|
86
|
+
# - an array and exists in two or more source hashes, the values from each source are merged into a single
|
87
|
+
# array and de-duplicated (but not automatically flattened, as in an array merge lookup).
|
88
|
+
# - a hash and exists in two or more source hashes, the values from each source are recursively merged, as
|
89
|
+
# though they were source hashes.
|
90
|
+
# - mismatched between two or more source hashes, we haven’t validated the behavior. It should act as
|
91
|
+
# described in the deep_merge gem documentation.
|
92
|
+
# - _deep_ - In a deep hash merge, Hiera behaves the same as for _deeper_, except that when a string/number/boolean
|
93
|
+
# exists in two or more source hashes, the lowest priority value goes into the final hash. This is considered
|
94
|
+
# largely useless and should be avoided. Use _deeper_ instead.
|
95
|
+
#
|
96
|
+
# The _merge_ can be given as a hash with the mandatory key `:strategy` to denote the actual strategy. This
|
97
|
+
# is useful for the `:deeper` and `:deep` strategy since they can use additional options to control the behavior.
|
98
|
+
# The options can be passed as top level keys in the `merge` parameter when it is a given as a hash. Recognized
|
99
|
+
# options are:
|
100
|
+
#
|
101
|
+
# - 'knockout_prefix' Set to string value to signify prefix which deletes elements from existing element. Defaults is _undef_
|
102
|
+
# - 'sort_merged_arrays' Set to _true_ to sort all arrays that are merged together. Default is _false_
|
103
|
+
# - 'unpack_arrays' Set to string value used as a deliminator to join all array values and then split them again. Default is _undef_
|
104
|
+
# - 'merge_hash_arrays' Set to _true_ to merge hashes within arrays. Default is _false_
|
105
|
+
#
|
106
|
+
# @param key [String] The key to lookup
|
107
|
+
# @param default [Object,nil] The value to return when there is no match for _key_
|
108
|
+
# @param scope [#[],nil] The scope to use for the lookup
|
109
|
+
# @param order_override [#[]] An override that will considered the first source of lookup
|
110
|
+
# @param resolution_type [String,Hash<Symbol,String>] Symbolic resolution type or deep merge configuration
|
111
|
+
# @return [Object] The found value or the given _default_ value
|
59
112
|
def lookup(key, default, scope, order_override=nil, resolution_type=:priority)
|
60
113
|
Backend.lookup(key, default, scope, order_override, resolution_type)
|
61
114
|
end
|
62
115
|
end
|
63
|
-
|
data/spec/spec_helper.rb
CHANGED
@@ -8,6 +8,29 @@ require 'tmpdir'
|
|
8
8
|
|
9
9
|
RSpec.configure do |config|
|
10
10
|
config.mock_with :mocha
|
11
|
+
|
12
|
+
if Hiera::Util.microsoft_windows? && RUBY_VERSION =~ /^1\./
|
13
|
+
require 'win32console'
|
14
|
+
config.output_stream = $stdout
|
15
|
+
config.error_stream = $stderr
|
16
|
+
config.formatters.each { |f| f.instance_variable_set(:@output, $stdout) }
|
17
|
+
end
|
18
|
+
|
19
|
+
config.after :suite do
|
20
|
+
# Log the spec order to a file, but only if the LOG_SPEC_ORDER environment variable is
|
21
|
+
# set. This should be enabled on Jenkins runs, as it can be used with Nick L.'s bisect
|
22
|
+
# script to help identify and debug order-dependent spec failures.
|
23
|
+
if ENV['LOG_SPEC_ORDER']
|
24
|
+
File.open("./spec_order.txt", "w") do |logfile|
|
25
|
+
config.instance_variable_get(:@files_to_run).each { |f| logfile.puts f }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# So everyone else doesn't have to include this base constant.
|
32
|
+
module HieraSpec
|
33
|
+
FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), 'unit', 'fixtures') unless defined?(FIXTURE_DIR)
|
11
34
|
end
|
12
35
|
|
13
36
|
# In ruby 1.8.5 Dir does not have mktmpdir defined, so this monkey patches
|
@@ -25,7 +25,7 @@ class Hiera
|
|
25
25
|
Backend.expects(:datafile).with(:json, {}, "one", "json").returns(nil)
|
26
26
|
Backend.expects(:datafile).with(:json, {}, "two", "json").returns(nil)
|
27
27
|
|
28
|
-
@backend.lookup("key", {}, nil, :priority)
|
28
|
+
expect { @backend.lookup("key", {}, nil, :priority, nil) }.to throw_symbol(:no_such_key)
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should retain the data types found in data files" do
|
@@ -35,9 +35,9 @@ class Hiera
|
|
35
35
|
|
36
36
|
@cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"stringval" => "string", "boolval" => true, "numericval" => 1}).times(3)
|
37
37
|
|
38
|
-
@backend.lookup("stringval", {}, nil, :priority).should == "string"
|
39
|
-
@backend.lookup("boolval", {}, nil, :priority).should == true
|
40
|
-
@backend.lookup("numericval", {}, nil, :priority).should == 1
|
38
|
+
@backend.lookup("stringval", {}, nil, :priority, nil).should == "string"
|
39
|
+
@backend.lookup("boolval", {}, nil, :priority, nil).should == true
|
40
|
+
@backend.lookup("numericval", {}, nil, :priority, nil).should == 1
|
41
41
|
end
|
42
42
|
|
43
43
|
it "should pick data earliest source that has it for priority searches" do
|
@@ -49,12 +49,12 @@ class Hiera
|
|
49
49
|
File.stubs(:exist?).with("/nonexisting/one.json").returns(true)
|
50
50
|
@cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "test_%{rspec}"})
|
51
51
|
|
52
|
-
@backend.lookup("key", scope, nil, :priority).should == "test_test"
|
52
|
+
@backend.lookup("key", scope, nil, :priority, nil).should == "test_test"
|
53
53
|
end
|
54
54
|
|
55
55
|
it "should build an array of all data sources for array searches" do
|
56
56
|
Hiera::Backend.stubs(:empty_answer).returns([])
|
57
|
-
Backend.stubs(:parse_answer).with('answer', {}).returns("answer")
|
57
|
+
Backend.stubs(:parse_answer).with('answer', {}, {}, anything).returns("answer")
|
58
58
|
Backend.expects(:datafile).with(:json, {}, "one", "json").returns("/nonexisting/one.json")
|
59
59
|
Backend.expects(:datafile).with(:json, {}, "two", "json").returns("/nonexisting/two.json")
|
60
60
|
|
@@ -66,18 +66,18 @@ class Hiera
|
|
66
66
|
@cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "answer"})
|
67
67
|
@cache.expects(:read_file).with("/nonexisting/two.json", Hash).returns({"key" => "answer"})
|
68
68
|
|
69
|
-
@backend.lookup("key", {}, nil, :array).should == ["answer", "answer"]
|
69
|
+
@backend.lookup("key", {}, nil, :array, nil).should == ["answer", "answer"]
|
70
70
|
end
|
71
71
|
|
72
72
|
it "should parse the answer for scope variables" do
|
73
|
-
Backend.stubs(:parse_answer).with('test_%{rspec}', {'rspec' => 'test'}).returns("test_test")
|
73
|
+
Backend.stubs(:parse_answer).with('test_%{rspec}', {'rspec' => 'test'}, {}, anything).returns("test_test")
|
74
74
|
Backend.expects(:datasources).yields("one")
|
75
75
|
Backend.expects(:datafile).with(:json, {"rspec" => "test"}, "one", "json").returns("/nonexisting/one.json")
|
76
76
|
|
77
77
|
File.expects(:exist?).with("/nonexisting/one.json").returns(true)
|
78
78
|
@cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "test_%{rspec}"})
|
79
79
|
|
80
|
-
@backend.lookup("key", {"rspec" => "test"}, nil, :priority).should == "test_test"
|
80
|
+
@backend.lookup("key", {"rspec" => "test"}, nil, :priority, nil).should == "test_test"
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
@@ -3,12 +3,29 @@ require 'hiera/backend/yaml_backend'
|
|
3
3
|
|
4
4
|
class Hiera
|
5
5
|
module Backend
|
6
|
+
class FakeCache
|
7
|
+
attr_accessor :value
|
8
|
+
def read(path, expected_type, default, &block)
|
9
|
+
read_file(path, expected_type, &block)
|
10
|
+
rescue => e
|
11
|
+
default
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_file(path, expected_type, &block)
|
15
|
+
output = block.call(@value)
|
16
|
+
if !output.is_a? expected_type
|
17
|
+
raise TypeError
|
18
|
+
end
|
19
|
+
output
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
6
23
|
describe Yaml_backend do
|
7
24
|
before do
|
8
25
|
Config.load({})
|
9
26
|
Hiera.stubs(:debug)
|
10
27
|
Hiera.stubs(:warn)
|
11
|
-
@cache =
|
28
|
+
@cache = FakeCache.new
|
12
29
|
@backend = Yaml_backend.new(@cache)
|
13
30
|
end
|
14
31
|
|
@@ -20,128 +37,100 @@ class Hiera
|
|
20
37
|
end
|
21
38
|
|
22
39
|
describe "#lookup" do
|
23
|
-
it "should look for data in all sources" do
|
24
|
-
Backend.expects(:datasources).multiple_yields(["one"], ["two"])
|
25
|
-
Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns(nil)
|
26
|
-
Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns(nil)
|
27
|
-
|
28
|
-
@backend.lookup("key", {}, nil, :priority)
|
29
|
-
end
|
30
|
-
|
31
40
|
it "should pick data earliest source that has it for priority searches" do
|
32
|
-
Backend.expects(:
|
33
|
-
|
34
|
-
Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns(nil).never
|
35
|
-
@cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"answer"})
|
36
|
-
File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
|
37
|
-
|
38
|
-
@backend.lookup("key", {}, nil, :priority).should == "answer"
|
39
|
-
end
|
41
|
+
Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).yields(["one", "/nonexisting/one.yaml"])
|
42
|
+
@cache.value = "---\nkey: answer"
|
40
43
|
|
41
|
-
|
42
|
-
Backend.expects(:datasources).multiple_yields(["one"])
|
43
|
-
Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns(nil)
|
44
|
-
YAML.expects(:load_file).never
|
45
|
-
|
46
|
-
@backend.lookup("key", {}, nil, :priority)
|
44
|
+
@backend.lookup("key", {}, nil, :priority, nil).should == "answer"
|
47
45
|
end
|
48
46
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
47
|
+
describe "handling unexpected YAML values" do
|
48
|
+
before do
|
49
|
+
Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).yields(["one", "/nonexisting/one.yaml"])
|
50
|
+
end
|
51
|
+
|
52
|
+
it "throws :no_such_key when key is missing in YAML" do
|
53
|
+
@cache.value = "---\n"
|
54
|
+
expect { @backend.lookup("key", {}, nil, :priority, nil) }.to throw_symbol(:no_such_key)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns nil when the YAML value is nil" do
|
58
|
+
@cache.value = "key: ~\n"
|
59
|
+
@backend.lookup("key", {}, nil, :priority, nil).should be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
it "throws :no_such_key when the YAML file is false" do
|
63
|
+
@cache.value = ""
|
64
|
+
expect { @backend.lookup("key", {}, nil, :priority, nil) }.to throw_symbol(:no_such_key)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "raises a TypeError when the YAML value is not a hash" do
|
68
|
+
@cache.value = "---\n[one, two, three]"
|
69
|
+
expect { @backend.lookup("key", {}, nil, :priority, nil) }.to raise_error(TypeError)
|
70
|
+
end
|
56
71
|
end
|
57
72
|
|
58
73
|
it "should build an array of all data sources for array searches" do
|
59
|
-
Backend.expects(:
|
60
|
-
Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
|
61
|
-
Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
|
62
|
-
File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
|
63
|
-
File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
|
64
|
-
|
74
|
+
Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
|
65
75
|
@cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"answer"})
|
66
76
|
@cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>"answer"})
|
67
77
|
|
68
|
-
@backend.lookup("key", {}, nil, :array).should == ["answer", "answer"]
|
78
|
+
@backend.lookup("key", {}, nil, :array, nil).should == ["answer", "answer"]
|
69
79
|
end
|
70
80
|
|
71
81
|
it "should ignore empty hash of data sources for hash searches" do
|
72
|
-
Backend.expects(:
|
73
|
-
Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
|
74
|
-
Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
|
75
|
-
File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
|
76
|
-
File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
|
82
|
+
Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
|
77
83
|
|
78
84
|
@cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({})
|
79
85
|
@cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
|
80
86
|
|
81
|
-
@backend.lookup("key", {}, nil, :hash).should == {"a" => "answer"}
|
87
|
+
@backend.lookup("key", {}, nil, :hash, nil).should == {"a" => "answer"}
|
82
88
|
end
|
83
89
|
|
84
90
|
it "should build a merged hash of data sources for hash searches" do
|
85
|
-
Backend.expects(:
|
86
|
-
Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
|
87
|
-
Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
|
88
|
-
File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
|
89
|
-
File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
|
91
|
+
Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
|
90
92
|
|
91
93
|
@cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
|
92
94
|
@cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"b"=>"answer", "a"=>"wrong"}})
|
93
95
|
|
94
|
-
@backend.lookup("key", {}, nil, :hash).should == {"a" => "answer", "b" => "answer"}
|
96
|
+
@backend.lookup("key", {}, nil, :hash, nil).should == {"a" => "answer", "b" => "answer"}
|
95
97
|
end
|
96
98
|
|
97
99
|
it "should fail when trying to << a Hash" do
|
98
|
-
Backend.expects(:
|
99
|
-
Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
|
100
|
-
Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
|
101
|
-
File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
|
102
|
-
File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
|
100
|
+
Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
|
103
101
|
|
104
102
|
@cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>["a", "answer"]})
|
105
103
|
@cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
|
106
104
|
|
107
|
-
expect {@backend.lookup("key", {}, nil, :array)}.to raise_error(Exception, "Hiera type mismatch: expected Array and got Hash")
|
105
|
+
expect {@backend.lookup("key", {}, nil, :array, nil)}.to raise_error(Exception, "Hiera type mismatch for key 'key': expected Array and got Hash")
|
108
106
|
end
|
109
107
|
|
110
108
|
it "should fail when trying to merge an Array" do
|
111
|
-
Backend.expects(:
|
112
|
-
Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
|
113
|
-
Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
|
114
|
-
File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
|
115
|
-
File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
|
109
|
+
Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
|
116
110
|
|
117
111
|
@cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
|
118
112
|
@cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>["a", "wrong"]})
|
119
113
|
|
120
|
-
expect { @backend.lookup("key", {}, nil, :hash) }.to raise_error(Exception, "Hiera type mismatch: expected Hash and got Array")
|
114
|
+
expect { @backend.lookup("key", {}, nil, :hash, nil) }.to raise_error(Exception, "Hiera type mismatch for key 'key': expected Hash and got Array")
|
121
115
|
end
|
122
116
|
|
123
117
|
it "should parse the answer for scope variables" do
|
124
|
-
Backend.expects(:
|
125
|
-
Backend.expects(:datafile).with(:yaml, {"rspec" => "test"}, "one", "yaml").returns("/nonexisting/one.yaml")
|
126
|
-
File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
|
118
|
+
Backend.expects(:datasourcefiles).with(:yaml, {"rspec" => "test"}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"])
|
127
119
|
|
128
120
|
@cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"test_%{rspec}"})
|
129
121
|
|
130
|
-
@backend.lookup("key", {"rspec" => "test"}, nil, :priority).should == "test_test"
|
122
|
+
@backend.lookup("key", {"rspec" => "test"}, nil, :priority, nil).should == "test_test"
|
131
123
|
end
|
132
124
|
|
133
125
|
it "should retain datatypes found in yaml files" do
|
134
|
-
Backend.expects(:
|
135
|
-
Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml").times(3)
|
136
|
-
File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
|
126
|
+
Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"]).times(3)
|
137
127
|
|
138
|
-
yaml = "---\nstringval: 'string'\nboolval: true\nnumericval: 1"
|
139
128
|
|
140
|
-
@cache.
|
129
|
+
@cache.value = "---\nstringval: 'string'\nboolval: true\nnumericval: 1"
|
141
130
|
|
142
|
-
@backend.lookup("stringval", {}, nil, :priority).should == "string"
|
143
|
-
@backend.lookup("boolval", {}, nil, :priority).should == true
|
144
|
-
@backend.lookup("numericval", {}, nil, :priority).should == 1
|
131
|
+
@backend.lookup("stringval", {}, nil, :priority, nil).should == "string"
|
132
|
+
@backend.lookup("boolval", {}, nil, :priority, nil).should == true
|
133
|
+
@backend.lookup("numericval", {}, nil, :priority, nil).should == 1
|
145
134
|
end
|
146
135
|
end
|
147
136
|
end
|