ruby-puppetdb 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 06d30fe03dc440c05f38f596006a7fe936ae8b21
4
- data.tar.gz: 81ce06c2b619e6784d5b9c1aa0f87909bd30f602
3
+ metadata.gz: 9ed96d47f9a2eae2e54dccea8d9961cd185d0631
4
+ data.tar.gz: dc1ba65a4259f59d583dda883957b3bc5127df4a
5
5
  SHA512:
6
- metadata.gz: 2e7675f6543e5a22395b54461f8529ee61b84ffd09cc9146ce83bc2f1d1ef3930a301384b1d5431bf8564244a66adef5e988e80b4674b62d69f8c06eccca4985
7
- data.tar.gz: 1cbe4bf2114a646c0a09eee902c0247cf79e76782f24ea9f785011968bb93153fb203700370823e06089bfeb96aedc77be400752f07aaeadc1a168561ae120f0
6
+ metadata.gz: 15f7ae9d9c39d487f772ea24d46229dfced946265d9fd52e5b7603a319eeb420c335d57ce618ab45344b47cfa10728645ddacf9a79d3b02ab6f6cb39ec961e94
7
+ data.tar.gz: 79e0500fd751c24e7ca74d5df6342d4eb76b8b2f1721672472d2d99832d6d4a87a654c49cd3c3a375aa327919f535bd3099d926b925171ccf5559d8159b95f85
@@ -48,11 +48,13 @@ Puppet::Face.define(:query, '1.0.0') do
48
48
  puppetdb = PuppetDB::Connection.new options[:host], options[:port], !options[:no_ssl]
49
49
  parser = PuppetDB::Parser.new
50
50
  if options[:facts] != ''
51
- factquery = parser.facts_query(query, options[:facts].split(','))
51
+ facts = options[:facts].split(',')
52
+ factquery = parser.facts_query(query, facts)
52
53
  else
54
+ facts = [:all]
53
55
  factquery = parser.parse(query, :facts)
54
56
  end
55
- parser.facts_hash(puppetdb.query(:facts, factquery, :extract => [:certname, :name, :value]))
57
+ parser.facts_hash(puppetdb.query(:facts, factquery, :extract => [:certname, :name, :value]), facts)
56
58
  end
57
59
  end
58
60
 
@@ -15,6 +15,8 @@ Puppet::Parser::Functions.newfunction(:query_facts, :type => :rvalue, :arity =>
15
15
  EOT
16
16
  ) do |args|
17
17
  query, facts = args
18
+ facts = facts.map { |fact| fact.match(/\./) ? fact.split('.') : fact }
19
+ facts_for_query = facts.map { |fact| fact.is_a?(Array) ? fact.first : fact }
18
20
 
19
21
  require 'puppet/util/puppetdb'
20
22
 
@@ -31,6 +33,6 @@ EOT
31
33
  uri = URI(Puppet::Util::Puppetdb.config.server_urls.first)
32
34
  puppetdb = PuppetDB::Connection.new(uri.host, uri.port, uri.scheme == 'https')
33
35
  parser = PuppetDB::Parser.new
34
- query = parser.facts_query query, facts if query.is_a? String
35
- parser.facts_hash(puppetdb.query(:facts, query, :extract => [:certname, :name, :value]))
36
+ query = parser.facts_query query, facts_for_query if query.is_a? String
37
+ parser.facts_hash(puppetdb.query(:facts, query, :extract => [:certname, :name, :value]), facts)
36
38
  end
@@ -1,17 +1,23 @@
1
1
  Puppet::Parser::Functions.newfunction(:query_nodes, :type => :rvalue, :arity => -2, :doc => <<-EOT
2
2
 
3
- accepts two arguments, a query used to discover nodes, and a optional
3
+ accepts two arguments, a query used to discover nodes, and an optional
4
4
  fact that should be returned.
5
5
 
6
6
  The query specified should conform to the following format:
7
7
  (Type[title] and fact_name<operator>fact_value) or ...
8
8
  Package["mysql-server"] and cluster_id=my_first_cluster
9
9
 
10
- The second argument should be single fact (this argument is optional)
10
+ The second argument should be single fact or series of keys joined on periods
11
+ (this argument is optional)
11
12
 
12
13
  EOT
13
14
  ) do |args|
