ruby-puppetdb 1.0.0.pre2

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.
Files changed (40) hide show
  1. data/.gitignore +3 -0
  2. data/COPYING +202 -0
  3. data/Modulefile +7 -0
  4. data/README.md +233 -0
  5. data/Rakefile +24 -0
  6. data/bin/find-nodes +56 -0
  7. data/examples/nova_functions.pp +16 -0
  8. data/examples/query_node_examples.pp +12 -0
  9. data/examples/query_resource_examples.pp +48 -0
  10. data/lib/puppet/application/query.rb +22 -0
  11. data/lib/puppet/face/query.rb +60 -0
  12. data/lib/puppet/parser/functions/pdbfactquery.rb +31 -0
  13. data/lib/puppet/parser/functions/pdbnodequery.rb +38 -0
  14. data/lib/puppet/parser/functions/pdbnodequery_all.rb +40 -0
  15. data/lib/puppet/parser/functions/pdbquery.rb +41 -0
  16. data/lib/puppet/parser/functions/pdbresourcequery.rb +39 -0
  17. data/lib/puppet/parser/functions/pdbresourcequery_all.rb +37 -0
  18. data/lib/puppet/parser/functions/pdbstatusquery.rb +31 -0
  19. data/lib/puppet/parser/functions/query_facts.rb +27 -0
  20. data/lib/puppet/parser/functions/query_nodes.rb +27 -0
  21. data/lib/puppetdb.rb +2 -0
  22. data/lib/puppetdb/astnode.rb +86 -0
  23. data/lib/puppetdb/connection.rb +62 -0
  24. data/lib/puppetdb/grammar.y +57 -0
  25. data/lib/puppetdb/lexer.l +28 -0
  26. data/lib/puppetdb/lexer.rb +135 -0
  27. data/lib/puppetdb/parser.rb +368 -0
  28. data/lib/puppetdb/util.rb +18 -0
  29. data/ruby-puppetdb.gemspec +16 -0
  30. data/spec/spec_helper.rb +4 -0
  31. data/spec/unit/puppet/parser/functions/pdbfactquery_spec.rb +19 -0
  32. data/spec/unit/puppet/parser/functions/pdbnodequery_all_spec.rb +19 -0
  33. data/spec/unit/puppet/parser/functions/pdbnodequery_spec.rb +19 -0
  34. data/spec/unit/puppet/parser/functions/pdbquery_spec.rb +19 -0
  35. data/spec/unit/puppet/parser/functions/pdbresourcequery_all_spec.rb +19 -0
  36. data/spec/unit/puppet/parser/functions/pdbresourcequery_spec.rb +19 -0
  37. data/spec/unit/puppet/parser/functions/pdbstatusquery_spec.rb +19 -0
  38. data/spec/unit/puppet/parser/functions/query_facts_spec.rb +11 -0
  39. data/spec/unit/puppet/parser/functions/query_nodes_spec.rb +11 -0
  40. metadata +118 -0
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rspec/core/rake_task'
4
+
5
+ task :default => [:test]
6
+
7
+ desc 'Run RSpec'
8
+ RSpec::Core::RakeTask.new(:test) do |t|
9
+ t.pattern = 'spec/{unit}/**/*.rb'
10
+ t.rspec_opts = ['--color']
11
+ end
12
+
13
+ desc "Generate Lexer and Parser"
14
+ task :generate => [:lexer, :parser]
15
+
16
+ desc "Generate Parser"
17
+ task :parser do
18
+ `racc lib/puppetdb/grammar.y -o lib/puppetdb/parser.rb --superclass='PuppetDB::Lexer'`
19
+ end
20
+
21
+ desc "Generate Lexer"
22
+ task :lexer do
23
+ `rex lib/puppetdb/lexer.l -o lib/puppetdb/lexer.rb`
24
+ end
data/bin/find-nodes ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'puppet'
4
+ require 'rubygems'
5
+ require 'puppetdb/connection'
6
+ require 'optparse'
7
+ require 'net/http'
8
+ require 'net/https'
9
+
10
+ Puppet.initialize_settings
11
+
12
+ options = {:puppetdb_host => "puppetdb",
13
+ :puppetdb_port => 443,
14
+ :fact => nil,
15
+ :query => nil}
16
+
17
+ opt = OptionParser.new
18
+
19
+ opt.on("--puppetdb [PUPPETDB]", "-p", "Host running PuppetDB (#{options[:puppetdb_host]})") do |v|
20
+ options[:puppetdb_host] = v
21
+ end
22
+
23
+ opt.on("--port [PORT]", "-P", Integer, "Port PuppetDB is running on (#{options[:puppetdb_port]})") do |v|
24
+ options[:puppetdb_port] = v
25
+ end
26
+
27
+ opt.on("--query [QUERY]", "-q", "Query String") do |v|
28
+ options[:query] = v
29
+ end
30
+
31
+ opt.on("--facts [FACT]", "-f", "Comma separated list of facts") do |v|
32
+ options[:facts] = v.split ','
33
+ end
34
+
35
+ opt.parse!
36
+
37
+ options[:query] ||= ARGV[0]
38
+
39
+ abort "Please specify a query" unless options[:query]
40
+
41
+ puppetdb = PuppetDB::Connection.new(options[:puppetdb_host], options[:puppetdb_port])
42
+ http = Net::HTTP.new(options[:puppetdb_host], options[:puppetdb_port])
43
+ http.use_ssl = true
44
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
45
+ if options[:facts]
46
+ query = puppetdb.parse_query(options[:query], :facts)
47
+ facts = puppetdb.facts(options[:facts], query, http)
48
+ facts.each_value do |host|
49
+ print options[:facts].collect { |f| host[f] if host.include? f }.join(',') + "\n"
50
+ end
51
+ else
52
+ query = puppetdb.parse_query(options[:query])
53
+ results = puppetdb.query(:nodes, query, http)
54
+ hosts = results.collect { |host| host['name'] }
55
+ hosts.each { |host| print host + "\n" }
56
+ end
@@ -0,0 +1,16 @@
1
+ # These examples use functions that ship with the
2
+ # puppetlabs-nova module
3
+
4
+ $rabbit_connection_hash = collect_rabbit_connection('fqdn', 'architecture=amd64')
5
+
6
+ notice("rabbit host: ${rabbit_connection_hash[host]}")
7
+ notice("rabbit port: ${rabbit_connection_hash[port]}")
8
+ notice("rabbit user: ${rabbit_connection_hash[user]}")
9
+ notice("rabbit password: ${rabbit_connection_hash[password]}")
10
+
11
+ notice(collect_nova_db_connection('fqdn', 'architecture=amd64'))
12
+
13
+ $vnc_proxy_host = unique(query_nodes('Class[Nova::Vncproxy]', 'fqdn'))
14
+ notice("vnc proxy host ${vnc_proxy_host}")
15
+
16
+ # glance api servers
@@ -0,0 +1,12 @@
1
+ # query for all nodes that have the package mysql-server applied to them
2
+ #$nodes = query_nodes('Package["mysql-server"]')
3
+ # query for all nodes that have the package my-server applied
4
+ # and that have the architecture of amd64
5
+ #$nodes = query_nodes('Package["mysql-server"] and architecture=amd64')
6
+ # return the fqdn fact for each node instead of the node_name
7
+ # munge to be unique if you dont want duplicates to cause failures
8
+ #$nodes = unique(query_nodes('Package["mysql-server"] and architecture=amd64', 'fqdn'))
9
+
10
+ $nodes = unique(query_nodes('Package["mysql-server"] and architecture=amd64', 'fqdn'))
11
+
12
+ notify { $nodes: }
@@ -0,0 +1,48 @@
1
+ #
2
+ # I need to be able to query for how to connect to things:
3
+
4
+
5
+ # I need to query the following things
6
+ # sql_connection
7
+ # mysql://nova:${nova_db_password}@${controller_node_internal}/nova
8
+ # rabbit_host
9
+ # rabbit_password
10
+ # rabbit_user
11
+
12
+ # for the rabbitmq host
13
+
14
+ # this syntax is a little strange ...
15
+ # it makes the resource look a little extraneous
16
+ $rabbit_resources = query_resource('Class[Nova::Rabbitmq]')
17
+
18
+ $rabbit_class = $rabbit_resources['Class[Nova::Rabbitmq]']
19
+ $rabbit_params = $rabbit_class['parameters']
20
+
21
+ # check that only one host has been found
22
+ $rabbit_host = unique(query_nodes('Class[Nova::Rabbitmq]', 'fqdn') )
23
+ notice("rabbit host: ${rabbit_host}")
24
+
25
+ $rabbit_port = $rabbit_params['port']
26
+ notice("rabbit port: ${rabbit_port}")
27
+ $rabbit_user = $rabbit_params['userid']
28
+ notice("rabbit user: ${rabbit_user}")
29
+ $rabbit_password = $rabbit_params['password']
30
+ notice("rabbit password: ${rabbit_password}")
31
+
32
+ # return the fqdn of the host that has applied
33
+ $vnc_proxy_host = unique(query_nodes('Class[Nova::Vncproxy]', 'fqdn'))
34
+ notice("vnc proxy host ${vnc_proxy_host}")
35
+ # check the size of this thing and make some decisions
36
+
37
+ # figure out sql connection
38
+ $nova_db_host = unique(query_nodes('Class[Nova::Db::Mysql]', 'fqdn'))
39
+ $nova_db_resources = query_resource('Class[Nova::Db::Mysql]', 'architecture=amd64')
40
+ $nova_db_class = $nova_db_resources['Class[Nova::Db::Mysql]']
41
+ $nova_db_params = $nova_db_class['parameters']
42
+ $nova_db_name = $nova_db_params['dbname']
43
+ $nova_db_user = $nova_db_params['user']
44
+ $nova_db_password = $nova_db_params['password']
45
+
46
+ $nova_sql_conn = "mysql://${nova_db_user}:${nova_db_password}@${nova_db_host}/${nova_db_name}"
47
+
48
+ notice("nova sql connection: ${nova_sql_conn}")
@@ -0,0 +1,22 @@
1
+ require 'puppet/application/face_base'
2
+
3
+ class Puppet::Application::Query < Puppet::Application::FaceBase
4
+ def self.setting
5
+ begin
6
+ require 'puppet'
7
+ require 'puppet/util/puppetdb'
8
+ host = Puppet::Util::Puppetdb.server || 'puppetdb'
9
+ port = Puppet::Util::Puppetdb.port || 8081
10
+ rescue Exception => e
11
+ Puppet.debug(e.message)
12
+ host = 'puppetdb'
13
+ port = 8081
14
+ end
15
+
16
+ Puppet.debug(host)
17
+ Puppet.debug(port)
18
+
19
+ { :host => host,
20
+ :port => port }
21
+ end
22
+ end
@@ -0,0 +1,60 @@
1
+ require 'puppet/application/query'
2
+ require 'puppet/face'
3
+ Puppet::Face.define(:query, '1.0.0') do
4
+ require 'puppetdb/connection'
5
+
6
+ copyright "Puppet Labs & Erik Dalén", 2012..2013
7
+ license "Apache 2 license; see COPYING"
8
+
9
+
10
+ option '--puppetdb_host PUPPETDB' do
11
+ summary "Host running PuppetDB. "
12
+ default_to { Puppet::Application::Query.setting[:host] }
13
+ end
14
+
15
+ option '--puppetdb_port PORT' do
16
+ summary 'Port PuppetDB is running on'
17
+ default_to { Puppet::Application::Query.setting[:port] }
18
+ end
19
+
20
+ action :facts do
21
+ summary 'Serves as an interface to puppetdb allowing a user to query for a list of nodes'
22
+
23
+ description <<-EOT
24
+ Here is a ton of more useful information :)
25
+ EOT
26
+
27
+ arguments "<query>"
28
+
29
+ option '--facts FACTS' do
30
+ summary 'facts to return that represent each host'
31
+ description <<-EOT
32
+ Filter for the fact subcommand can be used to specify the facts to filter for.
33
+ It accepts either a string or a comma delimited list of facts.
34
+ EOT
35
+ default_to { '' }
36
+ end
37
+
38
+ when_invoked do |query, options|
39
+ puppetdb = PuppetDB::Connection.new options[:puppetdb_host], options[:puppetdb_port]
40
+ puppetdb.facts(options[:facts].split(','), puppetdb.parse_query(query, :facts))
41
+ end
42
+
43
+ end
44
+
45
+ action :nodes do
46
+
47
+ summary 'Perform complex queries for nodes from PuppetDB'
48
+ description <<-EOT
49
+ Here is a ton of more useful information :)
50
+ EOT
51
+
52
+ arguments "<query>"
53
+
54
+ when_invoked do |query, options|
55
+ puppetdb = PuppetDB::Connection.new options[:puppetdb_host], options[:puppetdb_port]
56
+ puppetdb.query(:nodes, puppetdb.parse_query(query, :nodes))
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,31 @@
1
+ module Puppet::Parser::Functions
2
+ newfunction(:pdbfactquery, :type => :rvalue, :doc => "\
3
+ Perform a PuppetDB fact query
4
+
5
+ The first argument is the node to get facts for.
6
+ Second argument is optional, if specified only return that specific fact.
7
+
8
+ Examples:
9
+ # Get hash of facts for foo.example.com
10
+ pdbfactquery('foo.example.com')
11
+ # Get the uptime fact for foo.example.com
12
+ pdbfactquery('foo.example.com', 'uptime')") do |args|
13
+
14
+ raise(Puppet::ParseError, "pdbquery(): Wrong number of arguments " +
15
+ "given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
16
+
17
+ Puppet::Parser::Functions.autoloader.load(:pdbquery) unless Puppet::Parser::Functions.autoloader.loaded?(:pdbquery)
18
+
19
+ node, fact = args
20
+ if node.is_a?(Array) then
21
+ node.collect { |n| function_pdbfactquery([n,fact]) }
22
+ else
23
+ facts = function_pdbquery(["facts/#{args[0]}"])['facts']
24
+ if fact then
25
+ facts[fact]
26
+ else
27
+ facts
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ module Puppet::Parser::Functions
2
+ newfunction(:pdbnodequery, :type => :rvalue, :doc => "\
3
+ Perform a PuppetDB node query
4
+
5
+ The first argument is the node query, it has to be an array.
6
+ Second argument is optional but allows you to specify a resource query
7
+ that the nodes returned also have to match.
8
+
9
+ This function excludes any deactivated hosts.
10
+
11
+ Returns a array of strings with the certname of the nodes (fqdn by default).
12
+
13
+ # Return an array of active nodes with an uptime more than 30 days
14
+ $ret = pdbnodequery(['>',['fact','uptime_days'],30])
15
+
16
+ # Return an array of active nodes with an uptime more than 30 days and
17
+ # having the class 'apache'
18
+ $ret = pdbnodequery(['>',['fact','uptime_days'],30], ['and',['=','type','Class'],['=','title','Apache']])") do |args|
19
+
20
+ raise(Puppet::ParseError, "pdbquery(): Wrong number of arguments " +
21
+ "given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
22
+
23
+ Puppet::Parser::Functions.autoloader.load(:pdbquery) unless Puppet::Parser::Functions.autoloader.loaded?(:pdbquery)
24
+ Puppet::Parser::Functions.autoloader.load(:pdbresourcequery) unless Puppet::Parser::Functions.autoloader.loaded?(:pdbresourcequery)
25
+
26
+ nodeq, resq = args
27
+
28
+ nodeqnodes = function_pdbquery(['nodes', ['and',['=',['node','active'],true],nodeq] ])
29
+
30
+ if resq then
31
+ resqnodes = function_pdbresourcequery([resq, 'certname'])
32
+ nodeqnodes & resqnodes
33
+ else
34
+ # No resource query to worry about, just return the nodequery
35
+ nodeqnodes
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,40 @@
1
+ module Puppet::Parser::Functions
2
+ newfunction(:pdbnodequery_all, :type => :rvalue, :doc => "\
3
+ Perform a PuppetDB node query
4
+
5
+ The first argument is the node query.
6
+ Second argument is optional but allows you to specify a resource query
7
+ that the nodes returned also have to match.
8
+
9
+ Returns a array of strings with the certname of the nodes (fqdn by default).
10
+
11
+ # Return an array of both active and deactivaded nodes with an uptime more than 30 days
12
+ $ret = pdbnodequery_all(['and',['>',['fact','uptime_days'],30]])
13
+
14
+ # Return an array of both active and deactivated nodes with an uptime more
15
+ # than 30 days and having the class 'apache'
16
+ $ret = pdbnodequery_all(
17
+ ['>',['fact','uptime_days'],30],
18
+ ['and',
19
+ ['=','type','Class'],
20
+ ['=','title','Apache']])") do |args|
21
+
22
+ raise(Puppet::ParseError, "pdbquery_all(): Wrong number of arguments " +
23
+ "given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
24
+
25
+ Puppet::Parser::Functions.autoloader.load(:pdbquery) unless Puppet::Parser::Functions.autoloader.loaded?(:pdbquery)
26
+ Puppet::Parser::Functions.autoloader.load(:pdbresourcequery_all) unless Puppet::Parser::Functions.autoloader.loaded?(:pdbresourcequery_all)
27
+
28
+ nodeq, resq = args
29
+
30
+ nodeqnodes = function_pdbquery(['nodes', nodeq])
31
+
32
+ if resq then
33
+ resqnodes = function_pdbresourcequery_all([resq, 'certname'])
34
+ nodeqnodes & resqnodes
35
+ else
36
+ # No resource query to worry about, just return the nodequery
37
+ nodeqnodes
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ module Puppet::Parser::Functions
2
+ newfunction(:pdbquery, :type => :rvalue, :doc => "\
3
+ Perform a PuppetDB query
4
+
5
+ The first argument is the URL path that should be queried, for
6
+ example 'nodes' or 'status/nodes/<nodename>'.
7
+ The second argument if supplied if the query parameter, if it is
8
+ a string it is assumed to be JSON formatted and sent as is,
9
+ anything else is converted to JSON and then sent.
10
+
11
+ Example: pdbquery('nodes', ['=', ['node', 'active'], true ])") do |args|
12
+
13
+ raise(Puppet::ParseError, "pdbquery(): Wrong number of arguments " +
14
+ "given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
15
+
16
+ require 'puppet/network/http_pool'
17
+ require 'uri'
18
+ require 'puppet/util/puppetdb'
19
+ require 'puppet/indirector/rest'
20
+
21
+ # Query type (URL path)
22
+ t, q = args
23
+
24
+ # Query contents
25
+ if q then
26
+ # Convert to JSON if it isn't already
27
+ q=q.to_pson unless q.is_a? String
28
+ params = URI.escape("?query=#{q}")
29
+ else
30
+ params = ''
31
+ end
32
+
33
+ conn = Puppet::Network::HttpPool.http_instance(Puppet::Util::Puppetdb.server, Puppet::Util::Puppetdb.port, use_ssl = true)
34
+ response = conn.get("/v1/#{t}#{params}", { "Accept" => "application/json",})
35
+
36
+ unless response.kind_of?(Net::HTTPSuccess)
37
+ raise Puppet::ParseError, "PuppetDB query error: [#{response.code}] #{response.msg}"
38
+ end
39
+ PSON.load(response.body)
40
+ end
41
+ end
@@ -0,0 +1,39 @@
1
+ module Puppet::Parser::Functions
2
+ newfunction(:pdbresourcequery, :type => :rvalue, :doc => "\
3
+ Perform a PuppetDB resource query
4
+
5
+ The first argument is the resource query, it has to be an array.
6
+ Second argument is optional but allows you to specify the item you want
7
+ from the returned hash.
8
+
9
+ This function excludes any deactivated hosts.
10
+
11
+ Returns an array of hashes or array of strings if second argument is provided.
12
+
13
+ Examples:
14
+ # Return an array of hashes describing all files that are owned by root on active hosts.
15
+ $ret = pdbresourcequery(
16
+ ['and',
17
+ ['=','type','File'],
18
+ ['=',['parameter','owner'],'root']])
19
+
20
+ # Return an array of host names having those resources
21
+ $ret = pdbresourcequery(
22
+ ['and',
23
+ ['=','type','File'],
24
+ ['=',['parameter','owner'],'root']], 'certname')") do |args|
25
+
26
+ raise(Puppet::ParseError, "pdbresourcequery(): Wrong number of arguments " +
27
+ "given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
28
+
29
+ Puppet::Parser::Functions.autoloader.load(:pdbquery) unless Puppet::Parser::Functions.autoloader.loaded?(:pdbquery)
30
+
31
+ resq, info = args
32
+ ret = function_pdbquery(['resources', ['and',['=',['node','active'],true],resq] ])
33
+ if info then
34
+ ret.collect {|x| x[info]}
35
+ else
36
+ ret
37
+ end
38
+ end
39
+ end