hieracles 0.2.0 → 0.2.1
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile +2 -0
- data/README.md +54 -8
- data/bin/hc +12 -6
- data/bin/ppdb +42 -0
- data/hc.1 +50 -8
- data/lib/hieracles.rb +2 -2
- data/lib/hieracles/config.rb +31 -19
- data/lib/hieracles/format.rb +4 -0
- data/lib/hieracles/formats/console.rb +49 -16
- data/lib/hieracles/formats/csv.rb +12 -8
- data/lib/hieracles/formats/json.rb +19 -6
- data/lib/hieracles/formats/plain.rb +24 -3
- data/lib/hieracles/formats/rawyaml.rb +4 -0
- data/lib/hieracles/formats/yaml.rb +4 -0
- data/lib/hieracles/node.rb +55 -10
- data/lib/hieracles/notification.rb +31 -0
- data/lib/hieracles/options/hc.rb +109 -0
- data/lib/hieracles/options/ppdb.rb +32 -0
- data/lib/hieracles/optparse.rb +4 -43
- data/lib/hieracles/puppetdb.rb +12 -0
- data/lib/hieracles/puppetdb/apierror.rb +10 -0
- data/lib/hieracles/puppetdb/client.rb +63 -0
- data/lib/hieracles/puppetdb/filter.rb +15 -0
- data/lib/hieracles/puppetdb/fixsslconnectionadapter.rb +25 -0
- data/lib/hieracles/puppetdb/query.rb +79 -0
- data/lib/hieracles/puppetdb/request.rb +44 -0
- data/lib/hieracles/puppetdb/response.rb +14 -0
- data/ppdb.1 +158 -0
- data/spec/files/config.yml +2 -0
- data/spec/files/config_withdb.yml +9 -0
- data/spec/files/facts.json +110 -0
- data/spec/files/facts.yaml +103 -0
- data/spec/files/hiera_columns.yaml +16 -0
- data/spec/files/hiera_deep.yaml +17 -0
- data/spec/files/hiera_deeper.yaml +17 -0
- data/spec/files/ssl/bad-ca.crt +1 -0
- data/spec/files/ssl/bad-cert.crt +1 -0
- data/spec/files/ssl/bad-key.pem +1 -0
- data/spec/files/ssl/ca.crt +16 -0
- data/spec/files/ssl/cert.crt +16 -0
- data/spec/files/ssl/key-pass.pem +18 -0
- data/spec/files/ssl/key.pem +15 -0
- data/spec/lib/config_spec.rb +51 -11
- data/spec/lib/format_spec.rb +5 -0
- data/spec/lib/formats/console_spec.rb +24 -3
- data/spec/lib/formats/csv_spec.rb +15 -0
- data/spec/lib/formats/json_spec.rb +22 -2
- data/spec/lib/formats/plain_spec.rb +23 -3
- data/spec/lib/formats/rawyaml_spec.rb +13 -0
- data/spec/lib/formats/yaml_spec.rb +138 -48
- data/spec/lib/hiera_spec.rb +0 -1
- data/spec/lib/hieracles_spec.rb +8 -0
- data/spec/lib/interpolate_spec.rb +49 -0
- data/spec/lib/node_spec.rb +50 -9
- data/spec/lib/notification_spec.rb +29 -0
- data/spec/lib/options/hc_spec.rb +82 -0
- data/spec/lib/optparse_spec.rb +7 -7
- data/spec/lib/puppetdb/apierror_spec.rb +11 -0
- data/spec/lib/puppetdb/client_spec.rb +64 -0
- data/spec/lib/puppetdb/fixsslconnectionadapter_spec.rb +107 -0
- data/spec/lib/puppetdb/query_spec.rb +39 -0
- data/spec/lib/puppetdb/request_spec.rb +61 -0
- data/spec/lib/puppetdb/response_spec.rb +13 -0
- data/spec/spec_helper.rb +4 -4
- metadata +133 -30
- data/Rakefile +0 -14
- data/hieracles.gemspec +0 -90
- data/lib/hieracles/help.rb +0 -38
- data/spec/lib/help_spec.rb +0 -8
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'hieracles/optparse'
|
2
|
+
|
3
|
+
module Hieracles
|
4
|
+
module Options
|
5
|
+
class Ppdb < Hieracles::Optparse
|
6
|
+
|
7
|
+
def available_options
|
8
|
+
{
|
9
|
+
version: {
|
10
|
+
has_arg: false,
|
11
|
+
aliases: ['v', 'version']
|
12
|
+
}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.usage
|
17
|
+
return <<-END
|
18
|
+
|
19
|
+
Usage: ppdb <endpoint> <command> [extra_args]
|
20
|
+
|
21
|
+
Available commands:
|
22
|
+
node info <fqdn>
|
23
|
+
node facts <fqdn>
|
24
|
+
node resources <fqdn>
|
25
|
+
|
26
|
+
END
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/lib/hieracles/optparse.rb
CHANGED
@@ -4,48 +4,9 @@ module Hieracles
|
|
4
4
|
|
5
5
|
attr_reader :options, :payload
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
aliases: ['c', 'conf', 'config']
|
11
|
-
},
|
12
|
-
format: {
|
13
|
-
has_arg: true,
|
14
|
-
aliases: ['f', 'format']
|
15
|
-
},
|
16
|
-
params: {
|
17
|
-
has_arg: true,
|
18
|
-
aliases: ['p', 'params']
|
19
|
-
},
|
20
|
-
hierafile: {
|
21
|
-
has_arg: true,
|
22
|
-
aliases: ['h', 'hierafile']
|
23
|
-
},
|
24
|
-
basepath: {
|
25
|
-
has_arg: true,
|
26
|
-
aliases: ['b', 'basepath']
|
27
|
-
},
|
28
|
-
encpath: {
|
29
|
-
has_arg: true,
|
30
|
-
aliases: ['e', 'encpath']
|
31
|
-
},
|
32
|
-
version: {
|
33
|
-
has_arg: false,
|
34
|
-
aliases: ['v', 'version']
|
35
|
-
},
|
36
|
-
yaml_facts: {
|
37
|
-
has_arg: true,
|
38
|
-
aliases: ['y', 'yaml']
|
39
|
-
},
|
40
|
-
json_facts: {
|
41
|
-
has_arg: true,
|
42
|
-
aliases: ['j', 'json']
|
43
|
-
},
|
44
|
-
interactive: {
|
45
|
-
has_arg: false,
|
46
|
-
aliases: ['i', 'interactive']
|
47
|
-
}
|
48
|
-
}
|
7
|
+
def available_options
|
8
|
+
{}
|
9
|
+
end
|
49
10
|
|
50
11
|
def initialize(array)
|
51
12
|
@options = {}
|
@@ -71,7 +32,7 @@ module Hieracles
|
|
71
32
|
|
72
33
|
def optionkeys
|
73
34
|
back = {}
|
74
|
-
|
35
|
+
available_options.each do |k, v|
|
75
36
|
v[:aliases].each do |a|
|
76
37
|
back[a] = { var: k, has_args: v[:has_arg] }
|
77
38
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'hieracles/puppetdb/fixsslconnectionadapter'
|
2
|
+
require 'hieracles/puppetdb/apierror'
|
3
|
+
require 'hieracles/puppetdb/query'
|
4
|
+
require 'hieracles/puppetdb/filter'
|
5
|
+
require 'hieracles/puppetdb/client'
|
6
|
+
require 'hieracles/puppetdb/request'
|
7
|
+
require 'hieracles/puppetdb/response'
|
8
|
+
|
9
|
+
module Hieracles
|
10
|
+
module Puppetdb
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module Hieracles
|
4
|
+
module Puppetdb
|
5
|
+
class Client
|
6
|
+
include HTTParty
|
7
|
+
|
8
|
+
def initialize(options, version = 3)
|
9
|
+
@version = version
|
10
|
+
setup_if_ssl(options)
|
11
|
+
options['port'] ||= 8080
|
12
|
+
options['host'] ||= 'localhost'
|
13
|
+
scheme = options['usessl'] ? "https://" : "http://"
|
14
|
+
self.class.base_uri(scheme +
|
15
|
+
options['host'] +
|
16
|
+
':' + options['port'].to_s +
|
17
|
+
'/v' + @version.to_s())
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup_if_ssl(options)
|
21
|
+
if options['usessl']
|
22
|
+
self.class.default_options = {:options => options}
|
23
|
+
self.class.connection_adapter(FixSSLConnectionAdapter)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def request(endpoint, method = 'get', query = nil, opts = {})
|
28
|
+
ret = send("#{method}_request".to_sym, endpoint, query, opts)
|
29
|
+
if ret.code.to_s() =~ /^[4|5]/ or ret.parsed_response.length < 1
|
30
|
+
notifications = [ Hieracles::Notification.new('puppetdb', 'No match.', 'error') ]
|
31
|
+
Response.new({}, 0, notifications)
|
32
|
+
else
|
33
|
+
total = ret.headers['X-Records']
|
34
|
+
if total.nil?
|
35
|
+
total = ret.parsed_response.length
|
36
|
+
end
|
37
|
+
|
38
|
+
Response.new(ret.parsed_response, total)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_request(endpoint, query, opts)
|
43
|
+
path = "/" + endpoint
|
44
|
+
if query
|
45
|
+
json_query = JSON.dump(query)
|
46
|
+
filtered_opts = {'query' => json_query}
|
47
|
+
opts.each do |k,v|
|
48
|
+
if k == :counts_filter
|
49
|
+
filtered_opts['counts-filter'] = JSON.dump(v)
|
50
|
+
else
|
51
|
+
filtered_opts[k.to_s.sub("_", "-")] = v
|
52
|
+
end
|
53
|
+
end
|
54
|
+
puts path ; puts filtered_opts ; exit(0)
|
55
|
+
self.class.get(path, query: filtered_opts)
|
56
|
+
else
|
57
|
+
self.class.get(path)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module Hieracles
|
4
|
+
module Puppetdb
|
5
|
+
class FixSSLConnectionAdapter < HTTParty::ConnectionAdapter
|
6
|
+
def attach_ssl_certificates(http, options)
|
7
|
+
raise(IOError, "Cert file #{options['cert']} not found.") unless File.exist? options['cert'].to_s
|
8
|
+
raise(IOError, "Key file #{options['key']} not found.") unless File.exist? options['key']
|
9
|
+
raise(IOError, "CA file #{options['ca_file']} not found.") unless File.exist? options['ca_file']
|
10
|
+
http.cert = OpenSSL::X509::Certificate.new(File.read(options['cert']))
|
11
|
+
if options['key_password']
|
12
|
+
http.key = OpenSSL::PKey::RSA.new(File.read(options['key']), options['key_password'])
|
13
|
+
else
|
14
|
+
http.key = OpenSSL::PKey::RSA.new(File.read(options['key']))
|
15
|
+
end
|
16
|
+
http.ca_file = options['ca_file']
|
17
|
+
if options['verify_peer']
|
18
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
19
|
+
else
|
20
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Hieracles
|
2
|
+
module Puppetdb
|
3
|
+
class Query
|
4
|
+
|
5
|
+
def initialize(elements)
|
6
|
+
@elements = parse(elements)
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse(elements)
|
10
|
+
items = []
|
11
|
+
index = 0
|
12
|
+
if elements.length > 1
|
13
|
+
elements.each do |e|
|
14
|
+
puts items.inspect
|
15
|
+
if e == 'or'
|
16
|
+
index++
|
17
|
+
continue
|
18
|
+
end
|
19
|
+
if /(.*)(>|<|=|!=|~)(.*)/.match e
|
20
|
+
items[index] ||= []
|
21
|
+
items[index] << [$2, $1, $3]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
else
|
25
|
+
if /(.*)(>|<|=|!=|~)(.*)/.match elements[0]
|
26
|
+
items = [$2, $1, $3]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
items
|
30
|
+
end
|
31
|
+
|
32
|
+
def output
|
33
|
+
back = []
|
34
|
+
if @elements.length > 1
|
35
|
+
back << 'or'
|
36
|
+
@elements.each do |e|
|
37
|
+
back << build_and(e)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
@elements.each do |e|
|
41
|
+
back << build_and(e)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
back
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_and(arrays)
|
48
|
+
if arrays.length > 1
|
49
|
+
['and', arrays]
|
50
|
+
else
|
51
|
+
arrays
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def defined?
|
56
|
+
@elements.count > 0
|
57
|
+
end
|
58
|
+
|
59
|
+
def match(item)
|
60
|
+
@elements.each do |e|
|
61
|
+
matched = false
|
62
|
+
e.each do |a|
|
63
|
+
case a[0]
|
64
|
+
when '='
|
65
|
+
|
66
|
+
when '!='
|
67
|
+
when '<'
|
68
|
+
when '>'
|
69
|
+
when '!'
|
70
|
+
else
|
71
|
+
end
|
72
|
+
end
|
73
|
+
return true if matched
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Hieracles
|
2
|
+
module Puppetdb
|
3
|
+
class Request
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@client = Hieracles::Puppetdb::Client.new options
|
7
|
+
end
|
8
|
+
|
9
|
+
def node_info(fqdn)
|
10
|
+
@client.request("nodes/#{fqdn}")
|
11
|
+
end
|
12
|
+
alias_method :node_infos, :node_info
|
13
|
+
|
14
|
+
def node_facts(fqdn, regex = //)
|
15
|
+
resp = @client.request("nodes/#{fqdn}/facts")
|
16
|
+
filter = Filter.new regex
|
17
|
+
resp.data = resp.data.reduce({}) do |a, d|
|
18
|
+
if filter.match(d['name'])
|
19
|
+
a[d['name'].to_sym] = d['value']
|
20
|
+
end
|
21
|
+
a
|
22
|
+
end
|
23
|
+
resp
|
24
|
+
end
|
25
|
+
alias_method :node_fact, :node_facts
|
26
|
+
|
27
|
+
def node_resources(fqdn, *args)
|
28
|
+
resp = @client.request("nodes/#{fqdn}/resources")
|
29
|
+
field = args.shift
|
30
|
+
resp.data = resp.data.reduce({}) do |a, d|
|
31
|
+
if !field || Regexp.new(field).match(d['title'])
|
32
|
+
a[d['title']] = d
|
33
|
+
end
|
34
|
+
a
|
35
|
+
end
|
36
|
+
resp
|
37
|
+
end
|
38
|
+
alias_method :node_res, :node_resources
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Hieracles
|
2
|
+
module Puppetdb
|
3
|
+
class Response
|
4
|
+
attr_reader :data, :total_records, :notifications
|
5
|
+
attr_writer :data
|
6
|
+
|
7
|
+
def initialize(data, total_records = nil, notifications = nil)
|
8
|
+
@data = data
|
9
|
+
@total_records = total_records
|
10
|
+
@notifications = notifications
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/ppdb.1
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
.TH ppdb 1 "2015-12-05" "version 0.2.1" "Hieracles command manual"
|
2
|
+
|
3
|
+
.SH NAME
|
4
|
+
ppdb \- Command line tool to query puppetdb
|
5
|
+
.SH SYNOPSIS
|
6
|
+
.B ppdb
|
7
|
+
.I object
|
8
|
+
.I command
|
9
|
+
.B [
|
10
|
+
.I options
|
11
|
+
.B ]
|
12
|
+
|
13
|
+
.SH DESCRIPTION
|
14
|
+
.PP
|
15
|
+
This tool is part of the Hieracles tools suite.
|
16
|
+
.PP
|
17
|
+
PuppetDB stores information gathered by Puppet when nodes run
|
18
|
+
the puppet client. It exposes a very neat REST interface, but
|
19
|
+
its query system can be a little complicated.
|
20
|
+
.PP
|
21
|
+
The purpose of
|
22
|
+
.B ppdb
|
23
|
+
is to overlay the calls to the REST API and propose a more
|
24
|
+
user-friendly way to query the Puppet Database (puppetdb).
|
25
|
+
.PP
|
26
|
+
Note that this tool is designed to work fine with the version 3
|
27
|
+
of the PuppetDB API.
|
28
|
+
.PP
|
29
|
+
Ref http://docs.puppetlabs.com/puppetdb/2.3/api/
|
30
|
+
.PP
|
31
|
+
.B ppdb
|
32
|
+
takes at minimum 2 arguments, an object (or endpoint)
|
33
|
+
and a subcommand, plus extra parameters depending the subcommand.
|
34
|
+
.PP
|
35
|
+
The object is like the endpoint in PuppetDB API, but we extend it
|
36
|
+
to a different list of possible objects:
|
37
|
+
|
38
|
+
.IP node 10
|
39
|
+
Uses the nodes endpoint. It accepts the subcommands:
|
40
|
+
.RS
|
41
|
+
|
42
|
+
.IP info 10
|
43
|
+
will display the equivalent of
|
44
|
+
.I "GET /v3/nodes/<NODE>"
|
45
|
+
and takes the node
|
46
|
+
.B certname
|
47
|
+
as an argument.
|
48
|
+
.RS 10
|
49
|
+
Optionaly, you can add a filter to limit what fields are displayed.
|
50
|
+
.TP
|
51
|
+
eg. ppdb node info <fqdn>
|
52
|
+
.RS
|
53
|
+
will display all the fields from the API response
|
54
|
+
.RE
|
55
|
+
eg. ppdb node info <fqdn> time
|
56
|
+
.RS
|
57
|
+
will only display the fields containing
|
58
|
+
.I time
|
59
|
+
in their label.
|
60
|
+
.RE
|
61
|
+
.RE
|
62
|
+
|
63
|
+
.IP facts 10
|
64
|
+
will display the equivalent of
|
65
|
+
.I "GET /v3/nodes/<NODE>/facts"
|
66
|
+
and takes the node
|
67
|
+
.B certname
|
68
|
+
as an argument.
|
69
|
+
.RS 10
|
70
|
+
As the result can be verbose, you can add a filter to limit what
|
71
|
+
fields are displayed.
|
72
|
+
.TP
|
73
|
+
eg. ppdb node facts <fqdn>
|
74
|
+
.RS
|
75
|
+
will display all the fields from the API response
|
76
|
+
.RE
|
77
|
+
eg. ppdb node facts <fqdn> memory
|
78
|
+
.RS
|
79
|
+
will only display the fields containing
|
80
|
+
.I memory
|
81
|
+
in their label.
|
82
|
+
.RE
|
83
|
+
.RE
|
84
|
+
|
85
|
+
.IP resources 10
|
86
|
+
will display the equivalent of
|
87
|
+
.I "GET /v3/nodes/<NODE>/resources"
|
88
|
+
and takes the node
|
89
|
+
.B certname
|
90
|
+
as an argument. You can use
|
91
|
+
.I res
|
92
|
+
instead of
|
93
|
+
.I resources
|
94
|
+
for shorter.
|
95
|
+
.RS 10
|
96
|
+
As the result can be verbose, you can add a filter to limit what
|
97
|
+
resources are displayed.
|
98
|
+
.TP
|
99
|
+
eg. ppdb node res <fqdn>
|
100
|
+
.RS
|
101
|
+
will display all the fields from the API response
|
102
|
+
.RE
|
103
|
+
eg. ppdb node res <fqdn> nagios
|
104
|
+
.RS
|
105
|
+
will only display the fields containing
|
106
|
+
.I nagios
|
107
|
+
in their label.
|
108
|
+
.RE
|
109
|
+
.RE
|
110
|
+
|
111
|
+
.SH OPTIONS
|
112
|
+
|
113
|
+
.TP
|
114
|
+
.PD 0
|
115
|
+
.B \-v
|
116
|
+
.TP
|
117
|
+
.PD
|
118
|
+
.B \-\-version
|
119
|
+
outputs version.
|
120
|
+
|
121
|
+
|
122
|
+
.SH FILES
|
123
|
+
.I ~/.config/hieracles/config.yaml
|
124
|
+
.RS
|
125
|
+
ppdb uses the same configuration file as hieracles, and relies on
|
126
|
+
its information to find the url of the PuppetDB
|
127
|
+
|
128
|
+
.SH EXAMPLES
|
129
|
+
A typical config file would contain, at minimum:
|
130
|
+
.PP
|
131
|
+
.RS
|
132
|
+
---
|
133
|
+
.RE
|
134
|
+
.RS
|
135
|
+
puppetdb:
|
136
|
+
.RS
|
137
|
+
usessl: false
|
138
|
+
.RE
|
139
|
+
.RS
|
140
|
+
host: localhost
|
141
|
+
.RE
|
142
|
+
.RS
|
143
|
+
port: 8080
|
144
|
+
.RE
|
145
|
+
.RE
|
146
|
+
|
147
|
+
.SH SEE ALSO
|
148
|
+
hiera(1), puppet(8), hc(1)
|
149
|
+
|
150
|
+
.SH BUGS
|
151
|
+
Please report any bug to https://github.com/Gandi/hieracles/issues
|
152
|
+
|
153
|
+
.SH AUTHORS
|
154
|
+
Copyright (c) 2015 gandi.net https://gandi.net
|
155
|
+
.LP
|
156
|
+
Hieracles is written by mose@gandi.net
|
157
|
+
.LP
|
158
|
+
https://github.com/Gandi/hieracles
|