14
15
  query, fact = args
16
+ fact_for_query = if fact && fact.match(/\./)
17
+ fact.split('.').first
18
+ else
19
+ fact
20
+ end
15
21
 
16
22
  require 'puppet/util/puppetdb'
17
23
 
@@ -28,9 +34,15 @@ EOT
28
34
  uri = URI(Puppet::Util::Puppetdb.config.server_urls.first)
29
35
  puppetdb = PuppetDB::Connection.new(uri.host, uri.port, uri.scheme == 'https')
30
36
  parser = PuppetDB::Parser.new
31
- if fact
32
- query = parser.facts_query(query, [fact])
33
- puppetdb.query(:facts, query, :extract => :value).collect { |f| f['value'] }
37
+ if fact_for_query
38
+ query = parser.facts_query(query, [fact_for_query])
39
+ response = puppetdb.query(:facts, query, :extract => :value)
40
+
41
+ if fact.split('.').size > 1
42
+ parser.extract_nested_fact(response, fact.split('.')[1..-1])
43
+ else
44
+ response.collect { |f| f['value'] }
45
+ end
34
46
  else
35
47
  query = parser.parse(query, :nodes) if query.is_a? String
36
48
  puppetdb.query(:nodes, query, :extract => :certname).collect { |n| n['certname'] }
@@ -68,6 +68,7 @@ EOT
68
68
  results.reduce({}) do |ret, resource|
69
69
  ret[resource['certname']] = [] unless ret.key? resource['certname']
70
70
  ret[resource['certname']] << resource
71
+ ret
71
72
  end
72
73
  else
73
74
  results
@@ -1,4 +1,4 @@
1
1
  module PuppetDB
2
2
  # Current version of this module
3
- VERSION = [2, 1, 1]
3
+ VERSION ||= [2, 2, 0]
4
4
  end
@@ -22,7 +22,13 @@ module PuppetDB::ParserHelper
22
22
  if facts.nil?
23
23
  nodequery
24
24
  else
25
- factquery = ['or', *facts.collect { |f| ['=', 'name', f] }]
25
+ factquery = ['or', *facts.collect { |f|
26
+ if (f =~ /^\/(.+)\/$/)
27
+ ['~', 'name', f.scan(/^\/(.+)\/$/).last.first]
28
+ else
29
+ ['=', 'name', f]
30
+ end
31
+ }]
26
32
  if nodequery
27
33
  ['and', nodequery, factquery]
28
34
  else
@@ -33,19 +39,60 @@ module PuppetDB::ParserHelper
33
39
 
34
40
  # Turn an array of facts into a hash of nodes containing facts
35
41
  #
36
- # @param facts [Array] fact values
42
+ # @param fact_hash [Array] fact values
43
+ # @param facts [Array] fact names
37
44
  # @return [Hash] nodes as keys containing a hash of facts as value
38
- def facts_hash(facts)
39
- facts.reduce({}) do |ret, fact|
45
+ def facts_hash(fact_hash, facts)
46
+ fact_hash.reduce({}) do |ret, fact|
47
+ # Array#include? only matches on values of the same type, so if we find
48
+ # a matching string, it's not a nested query.
49
+ name, value = if facts.include?(fact['name']) || facts == [:all]
50
+ [fact['name'], fact['value']]
51
+ else
52
+ # Find the set of keys where the first value is the fact name
53
+ nested_keys = facts.select do |x|
54
+ x.is_a?(Array) && x.first == fact['name']
55
+ end.flatten
56
+
57
+ # Join all the key names together with an underscore to give
58
+ # us a unique name, and then send all the keys but the fact
59
+ # name (which was already queried out) to extract_nested_fact
60
+ [
61
+ nested_keys.join("_"),
62
+ extract_nested_fact([fact], nested_keys[1..-1]).first
63
+ ]
64
+ end
65
+
40
66
  if ret.include? fact['certname']
