hiera-browser 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- Y2ZhZTJkYTg0OTQyODg5MWFiZGJjNzJiNTFhZTdiYTgwYjU3NjI1Yg==
4
+ MTJjYmRkM2QwZmU3N2M3OGFhNjM3YjhhZDNkNGNmMGI3NTBiODJhMw==
5
5
  data.tar.gz: !binary |-
6
- YjllOTYxNDRhYjJjZDY3YTZmYWQ3MGRhN2Y2OTRhNThlMGVkMTZkNg==
6
+ OWY4MWM2M2ViOTg3MWFlMzA2MGYxN2I1MTk2YTE3MTI3MTkyMzc0Mw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MGJmNjFiYWM1YjFhYzAyYzI5NzZlYWFmZGFjZDQ1ZjI0OTA0MDQ1ZmQ5M2Jm
10
- NTczNzM1NTk1YWMzMjQ0ZDFjMzgzZGE5Njk3M2NhMjUwNWRkMmZhMTIyYmZh
11
- MjUxZTYwNTVjOTg3YzU4YmQ2OGMxOWRhYjFhZTQ2YjcxMDM3OTY=
9
+ NjQ1OGY4NDU5MmQ2NmVjN2EwNzAyNTlkN2I2NWM4M2Q3ZDk1ODczMWQ3YmE1
10
+ YWM5Mzg4YTRlODdjZjMzOTJiYjM5ODZmYzc4NDJhMDUyNjkzNGNkOGFiMzgz
11
+ OWZlY2U1OTAwMDg0ZGRlNjQ1YjlhNmZiMzQ5NGZiY2Q2MTZjZTY=
12
12
  data.tar.gz: !binary |-
13
- M2VlNmU1NGZkYzlhNzY1MzExZGZkZDhiNTAzNTVlNWY4YjAzNDQ3Y2JjOTJj
14
- YzRjMjBlYmExZmMzODM5NTdmZGU0NTY4NjQyYjNmNWM3NThjYWExMDQwOWJh
15
- MGUzZDNiZGQxMjYyOGU2NGZjMWI1ZWIwOTE5YTM5YTJmMzJkYTI=
13
+ NTE1MjMxOGFmN2YwODlkN2E2YWRjOWYwOTE0N2QxY2RlMDAyMzNhMGE4NGM0
14
+ ZDEzMjk4YzY3ZmZiOWQ5NzllYjk3OWNlODY1ZGViNmZlMTA1OWIyMWNhMGZj
15
+ ODk1NmM5ODM2OGJhNzM3MDFhMTU5ZjRhYzgwMTI0OTQyMmM3MTE=
@@ -12,7 +12,7 @@ use Rack::Session::Cookie, :secret => '4zENWx0ruhWU3ZN'
12
12
  class HieraBrowserUI < Sinatra::Application
13
13
  # api
14
14
  get '/api/v1/nodes' do
15
- @nodes = Node.list
15
+ @nodes = YamlDir.new.node_list
16
16
  JSON.generate(@nodes)
17
17
  end
18
18
 
@@ -35,7 +35,7 @@ class HieraBrowserUI < Sinatra::Application
35
35
 
36
36
  get '/nodes' do
37
37
  @title = "node list"
38
- @nodes = Node.list
38
+ @nodes = YamlDir.new.node_list
39
39
  slim :nodes
40
40
  end
41
41
 
@@ -2,4 +2,5 @@ require 'hiera'
2
2
  require 'hiera_browser/hiera_controller'
3
3
  require 'hiera_browser/data'
4
4
  require 'hiera_browser/node'
5
-
5
+ require 'hiera_browser/yamldir'
6
+ require 'hiera_browser/parameters'
@@ -1,37 +1,43 @@
1
1
  require 'yaml'
2
2
 
3
3
  class DataDir
4
- attr_reader :path
4
+ attr_reader :paths
5
5
 
6
+ # @return [void]
6
7
  def initialize(args={})
7
- @hiera = args[:hiera]
8
- @paths = render_paths(:path => args[:path])
8
+ @node_dir = args[:node_dir] || YamlDir.new
9
+ @paths = render_paths(:path => args[:path])
9
10
  end
10
11
 
12
+ # @return [Array]
11
13
  def render_paths(args)
12
14
  begin
