pl-puppetdb-ruby 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d0a1afa1ff2b6914268c1cc3872c03bc00ccf34e
4
+ data.tar.gz: f9293bb504fcb8aef8876db1887c269bdf2afae5
5
+ SHA512:
6
+ metadata.gz: b5b66af95faddc9f0355c5e1ff0ef7a617cb32fb6ec883cbb3cfdf2701773ee65b374621ec7165a8a2f9c8f20cd736943c0b4ca009672c1bf3317cf0ecca6846
7
+ data.tar.gz: 8eb00096fad175271a91fd77552dbbb056ca8a0b3fe3c130aa21ba51b9e951d6942ee2f3e992291fece5608fd5cf279d4f3fbc2c7a34328c3260a9321360b851
data/CHANGELOG.md ADDED
@@ -0,0 +1,71 @@
1
+ # Change log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ Each new release typically also includes the latest modulesync defaults.
5
+ These should not impact the functionality of the module.
6
+
7
+ ## Unreleased
8
+
9
+ **Implemented enhancements:**
10
+
11
+ - Add AccessDeniedError, UnauthorizedError and ForbiddenError exceptions
12
+ - Silence warnings about unspecified exception types in spec tests
13
+ - Add support for Puppet Enterprise RBAC token authentication
14
+ - Add support for loading configuration defaults from Puppet Enterprise Client Tools configuration files
15
+ <https://puppet.com/docs/pe/2018.1/installing_pe_client_tools.html#configuring-and-using-client-tools>
16
+
17
+ ## [v1.1.1](https://github.com/voxpupuli/puppetdb-ruby/tree/v1.1.1) (2017-08-17)
18
+ [Full Changelog](https://github.com/voxpupuli/puppetdb-ruby/compare/1.1.0...v1.1.1)
19
+
20
+ **Fixed bugs:**
21
+
22
+ - Rubygem is broken for 1.1.0 [\#31](https://github.com/voxpupuli/puppetdb-ruby/issues/31)
23
+
24
+ **Merged pull requests:**
25
+
26
+ - Add badges [\#30](https://github.com/voxpupuli/puppetdb-ruby/pull/30) ([raphink](https://github.com/raphink))
27
+
28
+ ## [1.1.0](https://github.com/voxpupuli/puppetdb-ruby/tree/1.1.0) (2017-08-17)
29
+ [Full Changelog](https://github.com/voxpupuli/puppetdb-ruby/compare/1.0.0...1.1.0)
30
+
31
+ **Closed issues:**
32
+
33
+ - Improve documentation [\#22](https://github.com/voxpupuli/puppetdb-ruby/issues/22)
34
+ - support for PQL in PuppetDB::Query [\#16](https://github.com/voxpupuli/puppetdb-ruby/issues/16)
35
+ - Any plans to revive this project? [\#12](https://github.com/voxpupuli/puppetdb-ruby/issues/12)
36
+
37
+ **Merged pull requests:**
38
+
39
+ - Add PQL support [\#28](https://github.com/voxpupuli/puppetdb-ruby/pull/28) ([raphink](https://github.com/raphink))
40
+
41
+ ## [1.0.0](https://github.com/voxpupuli/puppetdb-ruby/tree/1.0.0) (2017-08-02)
42
+ **Implemented enhancements:**
43
+
44
+ - Preparatory cleanup for refactor [\#21](https://github.com/voxpupuli/puppetdb-ruby/pull/21) ([dhollinger](https://github.com/dhollinger))
45
+ - Allow usage of unauthenticated PuppetDB over SSL [\#14](https://github.com/voxpupuli/puppetdb-ruby/pull/14) ([cassianoleal](https://github.com/cassianoleal))
46
+
47
+ **Closed issues:**
48
+
49
+ - Refactor to support v4 endpoints [\#20](https://github.com/voxpupuli/puppetdb-ruby/issues/20)
50
+ - API V4 Example [\#13](https://github.com/voxpupuli/puppetdb-ruby/issues/13)
51
+ - 'summarize-by' parameter not supported [\#9](https://github.com/voxpupuli/puppetdb-ruby/issues/9)
52
+ - Thanks! [\#6](https://github.com/voxpupuli/puppetdb-ruby/issues/6)
53
+ - Only GET requests supported [\#4](https://github.com/voxpupuli/puppetdb-ruby/issues/4)
54
+
55
+ **Merged pull requests:**
56
+
57
+ - rename gemspec to fix deploy [\#27](https://github.com/voxpupuli/puppetdb-ruby/pull/27) ([dhollinger](https://github.com/dhollinger))
58
+ - Remove branches restriction in travis.yml [\#26](https://github.com/voxpupuli/puppetdb-ruby/pull/26) ([dhollinger](https://github.com/dhollinger))
59
+ - Add rubygems deploy key [\#25](https://github.com/voxpupuli/puppetdb-ruby/pull/25) ([dhollinger](https://github.com/dhollinger))
60
+ - Release 1.0.0 [\#24](https://github.com/voxpupuli/puppetdb-ruby/pull/24) ([dhollinger](https://github.com/dhollinger))
61
+ - Update Docs for Release 1.0.0 [\#23](https://github.com/voxpupuli/puppetdb-ruby/pull/23) ([dhollinger](https://github.com/dhollinger))
62
+ - Add command API support [\#19](https://github.com/voxpupuli/puppetdb-ruby/pull/19) ([bekbulatov](https://github.com/bekbulatov))
63
+ - \(maint\) Transfer ownership to Vox Pupuli [\#18](https://github.com/voxpupuli/puppetdb-ruby/pull/18) ([rlinehan](https://github.com/rlinehan))
64
+ - "Voxpupulify" [\#17](https://github.com/voxpupuli/puppetdb-ruby/pull/17) ([nibalizer](https://github.com/nibalizer))
65
+ - Add Contributing Guidelines [\#7](https://github.com/voxpupuli/puppetdb-ruby/pull/7) ([rlinehan](https://github.com/rlinehan))
66
+ - Feature/fix readme [\#3](https://github.com/voxpupuli/puppetdb-ruby/pull/3) ([robinbowes](https://github.com/robinbowes))
67
+ - Update README with correct initialization of client [\#1](https://github.com/voxpupuli/puppetdb-ruby/pull/1) ([ccaum](https://github.com/ccaum))
68
+
69
+
70
+
71
+ \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
data/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ puppetdb-ruby
2
+
3
+ Copyright (C) 2013 Puppet Labs Inc
4
+
5
+ Puppet Labs can be contacted at: info@puppetlabs.com
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,248 @@
1
+ # puppetdb-ruby
2
+
3
+ [![Build Status](https://img.shields.io/travis/voxpupuli/puppetdb-ruby.svg)](https://travis-ci.org/voxpupuli/puppetdb-ruby)
4
+ [![Gem Version](https://img.shields.io/gem/v/puppetdb-ruby.svg)](https://rubygems.org/gems/puppetdb-ruby)
5
+ [![Gem Downloads](https://img.shields.io/gem/dt/puppetdb-ruby.svg)](https://rubygems.org/gems/puppetdb-ruby)
6
+ [![By VoxPupuli](https://img.shields.io/badge/voxpupuli-%F0%9F%90%B1-orange.svg)](https://voxpupuli.org/)
7
+
8
+ a simple gem for interacting with the
9
+ [PuppetDB](https://github.com/puppetlabs/puppetdb) API.
10
+
11
+ This library was migrated from [puppetlabs](https://github.com/puppetlabs)
12
+ ownership to VoxPupuli on 19 October 2016.
13
+
14
+ ## Installation
15
+
16
+ Installing from Ruby CLI:
17
+ ```
18
+ gem install puppetdb-ruby
19
+ ```
20
+
21
+ Include in Gemfile:
22
+ ``` ruby
23
+ gem 'puppetdb-ruby'
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ Require the puppetdb gem in your ruby code.
29
+
30
+ ```ruby
31
+ require 'puppetdb'
32
+
33
+ # Defaults to latest API version.
34
+ ```
35
+
36
+ #### Create a new connection:
37
+
38
+ Non-SSL:
39
+ ``` ruby
40
+ client = PuppetDB::Client.new({:server => 'http://localhost:8080'})
41
+ ```
42
+
43
+ SSL with cert-based authentication:
44
+ ``` ruby
45
+ client = PuppetDB::Client.new({
46
+ server_urls: 'https://localhost:8081',
47
+ cacert: '/path/to/ca.pem'
48
+ cert: '/path/to/certfile.pem',
49
+ key: '/path/to/keyfile.pem'
50
+ })
51
+ ```
52
+
53
+ SSL with PE RBAC token based authentication:
54
+ ``` ruby
55
+ client = PuppetDB::Client.new({
56
+ :server_urls => "https://localhost:8081",
57
+ :token => "my_pe_rbac_token",
58
+ :cacert => "/path/to/cacert.pem",
59
+ })
60
+ ```
61
+
62
+ Configure connections to multiple PuppetDB's via `server_urls`
63
+ ``` ruby
64
+ client = PuppetDB::Client.new({
65
+ :server_urls => "https://localhost:8081,https://localhost:8083",
66
+ :token => "my_pe_rbac_token",
67
+ :cacert => "/path/to/cacert.pem",
68
+ })
69
+ ```
70
+
71
+ SSL with PE RBAC token based authentication, using all settings from PE Client Tools configurations:
72
+ ``` ruby
73
+ client = PuppetDB::Client.new()
74
+ ```
75
+
76
+ Note: When using cert-based authentication you must specify the full pem structure. When using token based authentication
77
+ you must NOT provide the pem structure and instead pass ':token' and ':cacert' (or allow them to be read from the
78
+ PE Client Tools configuration).
79
+
80
+ #### Query API usage
81
+
82
+ The Query Feature allows the user to request data from PuppetDB using the Query endpoints. It defaults to the latest version of the Query Endpoint.
83
+
84
+ Currently, `puppetdb-ruby` only supports the [AST Query Language](https://docs.puppet.com/puppetdb/5.0/api/query/v4/ast.html).
85
+
86
+ Support for the [PQL Query Language](https://docs.puppet.com/puppetdb/5.0/api/query/tutorial-pql.html) is planned for a future release.
87
+
88
+ Example:
89
+ ``` ruby
90
+ response = client.request(
91
+ 'nodes',
92
+ [:and,
93
+ [:'=', ['fact', 'kernel'], 'Linux'],
94
+ [:>, ['fact', 'uptime_days'], 30]
95
+ ],
96
+ {:limit => 10}
97
+ )
98
+
99
+ nodes = response.data
100
+
101
+ # queries are composable
102
+
103
+ uptime = PuppetDB::Query[:>, [:fact, 'uptime_days'], 30]
104
+ redhat = PuppetDB::Query[:'=', [:fact, 'osfamily'], 'RedHat']
105
+ debian = PuppetDB::Query[:'=', [:fact, 'osfamily'], 'Debian']
106
+
107
+ client.request uptime.and(debian)
108
+ client.request uptime.and(redhat)
109
+ client.request uptime.and(debian.or(redhat))
110
+ ```
111
+
112
+ If you have configured multiple PuppetDB's via [`server_urls`](https://puppet.com/docs/puppetdb/latest/pdb_client_tools.html#step-3-install-and-configure-the-puppetdb-cli)
113
+ then you can query in `:failover` mode. This will query each PuppetDB in `server_urls`
114
+ in order until it gets a successful response. It will fail with an `APIError` only if all queries fail.
115
+
116
+ ``` ruby
117
+ response = client.request(
118
+ 'nodes',
119
+ [:"=", "certname", "foo"],
120
+ {
121
+ :limit => 10
122
+ :query_mode => :failover
123
+ }
124
+ )
125
+ ```
126
+
127
+ See the [PuppetDB API Docs](https://docs.puppet.com/puppetdb/5.0/api/index.html) for more.
128
+
129
+
130
+ #### PQL Queries usage
131
+
132
+ PQL queries are supported by using the empty endpoint.
133
+
134
+ Example:
135
+ ``` ruby
136
+ response = client.request(
137
+ '',
138
+ 'resources[title] { nodes { deactivated is null } }',
139
+ {:limit => 10}
140
+ )
141
+
142
+ resources = response.data
143
+ ```
144
+
145
+ See the [PuppetDB API Docs](https://docs.puppet.com/puppetdb/5.0/api/query/v4/pql.html) for more on PQL queries.
146
+
147
+
148
+ #### Command API Usage
149
+
150
+ The Command Feature allows the user to execute REST Commands against the PuppetDB Command API Endpoints. It defaults to the latest version of the Command Endpoint.
151
+
152
+ The command method takes three arguments:
153
+
154
+ * `command`: a string identifying the command
155
+ * `payload`: a valid JSON object of any sort. It’s up to an individual handler function to determine how to interpret that object.
156
+ * `version`: a JSON integer describing what version of the given command you’re attempting to invoke. The version of the command also indicates the version of the wire format to use for the command.
157
+
158
+ Example:
159
+ ``` ruby
160
+ client.command(
161
+ 'deactivate node',
162
+ {'certname' => 'test1', 'producer_timestamp' => '2015-01-01'},
163
+ 3
164
+ )
165
+ ```
166
+
167
+ See the PuppetDB [Commands Endpoint Docs](https://docs.puppet.com/puppetdb/5.0/api/command/v1/commands.html) for more information.
168
+
169
+ #### Query the status endpoint(s)
170
+
171
+ You can get the status of all configured PuppetDB's by querying the `/status/v1/services` endpoints.
172
+ ``` ruby
173
+ client.status
174
+
175
+ # The result will be of the form (one entry per server)
176
+ # {
177
+ # "http://localhost:8080": {
178
+ # "puppetdb-status": {
179
+ # "service_version": "6.3.1-SNAPSHOT",
180
+ # "service_status_version": 1,
181
+ # "detail_level": "info",
182
+ # "state": "running",
183
+ # "status": {
184
+ # "maintenance_mode?": false,
185
+ # "queue_depth": 0,
186
+ # "read_db_up?": true,
187
+ # "write_db_up?": true
188
+ # },
189
+ # "active_alerts": [
190
+ # ]
191
+ # },
192
+ # "status-service": {
193
+ # "service_version": "1.1.0",
194
+ # "service_status_version": 1,
195
+ # "detail_level": "info",
196
+ # "state": "running",
197
+ # "status": {
198
+ # },
199
+ # "active_alerts": [
200
+ # ]
201
+ # }
202
+ # }
203
+ # }
204
+ ```
205
+
206
+ #### Export an archive of PuppetDB
207
+
208
+ You can [`export`](https://puppet.com/docs/puppetdb/5.1/anonymization.html#using-the-export-command) an archive
209
+ of your PuppetDB to a file. Optionally you can override the `anonymization_profile` (default: none).
210
+
211
+ ``` ruby
212
+ client.export('path/for/new_puppetdb_export.tar.gz', anonymization_profile: :high)
213
+ ```
214
+
215
+ #### Import an archive into PuppetDB
216
+
217
+ Once you have a PuppetDB export, it can be loaded into PuppetDB with [`import`](https://puppet.com/docs/puppetdb/5.1/anonymization.html#using-the-import-command).
218
+
219
+ ``` ruby
220
+ client.import('path/to/existing_puppetdb_export.tar.gz')
221
+ ```
222
+
223
+ ## Tests
224
+
225
+ ```
226
+ bundle install
227
+ bundle exec rspec
228
+ ```
229
+
230
+ ## Issues & Contributions
231
+
232
+ File issues or feature requests using [GitHub
233
+ issues](https://github.com/voxpupuli/puppetdb-ruby/issues).
234
+
235
+ If you are interested in contributing to this project, please see the
236
+ [Contribution Guidelines](CONTRIBUTING.md)
237
+
238
+ ## Authors
239
+
240
+ This module was donated to VoxPupuli by Puppet Inc on 10-19-2016.
241
+
242
+ Nathaniel Smith <nathaniel@puppetlabs.com>
243
+ Lindsey Smith <lindsey@puppetlabs.com>
244
+ Ruth Linehan <ruth@puppetlabs.com>
245
+
246
+ ## License
247
+
248
+ See LICENSE.
data/lib/puppetdb.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'puppetdb/version'
2
+ require 'puppetdb/client'
3
+ require 'puppetdb/query'
4
+ require 'puppetdb/response'
5
+ require 'puppetdb/error'
6
+ require 'puppetdb/config'
7
+
8
+ module PuppetDB; end
@@ -0,0 +1,197 @@
1
+ require 'httparty'
2
+ require 'logger'
3
+
4
+ require 'puppetdb/error'
5
+
6
+ module PuppetDB
7
+ class FixSSLConnectionAdapter < HTTParty::ConnectionAdapter
8
+ def attach_ssl_certificates(http, options)
9
+ http.ca_file = options[:cacert]
10
+ http.cert = OpenSSL::X509::Certificate.new(File.read(options[:cert])) if options[:cert]
11
+ http.key = OpenSSL::PKey::RSA.new(File.read(options[:key])) if options[:key]
12
+
13
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
14
+ end
15
+ end
16
+
17
+ class Client
18
+ include HTTParty
19
+ attr_reader :use_ssl
20
+ attr_writer :logger
21
+
22
+ def hash_includes?(hash, *sought_keys)
23
+ sought_keys.each { |x| return false unless hash.include?(x) }
24
+ true
25
+ end
26
+
27
+ def debug(msg)
28
+ @logger.debug(msg) if @logger
29
+ end
30
+
31
+ def initialize(settings = {}, query_api_version = 4, command_api_version = 1, admin_api_version = 1)
32
+ config = Config.new(settings, load_files: true)
33
+ @query_api_version = query_api_version
34
+ @command_api_version = command_api_version
35
+ @admin_api_version = admin_api_version
36
+
37
+ @servers = config.server_urls
38
+ pem = config.pem
39
+ token = config.token
40
+ puts config.config
41
+ puts pem
42
+ puts token.nil?
43
+ puts @servers
44
+
45
+ @servers.each do |server|
46
+ scheme = URI.parse(server).scheme
47
+ @use_ssl ||= scheme == 'https'
48
+
49
+ unless %w[http https].include? scheme
50
+ error_msg = "Configuration error: server_url '#{server}' must specify a protocol of either http or https"
51
+ raise error_msg
52
+ end
53
+ end
54
+
55
+ return unless @use_ssl
56
+ unless hash_includes?(pem, :cacert, :cert, :key) || (pem[:cert].nil? && pem[:key].nil?)
57
+ error_msg = 'Configuration error: https:// specified, but configuration is incomplete. It requires cacert and either cert and key, or a valid token.'
58
+ raise error_msg
59
+ end
60
+
61
+ self.class.default_options = pem
62
+ self.class.headers('X-Authentication' => token) if token
63
+ self.class.connection_adapter(FixSSLConnectionAdapter)
64
+ end
65
+
66
+ def raise_if_error(response)
67
+ raise UnauthorizedError, response if response.code == 401
68
+ raise ForbiddenError, response if response.code == 403
69
+ raise APIError, response if response.code.to_s =~ %r{^[4|5]}
70
+ end
71
+
72
+ def request(endpoint, query, opts = {})
73
+ path = "/pdb/query/v#{@query_api_version}"
74
+ if endpoint == ''
75
+ # PQL
76
+ json_query = query
77
+ else
78
+ path += "/#{endpoint}"
79
+ query = PuppetDB::Query.maybe_promote(query)
80
+ json_query = query.build
81
+ end
82
+
83
+ query_mode = opts.delete(:query_mode) || :first
84
+ filtered_opts = { 'query' => json_query }
85
+ opts.each do |k, v|
86
+ if k == :counts_filter
87
+ filtered_opts['counts-filter'] = JSON.dump(v)
88
+ else
89
+ filtered_opts[k.to_s.sub('_', '-')] = v
90
+ end
91
+ end
92
+
93
+ debug("#{path} #{json_query} #{opts}")
94
+
95
+ if query_mode == :first
96
+ self.class.base_uri(@servers.first)
97
+ ret = self.class.get(path, body: filtered_opts)
98
+ raise_if_error(ret)
99
+
100
+ total = ret.headers['X-Records']
101
+ total = ret.parsed_response.length if total.nil?
102
+
103
+ Response.new(ret.parsed_response, total)
104
+ elsif query_mode == :failover
105
+
106
+ ret = nil
107
+ @servers.each do |server|
108
+ self.class.base_uri(server)
109
+ ret = self.class.get(path, body: filtered_opts)
110
+ if ret.code < 400
111
+ total = ret.headers['X-Records']
112
+ total = ret.parsed_response.length if total.nil?
113
+
114
+ return Response.new(ret.parsed_response, total)
115
+ else
116
+ debug("query on '#{server}' failed with #{ret.code}")
117
+ end
118
+ end
119
+ raise APIError, ret
120
+ else
121
+ raise ArgumentError, "Query mode '#{query_mode}' is not supported (try :first or :failover)."
122
+ end
123
+ end
124
+
125
+ def command(command, payload, version)
126
+ path = "/pdb/cmd/v#{@command_api_version}"
127
+
128
+ query = {
129
+ 'command' => command,
130
+ 'version' => version,
131
+ 'certname' => payload['certname']
132
+ }
133
+
134
+ debug("#{path} #{query} #{payload}")
135
+
136
+ self.class.base_uri(@servers.first)
137
+ ret = self.class.post(
138
+ path,
139
+ query: query,
140
+ body: payload.to_json,
141
+ headers: {
142
+ 'Accept' => 'application/json',
143
+ 'Content-Type' => 'application/json'
144
+ }
145
+ )
146
+ raise_if_error(ret)
147
+
148
+ Response.new(ret.parsed_response)
149
+ end
150
+
151
+ def export(filename, opts = {})
152
+ self.class.base_uri(@servers.first)
153
+ path = "/pdb/admin/v#{@admin_api_version}/archive"
154
+
155
+ # Allow opts to override anonymization_profile, but enforce
156
+ # stream_body to avoid using memory
157
+ params = { anonymization_profile: 'none' }.
158
+ merge(opts).
159
+ merge(stream_body: true)
160
+
161
+ File.open(filename, 'w') do |file|
162
+ self.class.get(path, params) do |fragment|
163
+ if [301, 302].include?(fragment.code)
164
+ debug 'Skip streaming write for redirect'
165
+ elsif fragment.code == 200
166
+ file.write(fragment)
167
+ else
168
+ raise StandardError, "Non-success status code while streaming #{fragment.code}"
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ def import(filename)
175
+ self.class.base_uri(@servers.first)
176
+ path = "/pdb/admin/v#{@admin_api_version}/archive"
177
+ self.class.post(path, body: { archive: File.open(filename) })
178
+ end
179
+
180
+ def status
181
+ status_endpoint = '/status/v1/services'
182
+ status_map = {}
183
+
184
+ @servers.each do |server|
185
+ self.class.base_uri(server)
186
+ ret = self.class.get(status_endpoint)
187
+
188
+ status_map[server] = if ret.code >= 400
189
+ { error: "Unable to build JSON object from server: #{server}" }
190
+ else
191
+ ret.parsed_response
192
+ end
193
+ end
194
+ status_map
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,87 @@
1
+ require 'json'
2
+
3
+ class PuppetDB::Config
4
+ def initialize(overrides = nil, load_files = false)
5
+ @overrides = {}
6
+ overrides.each { |k, v| @overrides[k.to_sym] = v } unless overrides.nil?
7
+
8
+ @load_files = load_files
9
+ end
10
+
11
+ def load_file(path)
12
+ File.open(path) { |f| JSON.parse(f.read, symbolize_names: true) }
13
+ end
14
+
15
+ def puppetlabs_root
16
+ '/etc/puppetlabs'
17
+ end
18
+
19
+ def global_conf
20
+ File.join(puppetlabs_root, 'client-tools', 'puppetdb.conf')
21
+ end
22
+
23
+ def user_root
24
+ File.join(Dir.home, '.puppetlabs')
25
+ end
26
+
27
+ def user_conf
28
+ File.join(user_root, 'client-tools', 'puppetdb.conf')
29
+ end
30
+
31
+ def default_cacert
32
+ "#{puppetlabs_root}/puppet/ssl/certs/ca.pem"
33
+ end
34
+
35
+ def defaults
36
+ {
37
+ cacert: default_cacert,
38
+ token_file: File.join(user_root, 'token')
39
+ }
40
+ end
41
+
42
+ def load_config
43
+ config = defaults
44
+ if @load_files
45
+ if File.exist?(global_conf) && File.readable?(global_conf)
46
+ config = config.merge(load_file(global_conf))
47
+ end
48
+
49
+ if @overrides[:config_file]
50
+ config = config.merge(load_file(@overrides[:config_file]))
51
+ elsif File.exist?(user_conf) && File.readable?(user_conf)
52
+ config = config.merge(load_file(user_conf))
53
+ end
54
+ end
55
+
56
+ config.merge(@overrides)
57
+ end
58
+
59
+ def config
60
+ @config ||= load_config
61
+ end
62
+
63
+ def load_token
64
+ if @config.include?(:token)
65
+ @config[:token]
66
+ elsif File.readable?(config[:token_file])
67
+ File.read(config[:token_file]).strip
68
+ end
69
+ end
70
+
71
+ def token
72
+ @token ||= load_token
73
+ end
74
+
75
+ def server_urls
76
+ return config[:server_urls].split(',') if config[:server_urls].is_a?(String)
77
+ config[:server_urls] || []
78
+ end
79
+
80
+ def pem
81
+ @config.select { |k, _| [:cacert, :cert, :key].include?(k) }
82
+ end
83
+
84
+ def [](key)
85
+ @config[key]
86
+ end
87
+ end
@@ -0,0 +1,17 @@
1
+ module PuppetDB
2
+ class APIError < RuntimeError
3
+ attr_reader :code, :response
4
+ def initialize(response)
5
+ @response = response
6
+ end
7
+ end
8
+
9
+ class AccessDeniedError < APIError
10
+ end
11
+
12
+ class ForbiddenError < AccessDeniedError
13
+ end
14
+
15
+ class UnauthorizedError < AccessDeniedError
16
+ end
17
+ end
@@ -0,0 +1,58 @@
1
+ require 'json'
2
+
3
+ module PuppetDB
4
+ class Query
5
+ attr_reader :sexpr
6
+
7
+ def initialize(query = [])
8
+ @sexpr = query
9
+ end
10
+
11
+ def self.[](*args)
12
+ Query.new(args)
13
+ end
14
+
15
+ def self.maybe_promote(query)
16
+ return Query.new(query) unless query.class == Query
17
+ query
18
+ end
19
+
20
+ def empty?
21
+ @sexpr.empty?
22
+ end
23
+
24
+ def compose(query)
25
+ query = self.class.maybe_promote(query)
26
+
27
+ # If an operand is the empty query ([]), compose returns a copy
28
+ # of the non-empty operand. If both operands are empty, the
29
+ # empty query is returned. If both operands are non-empty, the
30
+ # compose continues.
31
+ if query.empty? && !empty?
32
+ Query.new(@sexpr)
33
+ elsif empty? && !query.empty?
34
+ Query.new(query.sexpr)
35
+ elsif empty? && query.empty?
36
+ Query.new([])
37
+ else
38
+ yield query
39
+ end
40
+ end
41
+
42
+ def and(query)
43
+ compose(query) { |q| Query.new([:and, @sexpr, q.sexpr]) }
44
+ end
45
+
46
+ def or(query)
47
+ compose(query) { |q| Query.new([:or, @sexpr, q.sexpr]) }
48
+ end
49
+
50
+ def push(query)
51
+ compose(query) { |q| Query.new(@sexpr.dup.push(q.sexpr)) }
52
+ end
53
+
54
+ def build
55
+ JSON.dump(@sexpr)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,10 @@
1
+ module PuppetDB
2
+ class Response
3
+ attr_reader :data, :total_records
4
+
5
+ def initialize(data, total_records = nil)
6
+ @data = data
7
+ @total_records = total_records
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module PuppetDB
2
+ VERSION = '2.0.0'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pl-puppetdb-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Austin Blatt
8
+ - Vox Pupuli
9
+ - Nathaniel Smith
10
+ - Lindsey Smith
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2019-04-29 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: httparty
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ - !ruby/object:Gem::Dependency
45
+ name: rspec
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ - !ruby/object:Gem::Dependency
59
+ name: mocha
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ - !ruby/object:Gem::Dependency
73
+ name: rubocop
74
+ requirement: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - '='
77
+ - !ruby/object:Gem::Version
78
+ version: 0.48.1
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - '='
84
+ - !ruby/object:Gem::Version
85
+ version: 0.48.1
86
+ - !ruby/object:Gem::Dependency
87
+ name: rubocop-rspec
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - '='
91
+ - !ruby/object:Gem::Version
92
+ version: 1.15.1
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '='
98
+ - !ruby/object:Gem::Version
99
+ version: 1.15.1
100
+ - !ruby/object:Gem::Dependency
101
+ name: github_changelog_generator
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ description:
115
+ email: austin.blatt@puppet.com
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - CHANGELOG.md
121
+ - LICENSE
122
+ - README.md
123
+ - lib/puppetdb.rb
124
+ - lib/puppetdb/client.rb
125
+ - lib/puppetdb/config.rb
126
+ - lib/puppetdb/error.rb
127
+ - lib/puppetdb/query.rb
128
+ - lib/puppetdb/response.rb
129
+ - lib/puppetdb/version.rb
130
+ homepage: https://github.com/austb/puppetdb-ruby
131
+ licenses:
132
+ - apache
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.6.14.1
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Simple Ruby client library for PuppetDB API
154
+ test_files: []