41
- ret[fact['certname']][fact['name']] = fact['value']
67
+ ret[fact['certname']][name] = value
42
68
  else
43
- ret[fact['certname']] = { fact['name'] => fact['value'] }
69
+ ret[fact['certname']] = { name => value }
44
70
  end
45
71
  ret
46
72
  end
47
73
  end
48
74
 
75
+ # Take an array of hashes of fact hashes and get a nested value from each
76
+ # of them.
77
+ #
78
+ # @param fact_hashes [Array] an array of hashes of fact hashes
79
+ # @param keys [Array] an array of keys to dig into the hash
80
+ # @returt [Array] an array of extracted values
81
+ def extract_nested_fact(fact_hashes, keys)
82
+ fact_hashes.map do |fact_hash|
83
+ hash = fact_hash['value']
84
+
85
+ # Traverse the hash, setting `hash` equal to the next level deep each step
86
+ keys[0..-2].each do |key|
87
+ hash = hash.fetch(key, {})
88
+ end
89
+
90
+ # Lookup the final key. This will convert to nil if we've been defaulting
91
+ # to empty hash beforehand.
92
+ hash[keys.last]
93
+ end
94
+ end
95
+
49
96
  # Turn a query into one for only certain fields
50
97
  def self.extract(*field, query)
51
98
  ['extract', field.collect(&:to_s), query]
@@ -12,4 +12,43 @@ describe 'query_facts' do
12
12
  ]
13
13
  should run.with_params('', ['ipaddress']).and_return('apache4.puppetexplorer.io' => { 'ipaddress' => '172.31.6.80' })
14
14
  end
15
+
16
+ it do
17
+ PuppetDB::Connection.any_instance.expects(:query)
18
+ .with(:facts, ['or', ['=', 'name', 'ipaddress'], ['=', 'name', 'network_eth0']], {:extract => [:certname, :name, :value]})
19
+ .returns [
20
+ { 'certname' => 'apache4.puppetexplorer.io', 'environment' => 'production', 'name' => 'ipaddress', 'value' => '172.31.6.80' },
21
+ { 'certname' => 'apache4.puppetexplorer.io', 'environment' => 'production', 'name' => 'network_eth0', 'value' => '172.31.0.0' }
22
+ ]
23
+ should run.with_params('', ['ipaddress', 'network_eth0']).and_return('apache4.puppetexplorer.io' => { 'ipaddress' => '172.31.6.80', 'network_eth0' => '172.31.0.0' })
24
+ end
25
+
26
+ context 'with a nested fact parameter' do
27
+ it do
28
+ PuppetDB::Connection.any_instance.expects(:query)
29
+ .with(:facts, ['or', ['=', 'name', 'ipaddress'], ['=', 'name', 'networking']], {:extract => [:certname, :name, :value]})
30
+ .returns [
31
+ { 'certname' => 'apache4.puppetexplorer.io', 'environment' => 'production', 'name' => 'ipaddress', 'value' => '172.31.6.80' },
32
+ {
33
+ 'certname' => 'apache4.puppetexplorer.io',
34
+ 'environment' => 'production',
35
+ 'name' => 'networking',
36
+ 'value' => {
37
+ 'interfaces' => {
38
+ 'eth0' => {
39
+ 'ip' => '172.31.6.80',
40
+ 'network' => '172.31.0.0',
41
+ },
42
+ 'eth1' => {
43
+ 'ip' => '172.32.6.80',
44
+ 'network' => '172.32.0.0',
45
+ },
46
+ 'bond0' => {},
47
+ }
48
+ }
49
+ }
50
+ ]
51
+ should run.with_params('', ['ipaddress', 'networking.interfaces.eth0.ip']).and_return('apache4.puppetexplorer.io' => { 'ipaddress' => '172.31.6.80', 'networking_interfaces_eth0_ip' => '172.31.6.80' })
52
+ end
53
+ end
15
54
  end
@@ -1,6 +1,7 @@
1
1
  #! /usr/bin/env ruby -S rspec
2
2
 
3
3
  require 'spec_helper'
