hiera 3.1.0 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +42 -0
- data/lib/hiera/backend.rb +3 -3
- data/lib/hiera/interpolate.rb +52 -37
- data/lib/hiera/util.rb +22 -0
- data/lib/hiera/version.rb +1 -1
- data/spec/unit/fixtures/interpolate/config/hiera.yaml +4 -0
- data/spec/unit/fixtures/interpolate/data/bad_interpolation.yaml +9 -0
- data/spec/unit/fixtures/interpolate/data/complex.yaml +12 -0
- data/spec/unit/fixtures/interpolate/data/dotted_keys.yaml +40 -0
- data/spec/unit/fixtures/interpolate/data/empty_interpolation.yaml +7 -0
- data/spec/unit/fixtures/interpolate/data/weird_keys.yaml +12 -0
- data/spec/unit/interpolate_spec.rb +171 -36
- metadata +21 -9
- checksums.yaml +0 -7
data/README.md
CHANGED
@@ -101,6 +101,48 @@ $ hiera ssh_users.0
|
|
101
101
|
root
|
102
102
|
</pre>
|
103
103
|
|
104
|
+
### Use quotes to disable qualified key behavior
|
105
|
+
In case you have dotted keys and thus want to avoid using the qualified key semantics, you
|
106
|
+
can put segments of a dotted key, or the whole key, within quotes.
|
107
|
+
|
108
|
+
Given the following data:
|
109
|
+
|
110
|
+
<pre>
|
111
|
+
# yaml
|
112
|
+
a:
|
113
|
+
b.c:
|
114
|
+
d: 'Data for a => b.c => d'
|
115
|
+
</pre>
|
116
|
+
|
117
|
+
it is possible to do a lookup of the data like this:
|
118
|
+
|
119
|
+
<pre>
|
120
|
+
$ hiera 'a."b.c".d'
|
121
|
+
Data for a => b.c => d
|
122
|
+
</pre>
|
123
|
+
|
124
|
+
Quoting works in interpolation expressions as well.
|
125
|
+
|
126
|
+
Interpolating from global scope:
|
127
|
+
|
128
|
+
<pre>
|
129
|
+
# yaml
|
130
|
+
other.key: 'scope data: %{a."b.c".d}'
|
131
|
+
</pre>
|
132
|
+
|
133
|
+
or using an interpolation method:
|
134
|
+
|
135
|
+
<pre>
|
136
|
+
# yaml
|
137
|
+
a:
|
138
|
+
b.c:
|
139
|
+
d: 'Data for a => b.c => d'
|
140
|
+
other.key: 'hiera data %{hiera("a.''b.c''.d")}'
|
141
|
+
</pre>
|
142
|
+
|
143
|
+
Note that two single quotes are used to escape a single quote inside a single quoted string
|
144
|
+
(that's YAML syntax, not Hiera) and that the quoted key must be quoted in turn.
|
145
|
+
|
104
146
|
## Future Enhancements
|
105
147
|
|
106
148
|
* More backends should be created
|
data/lib/hiera/backend.rb
CHANGED
@@ -231,7 +231,7 @@ class Hiera
|
|
231
231
|
# databases then do so in your constructor, future calls to your
|
232
232
|
# backend will not create new instances
|
233
233
|
|
234
|
-
# @param key [String] The key to lookup
|
234
|
+
# @param key [String] The key to lookup. May be quoted with single or double quotes to avoid subkey traversal on dot characters
|
235
235
|
# @param scope [#[]] The primary source of data for substitutions.
|
236
236
|
# @param order_override [#[],nil] An override that will be pre-pended to the hierarchy definition.
|
237
237
|
# @param resolution_type [Symbol,Hash,nil] One of :hash, :array,:priority or a Hash with deep merge behavior and options
|
@@ -250,7 +250,7 @@ class Hiera
|
|
250
250
|
|
251
251
|
strategy = resolution_type.is_a?(Hash) ? :hash : resolution_type
|
252
252
|
|
253
|
-
segments = key.
|
253
|
+
segments = Util.split_key(key) { |problem| ArgumentError.new("#{problem} in key: #{key}") }
|
254
254
|
subsegments = nil
|
255
255
|
if segments.size > 1
|
256
256
|
raise ArgumentError, "Resolution type :#{strategy} is illegal when doing segmented key lookups" unless strategy.nil? || strategy == :priority
|
@@ -265,7 +265,7 @@ class Hiera
|
|
265
265
|
found_in_backend = false
|
266
266
|
new_answer = catch(:no_such_key) do
|
267
267
|
if subsegments.nil?
|
268
|
-
value = backend.lookup(
|
268
|
+
value = backend.lookup(segments[0], scope, order_override, resolution_type, context)
|
269
269
|
elsif backend.respond_to?(:lookup_with_segments)
|
270
270
|
value = backend.lookup_with_segments(segments, scope, order_override, resolution_type, context)
|
271
271
|
else
|
data/lib/hiera/interpolate.rb
CHANGED
@@ -4,34 +4,51 @@ require 'hiera/recursive_guard'
|
|
4
4
|
|
5
5
|
class Hiera::InterpolationInvalidValue < StandardError; end
|
6
6
|
|
7
|
+
# @api private
|
7
8
|
class Hiera::Interpolate
|
9
|
+
RX_INTERPOLATION = /%\{([^\}]*)\}/
|
10
|
+
RX_ONLY_INTERPOLATION = /^%\{([^\}]*)\}$/
|
11
|
+
RX_METHOD_AND_ARG = /^(\w+)\(([^)]*)\)$/
|
12
|
+
|
13
|
+
EMPTY_INTERPOLATIONS = {
|
14
|
+
'' => true,
|
15
|
+
'::' => true,
|
16
|
+
'""' => true,
|
17
|
+
"''" => true,
|
18
|
+
'"::"' => true,
|
19
|
+
"'::'" => true
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
INTERPOLATION_METHODS = {
|
23
|
+
'hiera' => :hiera_interpolate,
|
24
|
+
'scope' => :scope_interpolate,
|
25
|
+
'literal' => :literal_interpolate,
|
26
|
+
'alias' => :alias_interpolate
|
27
|
+
}.freeze
|
28
|
+
|
8
29
|
class << self
|
30
|
+
# These two patterns are never used but kept here anyway since they used to be public and therefore
|
31
|
+
# must be considered API. The class is now marked @api private and these should be removed in a
|
32
|
+
# future version
|
33
|
+
#
|
34
|
+
# @deprecated
|
9
35
|
INTERPOLATION = /%\{([^\}]*)\}/
|
36
|
+
|
37
|
+
# @deprecated
|
10
38
|
METHOD_INTERPOLATION = /%\{(scope|hiera|literal|alias)\(['"]([^"']*)["']\)\}/
|
11
39
|
|
12
40
|
def interpolate(data, scope, extra_data, context)
|
13
41
|
if data.is_a?(String)
|
14
42
|
# Wrapping do_interpolation in a gsub block ensures we process
|
15
43
|
# each interpolation site in isolation using separate recursion guards.
|
16
|
-
context
|
17
|
-
new_context = context.clone
|
44
|
+
new_context = context.nil? ? {} : context.clone
|
18
45
|
new_context[:recurse_guard] ||= Hiera::RecursiveGuard.new
|
19
|
-
data.gsub(
|
20
|
-
interp_val = do_interpolation(match, scope, extra_data, new_context)
|
21
|
-
|
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, new_context)
|
25
|
-
else
|
26
|
-
interpolate_method = nil
|
27
|
-
end
|
46
|
+
data.gsub(RX_INTERPOLATION) do |match|
|
47
|
+
(interp_val, interpolate_method) = do_interpolation(match, scope, extra_data, new_context)
|
28
48
|
|
29
|
-
if (
|
30
|
-
if data.match(
|
31
|
-
|
32
|
-
else
|
33
|
-
raise Hiera::InterpolationInvalidValue, "Cannot call alias in the string context"
|
34
|
-
end
|
49
|
+
if (interpolate_method == :alias_interpolate) && !interp_val.is_a?(String)
|
50
|
+
return interp_val if data.match(RX_ONLY_INTERPOLATION)
|
51
|
+
raise Hiera::InterpolationInvalidValue, "Cannot call alias in the string context"
|
35
52
|
else
|
36
53
|
interp_val
|
37
54
|
end
|
@@ -42,47 +59,45 @@ class Hiera::Interpolate
|
|
42
59
|
end
|
43
60
|
|
44
61
|
def do_interpolation(data, scope, extra_data, context)
|
45
|
-
if data.is_a?(String) && (match = data.match(
|
62
|
+
if data.is_a?(String) && (match = data.match(RX_INTERPOLATION))
|
46
63
|
interpolation_variable = match[1]
|
47
64
|
|
48
65
|
# HI-494
|
49
|
-
|
50
|
-
when '', '::'
|
51
|
-
return ''
|
52
|
-
end
|
66
|
+
return ['', nil] if EMPTY_INTERPOLATIONS[interpolation_variable.strip]
|
53
67
|
|
54
68
|
context[:recurse_guard].check(interpolation_variable) do
|
55
|
-
interpolate_method, key = get_interpolation_method_and_key(
|
69
|
+
interpolate_method, key = get_interpolation_method_and_key(interpolation_variable, context)
|
56
70
|
interpolated_data = send(interpolate_method, data, key, scope, extra_data, context)
|
57
71
|
|
58
72
|
# Halt recursion if we encounter a literal.
|
59
|
-
return interpolated_data if interpolate_method == :literal_interpolate
|
73
|
+
return [interpolated_data, interpolate_method] if interpolate_method == :literal_interpolate
|
60
74
|
|
61
|
-
do_interpolation(interpolated_data, scope, extra_data, context)
|
75
|
+
[do_interpolation(interpolated_data, scope, extra_data, context)[0], interpolate_method]
|
62
76
|
end
|
63
77
|
else
|
64
|
-
data
|
78
|
+
[data, nil]
|
65
79
|
end
|
66
80
|
end
|
67
81
|
private :do_interpolation
|
68
82
|
|
69
|
-
def get_interpolation_method_and_key(
|
70
|
-
if (match =
|
83
|
+
def get_interpolation_method_and_key(interpolation_variable, context)
|
84
|
+
if (match = interpolation_variable.match(RX_METHOD_AND_ARG))
|
71
85
|
Hiera.warn('Use of interpolation methods in hiera configuration file is deprecated') if context[:is_interpolate_config]
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
86
|
+
method = match[1]
|
87
|
+
method_sym = INTERPOLATION_METHODS[method]
|
88
|
+
raise Hiera::InterpolationInvalidValue, "Invalid interpolation method '#{method}'" unless method_sym
|
89
|
+
arg = match[2]
|
90
|
+
match_data = arg.match(Hiera::QUOTED_KEY)
|
91
|
+
raise Hiera::InterpolationInvalidValue, "Argument to interpolation method '#{method}' must be quoted, got '#{arg}'" unless match_data
|
92
|
+
[method_sym, match_data[1] || match_data[2]]
|
93
|
+
else
|
94
|
+
[:scope_interpolate, interpolation_variable]
|
80
95
|
end
|
81
96
|
end
|
82
97
|
private :get_interpolation_method_and_key
|
83
98
|
|
84
99
|
def scope_interpolate(data, key, scope, extra_data, context)
|
85
|
-
segments = key.
|
100
|
+
segments = Hiera::Util.split_key(key) { |problem| Hiera::InterpolationInvalidValue.new("#{problem} in interpolation expression: #{data}") }
|
86
101
|
catch(:no_such_key) { return Hiera::Backend.qualified_lookup(segments, scope) }
|
87
102
|
catch(:no_such_key) { Hiera::Backend.qualified_lookup(segments, extra_data) }
|
88
103
|
end
|
data/lib/hiera/util.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
class Hiera
|
2
|
+
|
3
|
+
# Matches a key that is quoted using a matching pair of either single or double quotes.
|
4
|
+
QUOTED_KEY = /^(?:"([^"]+)"|'([^']+)')$/
|
5
|
+
QUOTES = /[",]/
|
6
|
+
|
2
7
|
module Util
|
3
8
|
module_function
|
4
9
|
|
@@ -42,6 +47,23 @@ class Hiera
|
|
42
47
|
def common_appdata
|
43
48
|
Dir::COMMON_APPDATA
|
44
49
|
end
|
50
|
+
|
51
|
+
def split_key(key)
|
52
|
+
segments = key.split(/(?:"([^"]+)"|'([^']+)'|([^'".]+))/)
|
53
|
+
if segments.empty?
|
54
|
+
# Only happens if the original key was an empty string
|
55
|
+
''
|
56
|
+
elsif segments.shift == ''
|
57
|
+
count = segments.size
|
58
|
+
raise yield('Syntax error') unless count > 0
|
59
|
+
|
60
|
+
segments.keep_if { |seg| seg != '.' }
|
61
|
+
raise yield('Syntax error') unless segments.size * 2 == count + 1
|
62
|
+
segments
|
63
|
+
else
|
64
|
+
raise yield('Syntax error')
|
65
|
+
end
|
66
|
+
end
|
45
67
|
end
|
46
68
|
end
|
47
69
|
|
data/lib/hiera/version.rb
CHANGED
@@ -0,0 +1,9 @@
|
|
1
|
+
---
|
2
|
+
quote_mismatch: 'Key delimited with singe quote on one side aand double qoute on the other: %{''the.key"}'
|
3
|
+
quote_mismatch_arg: 'Arg delimited with singe quote on one side and double qoute on the other: %{hiera(''the.key")}'
|
4
|
+
non_existing_method: 'The method flubber does not exist: %{flubber("hello")}'
|
5
|
+
|
6
|
+
one_quote: 'Key with only one quote: %{the.''key}'
|
7
|
+
empty_segment: 'Key with only one quote: %{the..key}'
|
8
|
+
empty_quoted_segment: 'Key with only one quote: %{the.''''.key}'
|
9
|
+
partly_quoted_segment: 'Key with only one quote: %{the.''pa''key}'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
---
|
2
|
+
a.b: '(hiera) a dot b'
|
3
|
+
a.c.scope: "a dot c: %{'a.b'}"
|
4
|
+
a.c.hiera: 'a dot c: %{hiera("''a.b''")}'
|
5
|
+
a.c.scope: "a dot c: %{'a.b'}"
|
6
|
+
a.c.hiera: 'a dot c: %{hiera("''a.b''")}'
|
7
|
+
a.c.alias: '%{alias("''a.b''")}'
|
8
|
+
a:
|
9
|
+
d: '(hiera) a dot d is a hash entry'
|
10
|
+
d.x: '(hiera) a dot d.x is a hash entry'
|
11
|
+
d.z:
|
12
|
+
g: '(hiera) a dot d.z dot g is a hash entry'
|
13
|
+
|
14
|
+
a.x:
|
15
|
+
d: '(hiera) a.x dot d is a hash entry'
|
16
|
+
d.x: '(hiera) a.x dot d.x is a hash entry'
|
17
|
+
d.z:
|
18
|
+
g: '(hiera) a.x dot d.z dot g is a hash entry'
|
19
|
+
|
20
|
+
a.e.scope: "a dot e: %{a.d}"
|
21
|
+
a.e.hiera: "a dot e: %{hiera('a.d')}"
|
22
|
+
|
23
|
+
a.ex.scope: "a dot ex: %{a.'d.x'}"
|
24
|
+
a.ex.hiera: 'a dot ex: %{hiera("a.''d.x''")}'
|
25
|
+
|
26
|
+
a.xe.scope: "a dot xe: %{'a.x'.d}"
|
27
|
+
a.xe.hiera: 'a dot xe: %{hiera("''a.x''.d")}'
|
28
|
+
|
29
|
+
a.xm.scope: "a dot xm: %{a.'d.z'.g}"
|
30
|
+
a.xm.hiera: 'a dot xm: %{hiera("a.''d.z''.g")}'
|
31
|
+
|
32
|
+
a.xx.scope: "a dot xx: %{'a.x'.'d.z'.g}"
|
33
|
+
a.xx.hiera: 'a dot xx: %{hiera("''a.x''.''d.z''.g")}'
|
34
|
+
|
35
|
+
a.f.scope: "a dot f: %{'a.d'}"
|
36
|
+
a.f.hiera: 'a dot f: %{hiera("''a.d''")}'
|
37
|
+
|
38
|
+
x.1: '(hiera) x dot 1'
|
39
|
+
x.2.scope: "x dot 2: %{'x.1'}"
|
40
|
+
x.2.hiera: 'x dot 2: %{hiera("''x.1''")}'
|
@@ -4,3 +4,10 @@ only_empty_interpolation: '%{}'
|
|
4
4
|
empty_namespace: '%{::}'
|
5
5
|
whitespace1: '%{ :: }'
|
6
6
|
whitespace2: '%{ }'
|
7
|
+
|
8
|
+
quoted_empty_interpolation: 'clown%{""}shoe'
|
9
|
+
quoted_escaped_empty_interpolation: 'clown%%{""}{shoe}s'
|
10
|
+
quoted_only_empty_interpolation: '%{""}'
|
11
|
+
quoted_empty_namespace: '%{"::"}'
|
12
|
+
quoted_whitespace1: '%{ "::" }'
|
13
|
+
quoted_whitespace2: '%{ "" }'
|
@@ -2,98 +2,233 @@ require 'spec_helper'
|
|
2
2
|
require 'hiera/util'
|
3
3
|
|
4
4
|
describe "Hiera" do
|
5
|
-
|
6
|
-
|
5
|
+
let!(:fixtures) { File.join(HieraSpec::FIXTURE_DIR, 'interpolate') }
|
6
|
+
let!(:fixture_data) { File.join(fixtures, 'data') }
|
7
|
+
let(:hiera) { Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml')) }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
Hiera::Util.expects(:var_dir).at_most(3).returns(fixture_data)
|
11
|
+
end
|
7
12
|
|
13
|
+
context "when doing interpolation" do
|
8
14
|
it 'should prevent endless recursion' do
|
9
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
10
15
|
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
11
16
|
expect do
|
12
17
|
hiera.lookup('foo', nil, {})
|
13
18
|
end.to raise_error Hiera::InterpolationLoop, 'Lookup recursion detected in [hiera("bar"), hiera("foo")]'
|
14
19
|
end
|
20
|
+
|
21
|
+
it 'produces a nested hash with arrays from nested aliases with hashes and arrays' do
|
22
|
+
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
23
|
+
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
24
|
+
expect(hiera.lookup('root', nil, {}, nil, :hash)).to eq({'a'=>{'aa'=>{'b'=>{'bb'=>['text']}}}})
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'allows keys with white space' do
|
28
|
+
expect(hiera.lookup('ws_key', nil, {})).to eq('value for a ws key')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'allows keys with non alphanumeric characters' do
|
32
|
+
expect(hiera.lookup('angry', nil, {})).to eq('not happy')
|
33
|
+
end
|
15
34
|
end
|
16
35
|
|
17
36
|
context "when not finding value for interpolated key" do
|
18
|
-
let(:fixtures) { File.join(HieraSpec::FIXTURE_DIR, 'interpolate') }
|
19
|
-
|
20
37
|
it 'should resolve the interpolation to an empty string' do
|
21
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
22
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
23
38
|
expect(hiera.lookup('niltest', nil, {})).to eq('Missing key ##. Key with nil ##')
|
24
39
|
end
|
25
40
|
end
|
26
41
|
|
27
42
|
context "when there are empty interpolations %{} in data" do
|
28
|
-
let(:fixtures) { File.join(HieraSpec::FIXTURE_DIR, 'interpolate') }
|
29
|
-
|
30
43
|
it 'should should produce an empty string for the interpolation' do
|
31
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
32
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
33
44
|
expect(hiera.lookup('empty_interpolation', nil, {})).to eq('clownshoe')
|
34
45
|
end
|
35
46
|
|
36
47
|
it 'the empty interpolation can be escaped' do
|
37
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
38
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
39
48
|
expect(hiera.lookup('escaped_empty_interpolation', nil, {})).to eq('clown%{shoe}s')
|
40
49
|
end
|
41
50
|
|
42
51
|
it 'the value can consist of only an empty escape' do
|
43
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
44
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
45
52
|
expect(hiera.lookup('only_empty_interpolation', nil, {})).to eq('')
|
46
53
|
end
|
47
54
|
|
48
55
|
it 'the value can consist of an empty namespace %{::}' do
|
49
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
50
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
51
56
|
expect(hiera.lookup('empty_namespace', nil, {})).to eq('')
|
52
57
|
end
|
53
58
|
|
54
59
|
it 'the value can consist of whitespace %{ :: }' do
|
55
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
56
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
57
60
|
expect(hiera.lookup('whitespace1', nil, {})).to eq('')
|
58
61
|
end
|
59
62
|
|
60
63
|
it 'the value can consist of whitespace %{ }' do
|
61
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
62
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
63
64
|
expect(hiera.lookup('whitespace2', nil, {})).to eq('')
|
64
65
|
end
|
65
66
|
end
|
66
67
|
|
67
|
-
context
|
68
|
-
|
68
|
+
context 'when there are quoted empty interpolations %{} in data' do
|
69
|
+
it 'should should produce an empty string for the interpolation' do
|
70
|
+
expect(hiera.lookup('quoted_empty_interpolation', nil, {})).to eq('clownshoe')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'the empty interpolation can be escaped' do
|
74
|
+
expect(hiera.lookup('quoted_escaped_empty_interpolation', nil, {})).to eq('clown%{shoe}s')
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'the value can consist of only an empty escape' do
|
78
|
+
expect(hiera.lookup('quoted_only_empty_interpolation', nil, {})).to eq('')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'the value can consist of an empty namespace %{::}' do
|
82
|
+
expect(hiera.lookup('quoted_empty_namespace', nil, {})).to eq('')
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'the value can consist of whitespace %{ :: }' do
|
86
|
+
expect(hiera.lookup('quoted_whitespace1', nil, {})).to eq('')
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'the value can consist of whitespace %{ }' do
|
90
|
+
expect(hiera.lookup('quoted_whitespace2', nil, {})).to eq('')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when using dotted keys' do
|
95
|
+
it 'should find an entry using a quoted interpolation' do
|
96
|
+
expect(hiera.lookup('"a.c.scope"', nil, {'a.b' => '(scope) a dot b'})).to eq('a dot c: (scope) a dot b')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should find an entry using a quoted interpolation with method hiera' do
|
100
|
+
expect(hiera.lookup('"a.c.hiera"', nil, {'a.b' => '(scope) a dot b'})).to eq('a dot c: (hiera) a dot b')
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should find an entry using a quoted interpolation with method alias' do
|
104
|
+
expect(hiera.lookup('"a.c.alias"', nil, {'a.b' => '(scope) a dot b'})).to eq('(hiera) a dot b')
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should use a dotted key to navigate into a structure when it is not quoted' do
|
108
|
+
expect(hiera.lookup('"a.e.scope"', nil, {'a' => { 'd' => '(scope) a dot d is a hash entry'}})).to eq('a dot e: (scope) a dot d is a hash entry')
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should use a dotted key to navigate into a structure when when it is not quoted with method hiera' do
|
112
|
+
expect(hiera.lookup('"a.e.hiera"', nil, {'a' => { 'd' => '(scope) a dot d is a hash entry'}})).to eq('a dot e: (hiera) a dot d is a hash entry')
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is last' do
|
116
|
+
expect(hiera.lookup('"a.ex.scope"', nil, {'a' => { 'd.x' => '(scope) a dot d.x is a hash entry'}})).to eq('a dot ex: (scope) a dot d.x is a hash entry')
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is last and method is hiera' do
|
120
|
+
expect(hiera.lookup('"a.ex.hiera"', nil, {'a' => { 'd.x' => '(scope) a dot d.x is a hash entry'}})).to eq('a dot ex: (hiera) a dot d.x is a hash entry')
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is first' do
|
124
|
+
expect(hiera.lookup('"a.xe.scope"', nil, {'a.x' => { 'd' => '(scope) a.x dot d is a hash entry'}})).to eq('a dot xe: (scope) a.x dot d is a hash entry')
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is first and method is hiera' do
|
128
|
+
expect(hiera.lookup('"a.xe.hiera"', nil, {'a.x' => { 'd' => '(scope) a.x dot d is a hash entry'}})).to eq('a dot xe: (hiera) a.x dot d is a hash entry')
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is in the middle' do
|
132
|
+
expect(hiera.lookup('"a.xm.scope"', nil, {'a' => { 'd.z' => { 'g' => '(scope) a dot d.z dot g is a hash entry'}}})).to eq('a dot xm: (scope) a dot d.z dot g is a hash entry')
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is in the middle and method is hiera' do
|
136
|
+
expect(hiera.lookup('"a.xm.hiera"', nil, {'a' => { 'd.z' => { 'g' => '(scope) a dot d.z dot g is a hash entry'}}})).to eq('a dot xm: (hiera) a dot d.z dot g is a hash entry')
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should use a mix of several quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is in the middle' do
|
140
|
+
expect(hiera.lookup('"a.xx.scope"', nil, {'a.x' => { 'd.z' => { 'g' => '(scope) a.x dot d.z dot g is a hash entry'}}})).to eq('a dot xx: (scope) a.x dot d.z dot g is a hash entry')
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should use a mix of several quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is in the middle and method is hiera' do
|
144
|
+
expect(hiera.lookup('"a.xx.hiera"', nil, {'a.x' => { 'd.z' => { 'g' => '(scope) a.x dot d.z dot g is a hash entry'}}})).to eq('a dot xx: (hiera) a.x dot d.z dot g is a hash entry')
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should find an entry using using a quoted interpolation on dotted key containing numbers' do
|
148
|
+
expect(hiera.lookup('"x.2.scope"', nil, {'x.1' => '(scope) x dot 1'})).to eq('x dot 2: (scope) x dot 1')
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should find an entry using using a quoted interpolation on dotted key containing numbers using method hiera' do
|
152
|
+
expect(hiera.lookup('"x.2.hiera"', nil, {'x.1' => '(scope) x dot 1'})).to eq('x dot 2: (hiera) x dot 1')
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'will allow strange characters in the key' do
|
156
|
+
expect(hiera.lookup('very_angry', nil, {})).to eq('not happy at all')
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should not find a subkey when the dotted key is quoted' do
|
160
|
+
expect(hiera.lookup('"a.f.scope"', nil, {'a' => { 'f' => '(scope) a dot f is a hash entry'}})).to eq('a dot f: ')
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should not find a subkey when the dotted key is quoted with method hiera' do
|
164
|
+
expect(hiera.lookup('"a.f.hiera"', nil, {'a' => { 'f' => '(scope) a dot f is a hash entry'}})).to eq('a dot f: ')
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'when bad interpolation expressions are encountered' do
|
169
|
+
it 'should produce an error when different quotes are used on either side' do
|
170
|
+
expect { hiera.lookup('quote_mismatch', nil, {}) }.to raise_error(/Syntax error in interpolation expression: \%\{'the\.key"\}/)
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should produce an if there is only one quote' do
|
174
|
+
expect { hiera.lookup('one_quote', nil, {}) }.to raise_error(/Syntax error in interpolation expression: \%\{the\.'key\}/)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should produce an error for an empty segment' do
|
178
|
+
expect { hiera.lookup('empty_segment', nil, {}) }.to raise_error(/Syntax error in interpolation expression: \%\{the\.\.key\}/)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should produce an error for an empty quoted segment' do
|
182
|
+
expect { hiera.lookup('empty_quoted_segment', nil, {}) }.to raise_error(/Syntax error in interpolation expression: \%\{the\.''\.key\}/)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should produce an error for an partly quoted segment' do
|
186
|
+
expect { hiera.lookup('partly_quoted_segment', nil, {}) }.to raise_error(/Syntax error in interpolation expression: \%\{the\.'pa'key\}/)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should produce an error when different quotes are used on either side in a method argument' do
|
190
|
+
expect { hiera.lookup('quote_mismatch_arg', nil, {}) }.to raise_error(/Argument to interpolation method 'hiera' must be quoted, got ''the.key"'/)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should produce an error unless a known interpolation method is used' do
|
194
|
+
expect { hiera.lookup('non_existing_method', nil, {}) }.to raise_error(/Invalid interpolation method 'flubber'/)
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should produce an error if there is only one quote' do
|
198
|
+
expect { hiera.lookup('one_quote', nil, {}) }.to raise_error(/Syntax error/)
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'should produce an error when different quotes are used on either side in a top-level key' do
|
202
|
+
expect { hiera.lookup("'the.key\"", nil, {}) }.to raise_error(/Syntax error in key: 'the.key"/)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'when doing interpolation with override' do
|
207
|
+
let!(:fixtures) { File.join(HieraSpec::FIXTURE_DIR, 'override') }
|
69
208
|
|
70
209
|
it 'should resolve interpolation using the override' do
|
71
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
72
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera.yaml'))
|
73
210
|
expect(hiera.lookup('foo', nil, {}, 'alternate')).to eq('alternate')
|
74
211
|
end
|
75
212
|
end
|
76
213
|
|
77
214
|
context 'when doing interpolation in config file' do
|
78
|
-
let(:
|
215
|
+
let(:hiera) { Hiera.new(:config => File.join(fixtures, 'config', 'hiera_iplm_hiera.yaml')) }
|
79
216
|
|
80
217
|
it 'should allow and resolve a correctly configured interpolation using "hiera" method' do
|
81
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
82
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera_iplm_hiera.yaml'))
|
83
218
|
expect(hiera.lookup('foo', nil, {})).to eq('Foo')
|
84
219
|
end
|
85
220
|
|
86
|
-
it 'should detect interpolation recursion when using "hiera" method' do
|
87
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
88
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera_iplm_hiera_bad.yaml'))
|
89
|
-
expect{ hiera.lookup('foo', nil, {}) }.to raise_error(Hiera::InterpolationLoop, "Lookup recursion detected in [hiera('role')]")
|
90
|
-
end
|
91
|
-
|
92
221
|
it 'should issue warning when interpolation methods are used' do
|
93
222
|
Hiera.expects(:warn).with('Use of interpolation methods in hiera configuration file is deprecated').at_least_once
|
94
|
-
Hiera::Util.expects(:var_dir).at_least_once.returns(File.join(fixtures, 'data'))
|
95
|
-
hiera = Hiera.new(:config => File.join(fixtures, 'config', 'hiera_iplm_hiera.yaml'))
|
96
223
|
expect(hiera.lookup('foo', nil, {})).to eq('Foo')
|
97
224
|
end
|
98
225
|
end
|
226
|
+
|
227
|
+
context 'when doing interpolation in bad config file' do
|
228
|
+
let(:hiera) { Hiera.new(:config => File.join(fixtures, 'config', 'hiera_iplm_hiera_bad.yaml')) }
|
229
|
+
|
230
|
+
it 'should detect interpolation recursion when using "hiera" method' do
|
231
|
+
expect{ hiera.lookup('foo', nil, {}) }.to raise_error(Hiera::InterpolationLoop, "Lookup recursion detected in [hiera('role')]")
|
232
|
+
end
|
233
|
+
end
|
99
234
|
end
|
metadata
CHANGED
@@ -1,27 +1,30 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hiera
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.1
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Puppet Labs
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
12
|
+
date: 2016-03-23 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: json_pure
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- - '>='
|
19
|
+
- - ! '>='
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: '0'
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
|
-
- - '>='
|
27
|
+
- - ! '>='
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '0'
|
27
30
|
description: A pluggable data store for hierarcical data
|
@@ -61,11 +64,15 @@ files:
|
|
61
64
|
- spec/unit/fixtures/interpolate/config/hiera.yaml
|
62
65
|
- spec/unit/fixtures/interpolate/config/hiera_iplm_hiera.yaml
|
63
66
|
- spec/unit/fixtures/interpolate/config/hiera_iplm_hiera_bad.yaml
|
67
|
+
- spec/unit/fixtures/interpolate/data/bad_interpolation.yaml
|
68
|
+
- spec/unit/fixtures/interpolate/data/complex.yaml
|
69
|
+
- spec/unit/fixtures/interpolate/data/dotted_keys.yaml
|
64
70
|
- spec/unit/fixtures/interpolate/data/empty_interpolation.yaml
|
65
71
|
- spec/unit/fixtures/interpolate/data/frontend.json
|
66
72
|
- spec/unit/fixtures/interpolate/data/niltest.yaml
|
67
73
|
- spec/unit/fixtures/interpolate/data/recursive.yaml
|
68
74
|
- spec/unit/fixtures/interpolate/data/role.json
|
75
|
+
- spec/unit/fixtures/interpolate/data/weird_keys.yaml
|
69
76
|
- spec/unit/fixtures/override/config/hiera.yaml
|
70
77
|
- spec/unit/fixtures/override/data/alternate.yaml
|
71
78
|
- spec/unit/fixtures/override/data/common.yaml
|
@@ -76,26 +83,27 @@ files:
|
|
76
83
|
- spec/unit/version_spec.rb
|
77
84
|
homepage: https://github.com/puppetlabs/hiera
|
78
85
|
licenses: []
|
79
|
-
metadata: {}
|
80
86
|
post_install_message:
|
81
87
|
rdoc_options: []
|
82
88
|
require_paths:
|
83
89
|
- lib
|
84
90
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
85
92
|
requirements:
|
86
|
-
- - '>='
|
93
|
+
- - ! '>='
|
87
94
|
- !ruby/object:Gem::Version
|
88
95
|
version: '0'
|
89
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
90
98
|
requirements:
|
91
|
-
- - '>='
|
99
|
+
- - ! '>='
|
92
100
|
- !ruby/object:Gem::Version
|
93
101
|
version: '0'
|
94
102
|
requirements: []
|
95
103
|
rubyforge_project:
|
96
|
-
rubygems_version:
|
104
|
+
rubygems_version: 1.8.23
|
97
105
|
signing_key:
|
98
|
-
specification_version:
|
106
|
+
specification_version: 3
|
99
107
|
summary: Light weight hierarchical data store
|
100
108
|
test_files:
|
101
109
|
- spec/spec_helper.rb
|
@@ -109,11 +117,15 @@ test_files:
|
|
109
117
|
- spec/unit/fixtures/interpolate/config/hiera.yaml
|
110
118
|
- spec/unit/fixtures/interpolate/config/hiera_iplm_hiera.yaml
|
111
119
|
- spec/unit/fixtures/interpolate/config/hiera_iplm_hiera_bad.yaml
|
120
|
+
- spec/unit/fixtures/interpolate/data/bad_interpolation.yaml
|
121
|
+
- spec/unit/fixtures/interpolate/data/complex.yaml
|
122
|
+
- spec/unit/fixtures/interpolate/data/dotted_keys.yaml
|
112
123
|
- spec/unit/fixtures/interpolate/data/empty_interpolation.yaml
|
113
124
|
- spec/unit/fixtures/interpolate/data/frontend.json
|
114
125
|
- spec/unit/fixtures/interpolate/data/niltest.yaml
|
115
126
|
- spec/unit/fixtures/interpolate/data/recursive.yaml
|
116
127
|
- spec/unit/fixtures/interpolate/data/role.json
|
128
|
+
- spec/unit/fixtures/interpolate/data/weird_keys.yaml
|
117
129
|
- spec/unit/fixtures/override/config/hiera.yaml
|
118
130
|
- spec/unit/fixtures/override/data/alternate.yaml
|
119
131
|
- spec/unit/fixtures/override/data/common.yaml
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: b028f3d8c5d7d62503173b3a2460efe345866293
|
4
|
-
data.tar.gz: 6fd01d4e6590e18449bc6a70a43c46288e55e7ce
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: 35c2f04b974c34ea63366d97b9f74a90bbaba1ee9c6ff6a4189e8965d9bcc72edfe94b944b03d56fc14f059566e5a6570acf086c0396ec91689af49cc8e9f6da
|
7
|
-
data.tar.gz: 0a5dfdc722e1c800339811f74a6e76354b380681f6d727f33285e383ff2a049bac1acaaface1705afea3e8c4e3f8cf205f7d935157f95419962593646877d39c
|