hiera-puppet 0.3.0 → 1.0.0rc2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/extlookup2hiera +26 -26
- data/lib/hiera/backend/puppet_backend.rb +87 -75
- data/lib/hiera/scope.rb +40 -39
- data/lib/hiera_puppet.rb +89 -0
- data/lib/puppet/parser/functions/hiera.rb +6 -43
- data/lib/puppet/parser/functions/hiera_array.rb +6 -34
- data/lib/puppet/parser/functions/hiera_hash.rb +6 -34
- data/lib/puppet/parser/functions/hiera_include.rb +9 -35
- data/spec/helpers.rb +0 -0
- data/spec/spec_helper.rb +6 -12
- data/spec/unit/hiera/backend/puppet_backend_spec.rb +143 -0
- data/spec/unit/hiera/scope_spec.rb +64 -0
- data/spec/unit/hiera_puppet_spec.rb +105 -0
- data/spec/unit/puppet/parser/functions/hiera_array_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/hiera_hash_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/hiera_include_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/hiera_spec.rb +21 -0
- data/spec/watchr.rb +79 -0
- metadata +36 -18
- data/spec/unit/puppet_backend_spec.rb +0 -118
- data/spec/unit/scope_spec.rb +0 -64
data/bin/extlookup2hiera
CHANGED
@@ -6,51 +6,51 @@ require 'csv'
|
|
6
6
|
options = {:in => nil, :out => nil, :format => :yaml}
|
7
7
|
|
8
8
|
OptionParser.new do |opts|
|
9
|
-
|
9
|
+
opts.banner = "Converter for extlookup CSV files into Hiera JSON and YAML files"
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
opts.on("--in FILE", "-i", "Input CSV file") do |v|
|
12
|
+
options[:in] = v
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
opts.on("--out FILE", "-o", "Output Hiera file") do |v|
|
16
|
+
options[:out] = v
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
opts.on("--json", "-j", "Create JSON format file") do |v|
|
20
|
+
options[:format] = :json
|
21
|
+
end
|
22
22
|
end.parse!
|
23
23
|
|
24
24
|
if options[:in].nil? || options[:out].nil?
|
25
|
-
|
26
|
-
|
25
|
+
STDERR.puts "Please specify an input and output file with --in and --out"
|
26
|
+
exit 1
|
27
27
|
end
|
28
28
|
|
29
29
|
unless File.exist?(options[:in])
|
30
|
-
|
31
|
-
|
30
|
+
STDERR.puts "Cannot find input file #{options[:in]}"
|
31
|
+
exit 1
|
32
32
|
end
|
33
33
|
|
34
34
|
csvdata = CSV.read(options[:in])
|
35
35
|
hieradata = {}
|
36
36
|
|
37
37
|
csvdata.each do |d|
|
38
|
-
|
38
|
+
d = d.map{|item| item.to_s}
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
if d.size > 2
|
41
|
+
hieradata[d[0]] = d[1, d.size].flatten
|
42
|
+
else
|
43
|
+
hieradata[d[0]] = d[1]
|
44
|
+
end
|
45
45
|
end
|
46
46
|
|
47
47
|
case options[:format]
|
48
48
|
when :yaml
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
require 'yaml'
|
50
|
+
File.open(options[:out], "w") {|f| f.write hieradata.to_yaml}
|
52
51
|
when :json
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
require 'rubygems'
|
53
|
+
require 'json'
|
54
|
+
File.open(options[:out], "w") {|f| f.write JSON.pretty_generate hieradata}
|
56
55
|
end
|
56
|
+
|
@@ -1,90 +1,102 @@
|
|
1
1
|
class Hiera
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
module Backend
|
3
|
+
class Puppet_backend
|
4
|
+
def initialize
|
5
|
+
Hiera.debug("Hiera Puppet backend starting")
|
6
|
+
end
|
7
|
+
|
8
|
+
def hierarchy(scope, override)
|
9
|
+
begin
|
10
|
+
data_class = Config[:puppet][:datasource] || "data"
|
11
|
+
rescue
|
12
|
+
data_class = "data"
|
13
|
+
end
|
7
14
|
|
8
|
-
|
9
|
-
|
10
|
-
data_class = Config[:puppet][:datasource] || "data"
|
11
|
-
rescue
|
12
|
-
data_class = "data"
|
13
|
-
end
|
15
|
+
calling_class = scope.resource.name.to_s.downcase
|
16
|
+
calling_module = calling_class.split("::").first
|
14
17
|
|
15
|
-
|
16
|
-
calling_module = calling_class.split("::").first
|
18
|
+
hierarchy = Config[:hierarchy] || [calling_class, calling_module]
|
17
19
|
|
18
|
-
|
20
|
+
hierarchy = [hierarchy].flatten.map do |klass|
|
21
|
+
klass = Backend.parse_string(klass, scope,
|
22
|
+
{
|
23
|
+
"calling_class" => calling_class,
|
24
|
+
"calling_module" => calling_module
|
25
|
+
}
|
26
|
+
)
|
19
27
|
|
20
|
-
|
21
|
-
klass = Backend.parse_string(klass, scope, {"calling_class" => calling_class, "calling_module" => calling_module})
|
28
|
+
next if klass == ""
|
22
29
|
|
23
|
-
|
30
|
+
[data_class, klass].join("::")
|
31
|
+
end.compact
|
24
32
|
|
25
|
-
|
26
|
-
end.compact
|
33
|
+
hierarchy << [calling_class, data_class].join("::")
|
27
34
|
|
28
|
-
|
29
|
-
|
35
|
+
unless calling_module == calling_class
|
36
|
+
hierarchy << [calling_module, data_class].join("::")
|
37
|
+
end
|
30
38
|
|
31
|
-
|
39
|
+
hierarchy.insert(0, [data_class, override].join("::")) if override
|
32
40
|
|
33
|
-
|
34
|
-
|
41
|
+
hierarchy
|
42
|
+
end
|
43
|
+
|
44
|
+
def lookup(key, scope, order_override, resolution_type)
|
45
|
+
answer = nil
|
46
|
+
|
47
|
+
Hiera.debug("Looking up #{key} in Puppet backend")
|
48
|
+
|
49
|
+
include_class = Puppet::Parser::Functions.function(:include)
|
50
|
+
loaded_classes = scope.catalog.classes
|
35
51
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
when :array
|
76
|
-
answer << Backend.parse_answer(temp_answer, scope)
|
77
|
-
else
|
78
|
-
answer = Backend.parse_answer(temp_answer, scope)
|
79
|
-
break
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
answer = nil if answer == :undefined
|
85
|
-
|
86
|
-
answer
|
52
|
+
hierarchy(scope, order_override).each do |klass|
|
53
|
+
Hiera.debug("Looking for data in #{klass}")
|
54
|
+
|
55
|
+
varname = [klass, key].join("::")
|
56
|
+
temp_answer = nil
|
57
|
+
|
58
|
+
unless loaded_classes.include?(klass)
|
59
|
+
begin
|
60
|
+
if scope.respond_to?(:function_include)
|
61
|
+
scope.function_include(klass)
|
62
|
+
else
|
63
|
+
scope.real.function_include(klass)
|
64
|
+
end
|
65
|
+
|
66
|
+
temp_answer = scope[varname]
|
67
|
+
Hiera.debug("Found data in class #{klass}")
|
68
|
+
rescue
|
69
|
+
end
|
70
|
+
else
|
71
|
+
temp_answer = scope[varname]
|
72
|
+
end
|
73
|
+
|
74
|
+
next if temp_answer == :undefined
|
75
|
+
|
76
|
+
if temp_answer
|
77
|
+
# For array resolution we just append to the array whatever we
|
78
|
+
# find, we then go onto the next file and keep adding to the array.
|
79
|
+
#
|
80
|
+
# For priority searches we break after the first found data item.
|
81
|
+
case resolution_type
|
82
|
+
when :array
|
83
|
+
answer ||= []
|
84
|
+
answer << Backend.parse_answer(temp_answer, scope)
|
85
|
+
when :hash
|
86
|
+
answer ||= {}
|
87
|
+
answer = Backend.parse_answer(temp_answer, scope).merge answer
|
88
|
+
else
|
89
|
+
answer = Backend.parse_answer(temp_answer, scope)
|
90
|
+
break
|
87
91
|
end
|
92
|
+
end
|
88
93
|
end
|
94
|
+
|
95
|
+
answer = nil if answer == :undefined
|
96
|
+
|
97
|
+
answer
|
98
|
+
end
|
89
99
|
end
|
100
|
+
end
|
90
101
|
end
|
102
|
+
|
data/lib/hiera/scope.rb
CHANGED
@@ -1,41 +1,42 @@
|
|
1
1
|
class Hiera
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
def include?(key)
|
24
|
-
return true if ["calling_class", "calling_module"].include?(key)
|
25
|
-
|
26
|
-
return @real.lookupvar(key) != ""
|
27
|
-
end
|
28
|
-
|
29
|
-
def catalog
|
30
|
-
@real.catalog
|
31
|
-
end
|
32
|
-
|
33
|
-
def resource
|
34
|
-
@real.resource
|
35
|
-
end
|
36
|
-
|
37
|
-
def compiler
|
38
|
-
@real.compiler
|
39
|
-
end
|
2
|
+
class Scope
|
3
|
+
attr_reader :real
|
4
|
+
|
5
|
+
def initialize(real)
|
6
|
+
@real = real
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
if key == "calling_class"
|
11
|
+
ans = @real.resource.name.to_s.downcase
|
12
|
+
elsif key == "calling_module"
|
13
|
+
ans = @real.resource.name.to_s.downcase.split("::").first
|
14
|
+
else
|
15
|
+
ans = @real.lookupvar(key)
|
16
|
+
end
|
17
|
+
|
18
|
+
# damn you puppet visual basic style variables.
|
19
|
+
return nil if ans == ""
|
20
|
+
return ans
|
40
21
|
end
|
41
|
-
|
22
|
+
|
23
|
+
def include?(key)
|
24
|
+
return true if ["calling_class", "calling_module"].include?(key)
|
25
|
+
|
26
|
+
return @real.lookupvar(key) != ""
|
27
|
+
end
|
28
|
+
|
29
|
+
def catalog
|
30
|
+
@real.catalog
|
31
|
+
end
|
32
|
+
|
33
|
+
def resource
|
34
|
+
@real.resource
|
35
|
+
end
|
36
|
+
|
37
|
+
def compiler
|
38
|
+
@real.compiler
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
data/lib/hiera_puppet.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'hiera'
|
2
|
+
require 'hiera/scope'
|
3
|
+
require 'puppet'
|
4
|
+
|
5
|
+
module HieraPuppet
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def lookup(key, default, scope, override, resolution_type)
|
9
|
+
unless scope.respond_to?("[]")
|
10
|
+
scope = Hiera::Scope.new(scope)
|
11
|
+
end
|
12
|
+
|
13
|
+
answer = hiera.lookup(key, default, scope, override, resolution_type)
|
14
|
+
|
15
|
+
if answer.nil?
|
16
|
+
raise(Puppet::ParseError, "Could not find data item #{key} in any Hiera data file and no default supplied")
|
17
|
+
end
|
18
|
+
|
19
|
+
answer
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_args(args)
|
23
|
+
# Functions called from Puppet manifests like this:
|
24
|
+
#
|
25
|
+
# hiera("foo", "bar")
|
26
|
+
#
|
27
|
+
# Are invoked internally after combining the positional arguments into a
|
28
|
+
# single array:
|
29
|
+
#
|
30
|
+
# func = function_hiera
|
31
|
+
# func(["foo", "bar"])
|
32
|
+
#
|
33
|
+
# Functions called from templates preserve the positional arguments:
|
34
|
+
#
|
35
|
+
# scope.function_hiera("foo", "bar")
|
36
|
+
#
|
37
|
+
# Deal with Puppet's special calling mechanism here.
|
38
|
+
if args[0].is_a?(Array)
|
39
|
+
args = args[0]
|
40
|
+
end
|
41
|
+
|
42
|
+
if args.empty?
|
43
|
+
raise(Puppet::ParseError, "Please supply a parameter to perform a Hiera lookup")
|
44
|
+
end
|
45
|
+
|
46
|
+
key = args[0]
|
47
|
+
default = args[1]
|
48
|
+
override = args[2]
|
49
|
+
|
50
|
+
return [key, default, override]
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
module_function
|
55
|
+
|
56
|
+
def hiera
|
57
|
+
@hiera ||= Hiera.new(:config => hiera_config)
|
58
|
+
end
|
59
|
+
|
60
|
+
def hiera_config
|
61
|
+
config = {}
|
62
|
+
|
63
|
+
if config_file = hiera_config_file
|
64
|
+
config = Hiera::Config.load(config_file)
|
65
|
+
end
|
66
|
+
|
67
|
+
config[:logger] = 'puppet'
|
68
|
+
config
|
69
|
+
end
|
70
|
+
|
71
|
+
def hiera_config_file
|
72
|
+
config_file = nil
|
73
|
+
|
74
|
+
if Puppet.settings[:hiera_config].is_a?(String)
|
75
|
+
expanded_config_file = File.expand_path(Puppet.settings[:hiera_config])
|
76
|
+
if File.exist?(expanded_config_file)
|
77
|
+
config_file = expanded_config_file
|
78
|
+
end
|
79
|
+
elsif Puppet.settings[:confdir].is_a?(String)
|
80
|
+
expanded_config_file = File.expand_path(File.join(Puppet.settings[:confdir], '/hiera.yaml'))
|
81
|
+
if File.exist?(expanded_config_file)
|
82
|
+
config_file = expanded_config_file
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
config_file
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
@@ -1,45 +1,8 @@
|
|
1
1
|
module Puppet::Parser::Functions
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# where as calling from templates should work like this:
|
8
|
-
# scope.function_lookup("foo", "bar")
|
9
|
-
#
|
10
|
-
# Therefore, declare this function with args '*args' to accept any number
|
11
|
-
# of arguments and deal with puppet's special calling mechanism now:
|
12
|
-
if args[0].is_a?(Array)
|
13
|
-
args = args[0]
|
14
|
-
end
|
15
|
-
|
16
|
-
key = args[0]
|
17
|
-
default = args[1]
|
18
|
-
override = args[2]
|
19
|
-
|
20
|
-
configfile = File.join([File.dirname(Puppet.settings[:config]), "hiera.yaml"])
|
21
|
-
|
22
|
-
raise(Puppet::ParseError, "Hiera config file #{configfile} not readable") unless File.exist?(configfile)
|
23
|
-
raise(Puppet::ParseError, "You need rubygems to use Hiera") unless Puppet.features.rubygems?
|
24
|
-
|
25
|
-
require 'hiera'
|
26
|
-
require 'hiera/scope'
|
27
|
-
|
28
|
-
config = YAML.load_file(configfile)
|
29
|
-
config[:logger] = "puppet"
|
30
|
-
|
31
|
-
hiera = Hiera.new(:config => config)
|
32
|
-
|
33
|
-
if self.respond_to?("[]")
|
34
|
-
hiera_scope = self
|
35
|
-
else
|
36
|
-
hiera_scope = Hiera::Scope.new(self)
|
37
|
-
end
|
38
|
-
|
39
|
-
answer = hiera.lookup(key, default, hiera_scope, override, :priority)
|
40
|
-
|
41
|
-
raise(Puppet::ParseError, "Could not find data item #{key} in any Hiera data file and no default supplied") if answer.nil?
|
42
|
-
|
43
|
-
return answer
|
44
|
-
end
|
2
|
+
newfunction(:hiera, :type => :rvalue) do |*args|
|
3
|
+
require 'hiera_puppet'
|
4
|
+
key, default, override = HieraPuppet.parse_args(args)
|
5
|
+
HieraPuppet.lookup(key, default, self, override, :priority)
|
6
|
+
end
|
45
7
|
end
|
8
|
+
|