4
+ require 'puppetdb/connection'
4
5
 
5
6
  describe 'query_nodes' do
6
7
  context 'without fact parameter' do
@@ -20,4 +21,54 @@ describe 'query_nodes' do
20
21
  should run.with_params('hostname="apache4"', 'ipaddress').and_return(['172.31.6.80'])
21
22
  end
22
23
  end
24
+
25
+ context 'with a nested fact parameter' do
26
+ it do
27
+ PuppetDB::Connection.any_instance.expects(:query)
28
+ .with(:facts, ['and', ['in', 'certname', ['extract', 'certname', ['select_fact_contents', ['and', ['=', 'path', ['hostname']], ['=', 'value', 'apache4']]]]], ['or', ['=', 'name', 'networking']]], :extract => :value)
29
+ .returns [
30
+ {
31
+ 'value' => {
32
+ 'interfaces' => {
33
+ 'eth0' => {
34
+ 'ip' => '172.31.6.80',
35
+ 'network' => '172.31.0.0',
36
+ },
37
+ 'eth1' => {
38
+ 'ip' => '172.32.6.80',
39
+ 'network' => '172.32.0.0',
40
+ },
41
+ 'bond0' => {},
42
+ }
43
+ }
44
+ }
45
+ ]
46
+ should run.with_params('hostname="apache4"', 'networking.interfaces.eth1.ip').and_return(['172.32.6.80'])
47
+ end
48
+ end
49
+
50
+ context 'with a missing nested fact parameter' do
51
+ it do
52
+ PuppetDB::Connection.any_instance.expects(:query)
53
+ .with(:facts, ['and', ['in', 'certname', ['extract', 'certname', ['select_fact_contents', ['and', ['=', 'path', ['hostname']], ['=', 'value', 'apache4']]]]], ['or', ['=', 'name', 'networking']]], :extract => :value)
54
+ .returns [
55
+ {
56
+ 'value' => {
57
+ 'interfaces' => {
58
+ 'eth0' => {
59
+ 'ip' => '172.31.6.80',
60
+ 'network' => '172.31.0.0',
61
+ },
62
+ 'eth1' => {
63
+ 'ip' => '172.32.6.80',
64
+ 'network' => '172.32.0.0',
65
+ },
66
+ 'bond0' => {},
67
+ }
68
+ }
69
+ }
70
+ ]
71
+ should run.with_params('hostname="apache4"', 'networking.interfaces.missing_interface.ip').and_return([nil])
72
+ end
73
+ end
23
74
  end
@@ -215,12 +215,24 @@ describe PuppetDB::Parser do
215
215
  { 'certname' => 'ip-172-31-45-32.eu-west-1.compute.internal', 'environment' => 'production', 'name' => 'fqdn', 'value' => 'ip-172-31-45-32.eu-west-1.compute.internal' },
216
216
  { 'certname' => 'ip-172-31-33-234.eu-west-1.compute.internal', 'environment' => 'production', 'name' => 'fqdn', 'value' => 'ip-172-31-33-234.eu-west-1.compute.internal' },
217
217
  { 'certname' => 'ip-172-31-5-147.eu-west-1.compute.internal', 'environment' => 'production', 'name' => 'fqdn', 'value' => 'ip-172-31-5-147.eu-west-1.compute.internal' }
218
- ]).should eq(
218
+ ], ['kernel', 'fqdn']).should eq(
219
219
  'ip-172-31-45-32.eu-west-1.compute.internal' => { 'kernel' => 'Linux', 'fqdn' => 'ip-172-31-45-32.eu-west-1.compute.internal' },
220
220
  'ip-172-31-33-234.eu-west-1.compute.internal' => { 'kernel' => 'Linux', 'fqdn' => 'ip-172-31-33-234.eu-west-1.compute.internal' },
221
221
  'ip-172-31-5-147.eu-west-1.compute.internal' => { 'kernel' => 'Linux', 'fqdn' => 'ip-172-31-5-147.eu-west-1.compute.internal' }
222
222
  )
223
223
  end