13
- variables = args[:path].match(/\%\{([a-z_\:]+)\}/).captures
14
- variables.map{|v|
15
- Node.parameters[v].map{|param|
16
- args[:path].gsub(/\%\{#{v}\}/, param)}.flatten
15
+ interpolated_variables = args[:path].match(/\%\{([a-z_\:]+)\}/).captures
16
+ collected_parameters = @node_dir.collected_parameters
17
+ # collected_parameters is a ParameterCollection
18
+ # interpolated_variables might look like ['::environment']
19
+ interpolated_variables.map{|v|
20
+ collected_parameters[v].map{|param|
21
+ args[:path].gsub(/%{#{v}}/, param)}
17
22
  }.flatten
18
23
  rescue NoMethodError
19
24
  [args[:path]]
20
25
  end
21
26
  end
22
27
 
28
+ # @return [Array]
23
29
  def yaml_files
24
- @paths.map{|p|
25
- Dir.chdir(p) { Dir.glob('**/*.yaml') }
26
- }.flatten
30
+ @paths.map{|p| Dir.chdir(p) { Dir.glob('**/*.yaml') } }.flatten
27
31
  end
28
32
 
33
+ # @return [Array]
29
34
  def datafiles
30
35
  @paths.map{|path|
31
- yaml_files.map{|f| DataFile.new(:path => File.join(path,f))}.flatten
36
+ yaml_files.map{|f| DataFile.new(:path => File.join(path,f))}
32
37
  }.flatten
33
38
  end
34
39
 
40
+ # @return [Array]
35
41
  def keys
36
42
  datafiles.map{|datafile| datafile.keys}.flatten.uniq.sort
37
43
  end
@@ -40,11 +46,13 @@ end
40
46
  class DataFile
41
47
  attr_reader :path
42
48
 
49
+ # @return [void]
43
50
  def initialize(args={})
44
51
  @path = args[:path]
45
52
  @keys = keys
46
53
  end
47
54
 
55
+ # @return [Array]
48
56
  def keys
49
57
  YAML.load_file(@path).keys
50
58
  end
@@ -1,22 +1,30 @@
1
1
  require 'yaml'
2
2
 
3
+ # HieraController gives us a reasonably limited interface for Hiera
4
+ #
5
+ # @author David Gwilliam
3
6
  class HieraController
4
- @@hiera_yaml = ENV['HIERA_YAML'] || './hiera.yaml'
5
7
  attr_reader :hiera_yaml
6
8
 
9
+ # @param args [{:hiera_yaml => String}] path to `hiera.yaml`
10
+ # @return [void]
7
11
  def initialize(args={})
8
- @hiera_yaml = args[:hiera_yaml] || @@hiera_yaml
9
- @hiera = hiera(:config => @hiera_yaml)
12
+ @hiera_yaml = args[:hiera_yaml] || ENV['HIERA_YAML']
13
+ @hiera = hiera(:config => @hiera_yaml)
10
14
  end
11
15
 
16
+ # @param args [Hash] arguments to pass to Hiera.new()
17
+ # @return [Hiera]
12
18
  def hiera(args={})
13
19
  @hiera || Hiera.new(args)
14
20
  end
15
21
 
22
+ # @return [Hash]
16
23
  def config
17
24
  hiera.config
18
25
  end
19
26
 
27
+ # @return [Array]
20
28
  def datadirs
21
29
  config[:backends].map{|b|
22
30
  path = config[b.to_sym][:datadir]
@@ -27,40 +35,59 @@ class HieraController
27
35
  }
28
36
  end
29
37
 
38
+ # @return [Array]
30
39
  def keys
31
40
  datadirs.map{|d| d.keys}.flatten.uniq.sort
32
41
  end
33
42
 
43
+ # @return [Array]
34
44
  def hierarchy
35
45
  config[:hierarchy]
36
46
  end
37
47
 
38
- def top_scopify(args)
39
- scope = args[:scope]
40
- fix_keys = hierarchy.map{|datasource|
48
+ def hierarchy_variables
49
+ hierarchy.map{|datasource|
41
50
  begin
42
51
  datasource.match(/\%\{([\:a-z_]+)\}/)[1]
43
52
  rescue NoMethodError
44
53
  datasource
45
54
  end
46
55
  }
47
- fix_keys.select!{|datasource| datasource.start_with?("::")} unless fix_keys.empty?
56
+ end
57
+
58
+ # Return the scope but with the addition of fully qualified
59
+ # variable keys for any level of the hierarchy that's formatted that way, e.g.:
60
+ # { 'datacenter' => 'pdx', '::datacenter' => 'pdx' }
61
+ #
62
+ # @note needs to be moved to Node
63
+ # @param args [{:scope => Hash}]
64
+ # @return [Hash]
65
+ def top_scopify(args)
66
+ scope = args[:scope]
67
+ fix_keys = hierarchy_variables.select{|datasource| datasource.start_with?(Parameter.top_scope)}
48
68
  scope.inject({}){|a,fact|
49
- if fix_keys.include?("::#{fact.first}")
50
- a["::#{fact.first}"] = fact.last
51
- end
69
+ a[Parameter.top_scope(fact.first)] = fact.last if fix_keys.include?(Parameter.top_scope(fact.first))
52
70
  a[fact.first] = fact.last
53
- a
54
- }
71
+ a }
55
72
  end
56
73
 
57
- def lookup(args)
74
+ # Basically shadows the Hiera#lookup method
75
+ #
76
+ # @note needs to be moved to Node#lookup
77
+ # @param args [{:key => String, :scope => Hash, :resolution_type => Symbol}]
78
+ # @return [Hash]
79
+ def lookup(args = {})
80
+ raise ArgumentError, 'HieraController#lookup requires both :key and :scope args' unless args[:key] and args[:scope]
58
81
  key = args[:key]
59
82
  scope = top_scopify(:scope => args[:scope])
60
83
  resolution_type = args[:resolution_type] || :priority
61
84
  Hash[*[key,hiera.lookup(key, nil, scope, nil, resolution_type)]]
62
85
  end
63
86
 
87
+ # Retrieve all node values for all known hiera keys
88
+ #
89
+ # @param args [{:scope => Hash}]
90
+ # @return [Hash]
64
91
  def get_all(args)
65
92
  scope = top_scopify(:scope => args[:scope])
66
93
  values = keys.inject({}){|a, k|
@@ -73,6 +100,11 @@ class HieraController
73
100
  values
74
101
  end
75
102
 
103
+ # Check return value of priority lookup in order to determine which "additive"
104
+ # resolution type to use, then repeat the lookup with the correct resolution type
105
+ #
106
+ # @param args [{:key => String, :scope => Hash}]
107
+ # @return [Hash]
76
108
  def lookup_additive(args)
77
109
  key = args[:key]
78
110
  scope = top_scopify(:scope => args[:scope])
@@ -1,71 +1,69 @@
1
1
  require 'yaml'
2
2
  require 'puppet'
3
3
 
4
+ # A Node represents all that is known about a node in your infrastructure
4
5
  class Node
5
- attr_reader :certname, :facts, :node_dir
6
+ # @return [String] e.g., 'testnode.puppetlabs.com'
7
+ attr_reader :certname
8
+ # @return [Hash] e.g., { 'datacenter' => 'pdx', 'environment' => 'dev' }
9
+ attr_reader :facts
10
+ # @return [YamlDir]
11
+ attr_reader :node_dir
6
12
 
7
- @@node_dir =
8
- if ENV['YAML_DIR']
9
- ENV['YAML_DIR']
10
- elsif File.exist?('/var/opt/lib/pe-puppet/yaml')
11
- '/var/opt/lib/pe-puppet/yaml/node'
12
- else
13
- '/var/lib/puppet/yaml/node'
14
- end
15
13
 
14
+ # @param args [Hash{:certname => String, :node_dir => String}]
16
15
  def initialize(args)
17
16
  @certname = args[:certname]
17
+ @node_dir = YamlDir.new(:node_dir => args[:node_dir])
18
18
  @facts = facts_yaml
19
19
  @hiera = args[:hiera] || HieraController.new
20
20
  end
21
21
 
22
+ # @return [ParameterCollection]
23
+ def parameters
24
+ collection = ParameterCollection.new
25
+ facts_yaml.each {|k,v|
26
+ collection << Parameter.new(:key => k, :value => v)}
27
+ collection
28
+ end
29
+
30
+ # @return [Hash]
31
+ def load_yaml
32
+ path = File.join(@node_dir.path,"#{@certname}.yaml")
33
+ YAML.load_file(path)
34
+ end
35
+
36
+ # @return [Hash] parameters and facts merged from node cache
22
37
  def facts_yaml
23
- path = File.join(@@node_dir,"#{@certname}.yaml")
24
- node = YAML.load_file(path)
25
- node.parameters.merge(node.facts.values)
38
+ yaml = load_yaml
39
+ yaml.parameters.merge(yaml.facts.values)
26
40
  end
27
41
 
28
- def hiera_values(args={})
42
+ # @param args [Hash{:additive_keys => Array}]
43
+ # @return [Hash] all values for all keys, including additive lookups
44
+ # for any keys included in :additive_keys
45
+ def hiera_values(args = {})
29
46
  additive_keys = args[:additive_keys] || []
30
47
  @hiera.get_all(:scope => @facts, :additive_keys => additive_keys).
31
48
  values.inject({}){|a,v| a.merge!(v)}
32
49
  end
33
50
 
34
- def sorted_values(args)
51
+ # @param args [{:keys => Array}]
52
+ # @return [Array] flattened collection of all {#hiera_values} sorted alphabetically by key
53
+ # e.g. [['datacenter', 'pdx'], ['environment', 'dev']]
54
+ def sorted_values(args = {})
35
55
  keys = args[:keys]
36
56
  hiera_values(:additive_keys => keys).sort_by{|k,v|k}
37
57
  end
38
58
 
59
+ # @return [String]
39
60
  def environment
40
61
  @facts['environment']
41
62
  end
42
63
 
43
- def self.files
44
- begin
45
- Dir.chdir(@@node_dir) { Dir.glob('**/*.yaml') }
46
- rescue Errno::ENOENT => e
47
- raise "Can't find your $yamldir: #{e}"
48
- end
49
- end
50
-
51
- def self.list
52
- files = self.files
53
- files.map{|f| f.split('.yaml')}.flatten
54
- end
55
-
56
- def self.parameters
57
- files = self.files
58
- files.map{|f| YAML.load_file(File.join(@@node_dir,f)).parameters}.
59
- inject({}){|a,params|
60
- params.each {|key, value|
61
- a[key] = [] unless a[key]
62
- a[key] << value unless a[key].include? value
63
- }
64
- a
65
- }
66
- end
67
-
68
- def self.environments
69
- self.parameters["environment"]
64
+ # @param args [Hash{:key => String}]
65
+ # @return [Hash]
66
+ def lookup(args)
67
+ @hiera.lookup_additive(:key => args[:key], :scope => @facts)
70
68
  end
71
69
  end
@@ -0,0 +1,114 @@
1
+ # A collection of {Parameter}s, based on Arrays
2
+ class ParameterCollection
3
+ # @return [void]
4
+ def initialize
5
+ @collection = collection
6
+ end
7
+
8
+ # @return [Array]
9
+ def collection
10
+ @collection || []
11
+ end
12
+
13
+ def [](index)
14
+ stripped_index = index.sub(/^::/,'')
15
+ collection.select{|param| param.key == stripped_index }.map{|param|param.value}
16
+ end
17
+
18
+ # @param parameter [Parameter]
19
+ # @return [ParameterCollection]
20
+ def << (parameter)
21
+ collection << parameter
22
+ dedupe!
23
+ self
24
+ end
25
+
26
+ # @return [Array] all keys in this ParameterCollection
27
+ def keys
28
+ collection.map{|param| param.key}.uniq
29
+ end
30
+
31
+ # @param param [Parameter]
32
+ # @return [TrueClass, FalseClass] True if this ParameterCollection includes a Parameter
33
+ def include?(param)
34
+ truth = false
35
+ collection.each{|p| truth = true if p == param}
36
+ truth
37
+ end
38
+
39
+ # @return [Fixnum] the number of Parameters in the ParameterCollection
40
+ def count
41
+ collection.count
42
+ end
43
+
44
+ # @return [Hash] the parameter collection condensed to a Hash, multiple values
45
+ # for the same key condensed into an Array, all keys duplicated
46
+ def to_h
47
+ self.keys.inject({}){|a, k|
48
+ a[k] = self[k]
49
+ a[Parameter.top_scope(k)] = self[k]
50
+ a }
51
+ end
52
+
53
+ private
54
+
55
+ def dedupe!
56
+ @collection = collection.inject([]){|a, param|
57
+ if a.include?(param)
58
+ a
59
+ else
60
+ a << param
61
+ end }
62
+ end
63
+ end
64
+
65
+ # Structured object for holding key/value parameters, whether they are facts or not
66
+ class Parameter
67
+ # @param args [Hash{:key => String, :value => Object}]
68
+ # @return [void]
69
+ def initialize(args = {})
70
+ raise ArgumentError, "A Parameter must have both :key and :value" unless
71
+ args[:key] && args[:value]
72
+ @key = descope(args[:key])
73
+ @value = args[:value]
74
+ end
75
+
76
+ # @return [String] fully qualified {#key}
77
+ # e.g. `::datacenter`
78
+ def top_scope_key
79
+ Parameter.top_scope(@key)
80
+ end
81
+
82
+ # @param param [Parameter]
83
+ # @return [TrueClass, FalseClass]
84
+ def == (param)
85
+ if param.class == Parameter && @key == param.key && @value == param.value
86
+ true
87
+ else
88
+ false
89
+ end
90
+ end
91
+
92
+ # @return [String]
93
+ attr_reader :key
94
+
95
+ # @return [Object]
96
+ attr_reader :value
97
+
98
+ class << self
99
+ # @param key [String]
100
+ # @return [String] the provided key, fully qualified, e.g. "::key"
101
+ def top_scope(key = '')
102
+ "::#{key}"
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ # @param key [String] a top-scope variable name / parameter key, e.g. ::key
109
+ # @return [String] the provided key with any top-scoping removed, e.g. key
110
+ def descope(key)
111
+ key.sub(/^::/,'')
112
+ end
113
+ end
114
+
@@ -0,0 +1,58 @@
1
+ require 'puppet'
2
+
3
+ # YamlDir allows you to retrieve information from Puppet's node cache
4
+ class YamlDir
5
+ @@node_dir =
6
+ if ENV['YAML_DIR']
7
+ ENV['YAML_DIR']
8
+ elsif File.directory?('/var/opt/lib/pe-puppet/yaml')
9
+ '/var/opt/lib/pe-puppet/yaml/node'
10
+ else
11
+ '/var/lib/puppet/yaml/node'
12
+ end
13
+
14
+ def initialize(args = {})
15
+ @node_dir = args[:node_dir] || @@node_dir
16
+ raise Exception.new "Can't find your $yamldir: #{@node_dir}" unless File.directory?(@node_dir)
17
+ end
18
+
19
+ def path
20
+ @node_dir
21
+ end
22
+
23
+ def file_list
24
+ Dir.chdir(@node_dir) { Dir.glob('**/*.yaml') }
25
+ end
26
+
27
+ def node_list
28
+ file_list.map{|f| f.split('.yaml')}.flatten
29
+ end
30
+
31
+ def load_files
32
+ file_list.map{|f| YAML.load_file(File.join(@node_dir,f))}
33
+ end
34
+
35
+ # @note #parameters is provided for temporary backwards compatibility
36
+ # @see #collected_parameters
37
+ def parameters
38
+ collected_parameters_hash
39
+ end
40
+
41
+ # @note #collected_parameters is preferred over #parameters
42
+ def collected_parameters
43
+ collection = ParameterCollection.new
44
+ load_files.map{|f| f.parameters}.
45
+ each{|params| params.each {|key, value|
46
+ collection << Parameter.new(:key => key, :value => value) } }
47
+ collection
48
+ end
49
+
50
+ def collected_parameters_hash
51
+ collected_parameters.to_h
52
+ end
53
+
54
+ def environments
55
+ collected_parameters["environment"]
56
+ end
57
+ end
58
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiera-browser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Gwilliam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-05 00:00:00.000000000 Z
11
+ date: 2014-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hiera
@@ -192,6 +192,76 @@ dependencies:
192
192
  - - ! '>='
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: yard
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ! '>='
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ! '>='
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: redcarpet
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ! '>='
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ! '>='
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: guard
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ! '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ! '>='
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: guard-rspec
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ! '>='
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ! '>='
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: simplecov
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ~>
256
+ - !ruby/object:Gem::Version
257
+ version: 0.7.1
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ~>
263
+ - !ruby/object:Gem::Version
264
+ version: 0.7.1
195
265
  description: Tries to guess what values hiera will return for any existing node in
196
266
  your infrastructure
197
267
  email: dhgwilliam@gmail.com
@@ -210,6 +280,8 @@ files:
210
280
  - lib/hiera_browser/data.rb
211
281
  - lib/hiera_browser/hiera_controller.rb
212
282
  - lib/hiera_browser/node.rb
283
+ - lib/hiera_browser/parameters.rb
284
+ - lib/hiera_browser/yamldir.rb
213
285
  homepage:
214
286
  licenses:
215
287
  - APACHE 2.0