md-puppetdb-terminus 2.0.0.3
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 +7 -0
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +202 -0
- data/README.md +29 -0
- data/Rakefile +16 -0
- data/lib/md-puppetdb-terminus.rb +1 -0
- data/lib/puppet/application/storeconfigs.rb +4 -0
- data/lib/puppet/face/node/deactivate.rb +38 -0
- data/lib/puppet/face/node/status.rb +83 -0
- data/lib/puppet/face/storeconfigs.rb +179 -0
- data/lib/puppet/indirector/catalog/puppetdb.rb +350 -0
- data/lib/puppet/indirector/facts/puppetdb.rb +134 -0
- data/lib/puppet/indirector/facts/puppetdb_apply.rb +25 -0
- data/lib/puppet/indirector/node/puppetdb.rb +22 -0
- data/lib/puppet/indirector/resource/puppetdb.rb +107 -0
- data/lib/puppet/reports/puppetdb.rb +186 -0
- data/lib/puppet/util/puppetdb.rb +108 -0
- data/lib/puppet/util/puppetdb/blacklist.rb +35 -0
- data/lib/puppet/util/puppetdb/char_encoding.rb +212 -0
- data/lib/puppet/util/puppetdb/command.rb +113 -0
- data/lib/puppet/util/puppetdb/command_names.rb +8 -0
- data/lib/puppet/util/puppetdb/config.rb +112 -0
- data/lib/puppet/util/puppetdb/global_check.rb +31 -0
- data/lib/puppetdb-terminus.rb +1 -0
- data/lib/puppetdb/terminus.rb +6 -0
- data/lib/puppetdb/terminus/version.rb +5 -0
- data/puppetdb-terminus.gemspec +23 -0
- metadata +99 -0
@@ -0,0 +1,350 @@
|
|
1
|
+
require 'puppet/resource/catalog'
|
2
|
+
require 'puppet/indirector/rest'
|
3
|
+
require 'puppet/util/puppetdb'
|
4
|
+
|
5
|
+
class Puppet::Resource::Catalog::Puppetdb < Puppet::Indirector::REST
|
6
|
+
include Puppet::Util::Puppetdb
|
7
|
+
include Puppet::Util::Puppetdb::CommandNames
|
8
|
+
|
9
|
+
# Run initial checks
|
10
|
+
def initialize
|
11
|
+
Puppet::Util::Puppetdb::GlobalCheck.run
|
12
|
+
end
|
13
|
+
|
14
|
+
def save(request)
|
15
|
+
profile "catalog#save" do
|
16
|
+
catalog = munge_catalog(request.instance, extract_extra_request_data(request))
|
17
|
+
|
18
|
+
submit_command(request.key, catalog, CommandReplaceCatalog, 4)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def find(request)
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def extract_extra_request_data(request)
|
28
|
+
{
|
29
|
+
:transaction_uuid => request.options[:transaction_uuid],
|
30
|
+
:environment => request.environment,
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def munge_catalog(catalog, extra_request_data = {})
|
35
|
+
profile "Munge catalog" do
|
36
|
+
hash = profile "Convert catalog to PSON data hash" do
|
37
|
+
catalog.to_pson_data_hash
|
38
|
+
end
|
39
|
+
|
40
|
+
data = hash['data']
|
41
|
+
|
42
|
+
add_parameters_if_missing(data)
|
43
|
+
add_namevar_aliases(data, catalog)
|
44
|
+
stringify_titles(data)
|
45
|
+
stringify_version(data)
|
46
|
+
sort_unordered_metaparams(data)
|
47
|
+
munge_edges(data)
|
48
|
+
synthesize_edges(data, catalog)
|
49
|
+
filter_keys(data)
|
50
|
+
add_transaction_uuid(data, extra_request_data[:transaction_uuid])
|
51
|
+
add_environment(data, extra_request_data[:environment])
|
52
|
+
|
53
|
+
data
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Relationships = {
|
58
|
+
:before => {:direction => :forward, :relationship => 'before'},
|
59
|
+
:require => {:direction => :reverse, :relationship => 'required-by'},
|
60
|
+
:notify => {:direction => :forward, :relationship => 'notifies'},
|
61
|
+
:subscribe => {:direction => :reverse, :relationship => 'subscription-of'},
|
62
|
+
}
|
63
|
+
|
64
|
+
# Metaparams that may contain arrays, but whose semantics are
|
65
|
+
# fundamentally unordered
|
66
|
+
UnorderedMetaparams = [:alias, :audit, :before, :check, :notify, :require, :subscribe, :tag]
|
67
|
+
|
68
|
+
# Include environment in hash, returning the complete hash.
|
69
|
+
#
|
70
|
+
# @param hash [Hash] original data hash
|
71
|
+
# @param environment [String] environment
|
72
|
+
# @return [Hash] returns original hash augmented with environment
|
73
|
+
# @api private
|
74
|
+
def add_environment(hash, environment)
|
75
|
+
hash['environment'] = environment
|
76
|
+
|
77
|
+
hash
|
78
|
+
end
|
79
|
+
|
80
|
+
# Include transaction_uuid in hash, returning the complete hash.
|
81
|
+
#
|
82
|
+
# @param hash [Hash] original data hash
|
83
|
+
# @param transaction_uuid [String] transaction_uuid
|
84
|
+
# @return [Hash] returns original hash augmented with transaction_uuid
|
85
|
+
# @api private
|
86
|
+
def add_transaction_uuid(hash, transaction_uuid)
|
87
|
+
hash['transaction-uuid'] = transaction_uuid
|
88
|
+
|
89
|
+
hash
|
90
|
+
end
|
91
|
+
|
92
|
+
# Version is an integer (time since epoch in millis). The wire
|
93
|
+
# format specifies version should be a string
|
94
|
+
#
|
95
|
+
# @param hash [Hash] original data hash
|
96
|
+
# @return [Hash] returns a modified original hash
|
97
|
+
def stringify_version(hash)
|
98
|
+
hash['version'] = hash['version'].to_s
|
99
|
+
|
100
|
+
hash
|
101
|
+
end
|
102
|
+
|
103
|
+
def stringify_titles(hash)
|
104
|
+
resources = hash['resources']
|
105
|
+
profile "Stringify titles (resource count: #{resources.count})" do
|
106
|
+
resources.each do |resource|
|
107
|
+
resource['title'] = resource['title'].to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
hash
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_parameters_if_missing(hash)
|
115
|
+
resources = hash['resources']
|
116
|
+
profile "Add parameters if missing (resource count: #{resources.count})" do
|
117
|
+
resources.each do |resource|
|
118
|
+
resource['parameters'] ||= {}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
hash
|
123
|
+
end
|
124
|
+
|
125
|
+
def add_namevar_aliases(hash, catalog)
|
126
|
+
resources = hash['resources']
|
127
|
+
profile "Add namevar aliases (resource count: #{resources.count})" do
|
128
|
+
resources.each do |resource|
|
129
|
+
real_resource = catalog.resource(resource['type'], resource['title'])
|
130
|
+
|
131
|
+
# Resources with composite namevars can't be referred to by
|
132
|
+
# anything other than their title when declaring
|
133
|
+
# relationships. Trying to snag the :alias for these resources
|
134
|
+
# will only return _part_ of the name (a problem with Puppet
|
135
|
+
# proper), so skipping the adding of aliases for these resources
|
136
|
+
# is both an optimization and a safeguard.
|
137
|
+
next if real_resource.key_attributes.count > 1
|
138
|
+
|
139
|
+
aliases = [real_resource[:alias]].flatten.compact
|
140
|
+
|
141
|
+
# Non-isomorphic resources aren't unique based on namevar, so we can't
|
142
|
+
# use it as an alias
|
143
|
+
type = real_resource.resource_type
|
144
|
+
if !type.respond_to?(:isomorphic?) or type.isomorphic?
|
145
|
+
# This makes me a little sad. It turns out that the "to_hash" method
|
146
|
+
# of Puppet::Resource can have side effects. In particular, if the
|
147
|
+
# resource type specifies a title_pattern, calling "to_hash" will trigger
|
148
|
+
# the title_pattern processing, which can have the side effect of
|
149
|
+
# populating the namevar (potentially with a munged value). Thus,
|
150
|
+
# it is important that we search for namevar aliases in that hash
|
151
|
+
# rather than in the resource itself.
|
152
|
+
real_resource_hash = real_resource.to_hash
|
153
|
+
|
154
|
+
name = real_resource_hash[real_resource.send(:namevar)]
|
155
|
+
unless name.nil? or real_resource.title == name or aliases.include?(name)
|
156
|
+
aliases << name
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
resource['parameters']['alias'] = aliases unless aliases.empty?
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
hash
|
165
|
+
end
|
166
|
+
|
167
|
+
def sort_unordered_metaparams(hash)
|
168
|
+
resources = hash['resources']
|
169
|
+
profile "Sort unordered metaparams (resource count: #{resources.count})" do
|
170
|
+
resources.each do |resource|
|
171
|
+
params = resource['parameters']
|
172
|
+
UnorderedMetaparams.each do |metaparam|
|
173
|
+
if params[metaparam].kind_of? Array then
|
174
|
+
values = params[metaparam].sort
|
175
|
+
params[metaparam] = values unless values.empty?
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
hash
|
182
|
+
end
|
183
|
+
|
184
|
+
def munge_edges(hash)
|
185
|
+
edges = hash['edges']
|
186
|
+
profile "Munge edges (edge count: #{edges.count})" do
|
187
|
+
edges.each do |edge|
|
188
|
+
%w[source target].each do |vertex|
|
189
|
+
edge[vertex] = resource_ref_to_hash(edge[vertex]) if edge[vertex].is_a?(String)
|
190
|
+
end
|
191
|
+
edge['relationship'] ||= 'contains'
|
192
|
+
end
|
193
|
+
|
194
|
+
hash
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def map_aliases_to_title(hash)
|
199
|
+
resources = hash['resources']
|
200
|
+
aliases = {}
|
201
|
+
|
202
|
+
profile "Map aliases to title (resource count: #{resources.count})" do
|
203
|
+
resources.each do |resource|
|
204
|
+
names = resource['parameters']['alias'] || []
|
205
|
+
resource_hash = {'type' => resource['type'], 'title' => resource['title']}
|
206
|
+
names.each do |name|
|
207
|
+
alias_array = [resource['type'], name]
|
208
|
+
aliases[alias_array] = resource_hash
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
aliases
|
214
|
+
end
|
215
|
+
|
216
|
+
def synthesize_edges(hash, catalog)
|
217
|
+
profile "Synthesize edges" do
|
218
|
+
aliases = map_aliases_to_title(hash)
|
219
|
+
|
220
|
+
resource_table = {}
|
221
|
+
profile "Build up resource_table" do
|
222
|
+
hash['resources'].each do |resource|
|
223
|
+
resource_table[ [resource['type'], resource['title']] ] = resource
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
profile "Primary synthesis" do
|
228
|
+
hash['resources'].each do |resource|
|
229
|
+
# Standard virtual resources don't appear in the catalog. However,
|
230
|
+
# exported resources which haven't been also collected will appears as
|
231
|
+
# exported and virtual (collected ones will only be exported). They will
|
232
|
+
# eventually be removed from the catalog, so we can't add edges involving
|
233
|
+
# them. Puppet::Resource#to_pson_data_hash omits 'virtual', so we have to
|
234
|
+
# look it up in the catalog to find that information. This isn't done in
|
235
|
+
# a separate step because we don't actually want to send the field (it
|
236
|
+
# will always be false). See ticket #16472.
|
237
|
+
#
|
238
|
+
# The outer conditional is here because Class[main] can't properly be
|
239
|
+
# looked up using catalog.resource and will return nil. See ticket
|
240
|
+
# #16473. Yay.
|
241
|
+
if real_resource = catalog.resource(resource['type'], resource['title'])
|
242
|
+
next if real_resource.virtual?
|
243
|
+
end
|
244
|
+
|
245
|
+
Relationships.each do |param,relation|
|
246
|
+
if value = resource['parameters'][param]
|
247
|
+
[value].flatten.each do |other_ref|
|
248
|
+
edge = {'relationship' => relation[:relationship]}
|
249
|
+
|
250
|
+
resource_hash = {'type' => resource['type'], 'title' => resource['title']}
|
251
|
+
other_hash = resource_ref_to_hash(other_ref)
|
252
|
+
|
253
|
+
# Puppet doesn't always seem to check this correctly. If we don't
|
254
|
+
# users will later get an invalid relationship error instead.
|
255
|
+
#
|
256
|
+
# Primarily we are trying to catch the non-capitalized resourceref
|
257
|
+
# case problem here: http://projects.puppetlabs.com/issues/19474
|
258
|
+
# Once that problem is solved and older versions of Puppet that have
|
259
|
+
# the bug are no longer supported we can probably remove this code.
|
260
|
+
unless other_ref =~ /^[A-Z][a-z0-9_]*(::[A-Z][a-z0-9_]*)*\[.*\]/
|
261
|
+
rel = edge_to_s(resource_hash_to_ref(resource_hash), other_ref, param)
|
262
|
+
raise Puppet::Error, "Invalid relationship: #{rel}, because " +
|
263
|
+
"#{other_ref} doesn't seem to be in the correct format. " +
|
264
|
+
"Resource references should be formatted as: " +
|
265
|
+
"Classname['title'] or Modulename::Classname['title'] (take " +
|
266
|
+
"careful note of the capitalization)."
|
267
|
+
end
|
268
|
+
|
269
|
+
# This is an unfortunate hack. Puppet does some weird things w/rt
|
270
|
+
# munging off trailing slashes from file resources, and users may
|
271
|
+
# legally specify relationships using a different number of trailing
|
272
|
+
# slashes than the resource was originally declared with.
|
273
|
+
# We do know that for any file resource in the catalog, there should
|
274
|
+
# be a canonical entry for it that contains no trailing slashes. So,
|
275
|
+
# here, in case someone has specified a relationship to a file resource
|
276
|
+
# and has used one or more trailing slashes when specifying the
|
277
|
+
# relationship, we will munge off the trailing slashes before
|
278
|
+
# we look up the resource in the catalog to create the edge.
|
279
|
+
if other_hash['type'] == 'File' and other_hash['title'] =~ /\/$/
|
280
|
+
other_hash['title'] = other_hash['title'].sub(/\/+$/, '')
|
281
|
+
end
|
282
|
+
|
283
|
+
other_array = [other_hash['type'], other_hash['title']]
|
284
|
+
|
285
|
+
# Try to find the resource by type/title or look it up as an alias
|
286
|
+
# and try that
|
287
|
+
other_resource = resource_table[other_array]
|
288
|
+
if other_resource.nil? and alias_hash = aliases[other_array]
|
289
|
+
other_resource = resource_table[ alias_hash.values_at('type', 'title') ]
|
290
|
+
end
|
291
|
+
|
292
|
+
raise Puppet::Error, "Invalid relationship: #{edge_to_s(resource_hash_to_ref(resource_hash), other_ref, param)}, because #{other_ref} doesn't seem to be in the catalog" unless other_resource
|
293
|
+
|
294
|
+
# As above, virtual exported resources will eventually be removed,
|
295
|
+
# so if a real resource refers to one, it's wrong. Non-virtual
|
296
|
+
# exported resources are exported resources that were also
|
297
|
+
# collected in this catalog, so they're okay. Virtual non-exported
|
298
|
+
# resources can't appear in the catalog in the first place, so it
|
299
|
+
# suffices to check for virtual.
|
300
|
+
if other_real_resource = catalog.resource(other_resource['type'], other_resource['title'])
|
301
|
+
if other_real_resource.virtual?
|
302
|
+
raise Puppet::Error, "Invalid relationship: #{edge_to_s(resource_hash_to_ref(resource_hash), other_ref, param)}, because #{other_ref} is exported but not collected"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
# If the ref was an alias, it will have a different title, so use
|
307
|
+
# that
|
308
|
+
other_hash['title'] = other_resource['title']
|
309
|
+
|
310
|
+
if relation[:direction] == :forward
|
311
|
+
edge.merge!('source' => resource_hash, 'target' => other_hash)
|
312
|
+
else
|
313
|
+
edge.merge!('source' => other_hash, 'target' => resource_hash)
|
314
|
+
end
|
315
|
+
hash['edges'] << edge
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
profile "Make edges unique" do
|
323
|
+
hash['edges'].uniq!
|
324
|
+
end
|
325
|
+
|
326
|
+
hash
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def filter_keys(hash)
|
331
|
+
profile "Filter extraneous keys from the catalog" do
|
332
|
+
hash.delete_if do |k,v|
|
333
|
+
! ['name', 'version', 'edges', 'resources'].include?(k)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def resource_ref_to_hash(ref)
|
339
|
+
ref =~ /^([^\[\]]+)\[(.+)\]$/m
|
340
|
+
{'type' => $1, 'title' => $2}
|
341
|
+
end
|
342
|
+
|
343
|
+
def resource_hash_to_ref(hash)
|
344
|
+
"#{hash['type']}[#{hash['title']}]"
|
345
|
+
end
|
346
|
+
|
347
|
+
def edge_to_s(specifier_resource, referred_resource, param)
|
348
|
+
"#{specifier_resource} { #{param} => #{referred_resource} }"
|
349
|
+
end
|
350
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'puppet/node/facts'
|
3
|
+
require 'puppet/indirector/rest'
|
4
|
+
require 'puppet/util/puppetdb'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
class Puppet::Node::Facts::Puppetdb < Puppet::Indirector::REST
|
8
|
+
include Puppet::Util::Puppetdb
|
9
|
+
include Puppet::Util::Puppetdb::CommandNames
|
10
|
+
|
11
|
+
# Run initial checks
|
12
|
+
def initialize
|
13
|
+
Puppet::Util::Puppetdb::GlobalCheck.run
|
14
|
+
end
|
15
|
+
|
16
|
+
def save(request)
|
17
|
+
profile "facts#save" do
|
18
|
+
payload = profile "Encode facts command submission payload" do
|
19
|
+
facts = request.instance.dup
|
20
|
+
facts.values = facts.values.dup
|
21
|
+
facts.stringify
|
22
|
+
{
|
23
|
+
"name" => facts.name,
|
24
|
+
"values" => facts.values,
|
25
|
+
# PDB-453: we call to_s to avoid a 'stack level too deep' error
|
26
|
+
# when we attempt to use ActiveSupport 2.3.16 on RHEL 5 with
|
27
|
+
# legacy storeconfigs.
|
28
|
+
"environment" => request.environment.to_s,
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
submit_command(request.key, payload, CommandReplaceFacts, 2)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def find(request)
|
37
|
+
profile "facts#find" do
|
38
|
+
begin
|
39
|
+
url = "/v3/nodes/#{CGI.escape(request.key)}/facts"
|
40
|
+
response = profile "Query for nodes facts: #{url}" do
|
41
|
+
http_get(request, url, headers)
|
42
|
+
end
|
43
|
+
log_x_deprecation_header(response)
|
44
|
+
|
45
|
+
if response.is_a? Net::HTTPSuccess
|
46
|
+
profile "Parse fact query response (size: #{response.body.size})" do
|
47
|
+
result = JSON.parse(response.body)
|
48
|
+
# Note: the Inventory Service API appears to expect us to return nil here
|
49
|
+
# if the node isn't found. However, PuppetDB returns an empty array in
|
50
|
+
# this case; for now we will just look for that condition and assume that
|
51
|
+
# it means that the node wasn't found, so we will return nil. In the
|
52
|
+
# future we may want to improve the logic such that we can distinguish
|
53
|
+
# between the "node not found" and the "no facts for this node" cases.
|
54
|
+
if result.empty?
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
facts = result.inject({}) do |a,h|
|
58
|
+
a.merge(h['name'] => h['value'])
|
59
|
+
end
|
60
|
+
Puppet::Node::Facts.new(request.key, facts)
|
61
|
+
end
|
62
|
+
else
|
63
|
+
# Newline characters cause an HTTP error, so strip them
|
64
|
+
raise "[#{response.code} #{response.message}] #{response.body.gsub(/[\r\n]/, '')}"
|
65
|
+
end
|
66
|
+
rescue => e
|
67
|
+
raise Puppet::Error, "Failed to find facts from PuppetDB at #{self.class.server}:#{self.class.port}: #{e}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Search for nodes matching a set of fact constraints. The constraints are
|
73
|
+
# specified as a hash of the form:
|
74
|
+
#
|
75
|
+
# `{type.name.operator => value`
|
76
|
+
#
|
77
|
+
# The only accepted `type` is 'facts'.
|
78
|
+
#
|
79
|
+
# `name` must be the fact name to query against.
|
80
|
+
#
|
81
|
+
# `operator` may be one of {eq, ne, lt, gt, le, ge}, and will default to 'eq'
|
82
|
+
# if unspecified.
|
83
|
+
def search(request)
|
84
|
+
profile "facts#search" do
|
85
|
+
return [] unless request.options
|
86
|
+
operator_map = {
|
87
|
+
'eq' => '=',
|
88
|
+
'gt' => '>',
|
89
|
+
'lt' => '<',
|
90
|
+
'ge' => '>=',
|
91
|
+
'le' => '<=',
|
92
|
+
}
|
93
|
+
filters = request.options.sort.map do |key,value|
|
94
|
+
type, name, operator = key.to_s.split('.')
|
95
|
+
operator ||= 'eq'
|
96
|
+
raise Puppet::Error, "Fact search against keys of type '#{type}' is unsupported" unless type == 'facts'
|
97
|
+
if operator == 'ne'
|
98
|
+
['not', ['=', ['fact', name], value]]
|
99
|
+
else
|
100
|
+
[operator_map[operator], ['fact', name], value]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
query = ["and"] + filters
|
105
|
+
query_param = CGI.escape(query.to_json)
|
106
|
+
|
107
|
+
begin
|
108
|
+
url = "/v3/nodes?query=#{query_param}"
|
109
|
+
response = profile "Fact query request: #{URI.unescape(url)}" do
|
110
|
+
http_get(request, url, headers)
|
111
|
+
end
|
112
|
+
log_x_deprecation_header(response)
|
113
|
+
|
114
|
+
if response.is_a? Net::HTTPSuccess
|
115
|
+
profile "Parse fact query response (size: #{response.body.size})" do
|
116
|
+
JSON.parse(response.body).collect {|s| s["name"]}
|
117
|
+
end
|
118
|
+
else
|
119
|
+
# Newline characters cause an HTTP error, so strip them
|
120
|
+
raise "[#{response.code} #{response.message}] #{response.body.gsub(/[\r\n]/, '')}"
|
121
|
+
end
|
122
|
+
rescue => e
|
123
|
+
raise Puppet::Error, "Could not perform inventory search from PuppetDB at #{self.class.server}:#{self.class.port}: #{e}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def headers
|
129
|
+
{
|
130
|
+
"Accept" => "application/json",
|
131
|
+
"Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8",
|
132
|
+
}
|
133
|
+
end
|
134
|
+
end
|