224
+
225
+ it 'should handle nested facts' do
226
+ parser.facts_hash([
227
+ { 'certname' => 'ip-172-31-45-32.eu-west-1.compute.internal', 'environment' => 'production', 'name' => 'kernel', 'value' => 'Linux' },
228
+ { 'certname' => 'ip-172-31-33-234.eu-west-1.compute.internal', 'environment' => 'production', 'name' => 'kernel', 'value' => 'Linux' },
229
+ { 'certname' => 'ip-172-31-45-32.eu-west-1.compute.internal', 'environment' => 'production', 'name' => 'networking', 'value' => { 'interfaces' => { 'eth0' => { 'ip' => '172.31.45.32' } } } },
230
+ { 'certname' => 'ip-172-31-33-234.eu-west-1.compute.internal', 'environment' => 'production', 'name' => 'networking', 'value' => { 'interfaces' => { 'eth0' => { 'ip' => '172.31.33.234' } } } },
231
+ ], ['kernel', ['networking', 'interfaces', 'eth0', 'ip']]).should eq(
232
+ 'ip-172-31-45-32.eu-west-1.compute.internal' => { 'kernel' => 'Linux', 'networking_interfaces_eth0_ip' => '172.31.45.32' },
233
+ 'ip-172-31-33-234.eu-west-1.compute.internal' => { 'kernel' => 'Linux', 'networking_interfaces_eth0_ip' => '172.31.33.234' },
234
+ )
235
+ end
224
236
  end
225
237
 
226
238
  context 'extract' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-puppetdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erik Dalen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-14 00:00:00.000000000 Z
11
+ date: 2016-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -44,26 +44,32 @@ dependencies:
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 3.0.0
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: 5.0.0
48
51
  type: :runtime
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
51
54
  requirements:
52
55
  - - ">="
53
56
  - !ruby/object:Gem::Version
54
- version: '0'
57
+ version: 3.0.0
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: 5.0.0
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: rspec
57
63
  requirement: !ruby/object:Gem::Requirement
58
64
  requirements:
59
- - - '='
65
+ - - "~>"
60
66
  - !ruby/object:Gem::Version
61
67
  version: '2.13'
62
68
  type: :development
63
69
  prerelease: false
64
70
  version_requirements: !ruby/object:Gem::Requirement
65
71
  requirements:
66
- - - '='
72
+ - - "~>"
67
73
  - !ruby/object:Gem::Version
68
74
  version: '2.13'
69
75
  - !ruby/object:Gem::Dependency
@@ -129,9 +135,6 @@ dependencies:
129
135
  - - "~>"
130
136
  - !ruby/object:Gem::Version
131
137
  version: '1.4'
132
- - - "<"
133
- - !ruby/object:Gem::Version
134
- version: 1.4.12
135
138
  type: :development
136
139
  prerelease: false
137
140
  version_requirements: !ruby/object:Gem::Requirement
@@ -139,9 +142,6 @@ dependencies:
139
142
  - - "~>"
140
143
  - !ruby/object:Gem::Version
141
144
  version: '1.4'
142
- - - "<"
143
- - !ruby/object:Gem::Version
144
- version: 1.4.12
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: rexical
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -222,18 +222,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
222
  version: '0'
223
223
  requirements: []
224
224
  rubyforge_project:
225
- rubygems_version: 2.2.5
225
+ rubygems_version: 2.4.8
226
226
  signing_key:
227
227
  specification_version: 4
228
228
  summary: Query functions for PuppetDB
229
229
  test_files:
230
+ - spec/spec_helper.rb
230
231
  - spec/functions/query_facts_spec.rb
231
232
  - spec/functions/query_nodes_spec.rb
232
233
  - spec/functions/query_resources_spec.rb
233
- - spec/puppet/util/puppetdb.rb
234
- - spec/spec_helper.rb
235
234
  - spec/unit/puppetdb/parser_spec.rb
235
+ - spec/puppet/util/puppetdb.rb
236
236
  - examples/nova_functions.pp
237
237
  - examples/query_node_examples.pp
238
238
  - examples/query_resource_examples.pp
239
- has_rdoc: