quixoten-puppetdb-terminus 2.3.8 → 3.0.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 +4 -4
- data/lib/puppet/face/node/status.rb +5 -6
- data/lib/puppet/face/storeconfigs.rb +16 -15
- data/lib/puppet/indirector/catalog/puppetdb.rb +23 -5
- data/lib/puppet/indirector/facts/puppetdb.rb +27 -21
- data/lib/puppet/indirector/node/puppetdb.rb +3 -1
- data/lib/puppet/indirector/resource/puppetdb.rb +6 -4
- data/lib/puppet/reports/puppetdb.rb +59 -18
- data/lib/puppet/util/puppetdb.rb +9 -28
- data/lib/puppet/util/puppetdb/blacklist.rb +2 -2
- data/lib/puppet/util/puppetdb/char_encoding.rb +1 -1
- data/lib/puppet/util/puppetdb/command.rb +27 -25
- data/lib/puppet/util/puppetdb/config.rb +125 -94
- data/lib/puppet/util/puppetdb/http.rb +121 -0
- data/lib/puppetdb/terminus/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd5513b1969cbbc8de118e435e8882b9d3b6f9c1
|
4
|
+
data.tar.gz: 016c79651a57659cbbc308dd0d4df9fd309f63eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38044e3513401f5b9a6361329d3e0856a2dea01e34bfb9965284befeed31f37dd32200ad7d7a82a0530c9d376fbc1139524dd8a8509913a266d9749cffcd3fce
|
7
|
+
data.tar.gz: 0b9505971f2583012847afd93d92f766b2221e3218d7724192d18a937d1bc2a36ad33f39cbc071f7f5a8760d81f6b5dfa539c385e9de94c9753ab47a04b875e7
|
@@ -17,14 +17,11 @@ Puppet::Face.define(:node, '0.0.1') do
|
|
17
17
|
opts = args.pop
|
18
18
|
raise ArgumentError, "Please provide at least one node" if args.empty?
|
19
19
|
|
20
|
-
server = Puppet::Util::Puppetdb.server
|
21
|
-
port = Puppet::Util::Puppetdb.port
|
22
|
-
|
23
|
-
http = Puppet::Network::HttpPool.http_instance(server, port)
|
24
|
-
|
25
20
|
args.map do |node|
|
26
21
|
begin
|
27
|
-
response =
|
22
|
+
response = Puppet::Util::Puppetdb::Http.action("/pdb/query/v4/nodes/#{CGI.escape(node)}") do |http_instance, path|
|
23
|
+
http_instance.get(path, headers)
|
24
|
+
end
|
28
25
|
if response.is_a? Net::HTTPSuccess
|
29
26
|
result = JSON.parse(response.body)
|
30
27
|
elsif response.is_a? Net::HTTPNotFound
|
@@ -51,6 +48,8 @@ Puppet::Face.define(:node, '0.0.1') do
|
|
51
48
|
|
52
49
|
if status['deactivated']
|
53
50
|
lines << "Deactivated at #{status['deactivated']}"
|
51
|
+
elsif status['expired']
|
52
|
+
lines << "Expired at #{status['expired']}"
|
54
53
|
else
|
55
54
|
lines << "Currently active"
|
56
55
|
end
|
@@ -35,36 +35,36 @@ if Puppet::Util::Puppetdb.puppet3compat?
|
|
35
35
|
begin
|
36
36
|
Puppet::Rails.connect
|
37
37
|
|
38
|
+
timestamp = Time.now
|
39
|
+
|
38
40
|
# Fetch all nodes, including exported resources and their params
|
39
41
|
nodes = Puppet::Rails::Host.all(:include => {:resources => [:param_values, :puppet_tags]},
|
40
42
|
:conditions => {:resources => {:exported => true}})
|
41
43
|
|
42
|
-
catalogs = nodes.map { |node| node_to_catalog_hash(node) }
|
44
|
+
catalogs = nodes.map { |node| node_to_catalog_hash(node, timestamp.iso8601(5)) }
|
43
45
|
|
44
46
|
catalog_dir = File.join(workdir, 'catalogs')
|
45
47
|
FileUtils.mkdir(catalog_dir)
|
46
48
|
|
47
49
|
catalogs.each do |catalog|
|
48
|
-
filename = File.join(catalog_dir, "#{catalog[:
|
50
|
+
filename = File.join(catalog_dir, "#{catalog[:certname]}.json")
|
49
51
|
|
50
52
|
File.open(filename, 'w') do |file|
|
51
|
-
file.puts catalog.
|
53
|
+
file.puts catalog.to_json
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
57
|
node_names = nodes.map(&:name).sort
|
56
58
|
|
57
|
-
timestamp = Time.now
|
58
|
-
|
59
59
|
File.open(File.join(workdir, 'export-metadata.json'), 'w') do |file|
|
60
60
|
metadata = {
|
61
61
|
'timestamp' => timestamp,
|
62
|
-
'
|
63
|
-
'
|
62
|
+
'command_versions' => {
|
63
|
+
'replace_catalog' => 6,
|
64
64
|
}
|
65
65
|
}
|
66
66
|
|
67
|
-
file.puts metadata.
|
67
|
+
file.puts metadata.to_json
|
68
68
|
end
|
69
69
|
|
70
70
|
tarfile = destination_file(timestamp)
|
@@ -116,20 +116,21 @@ if Puppet::Util::Puppetdb.puppet3compat?
|
|
116
116
|
Puppet::Util::Execution.execute(command)
|
117
117
|
end
|
118
118
|
|
119
|
-
def node_to_catalog_hash(node)
|
119
|
+
def node_to_catalog_hash(node, timestamp)
|
120
120
|
resources = node.resources.map { |resource| resource_to_hash(resource) }
|
121
121
|
edges = node.resources.map { |resource| resource_to_edge_hash(resource) }
|
122
122
|
|
123
123
|
{
|
124
|
+
:environment => "production",
|
124
125
|
:metadata => {
|
125
126
|
:api_version => 1,
|
126
127
|
},
|
127
|
-
:
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
128
|
+
:certname => node.name,
|
129
|
+
:version => node.last_compile || Time.now,
|
130
|
+
:edges => edges,
|
131
|
+
:resources => resources + [stage_main_hash],
|
132
|
+
:timestamp => timestamp,
|
133
|
+
:producer_timestamp => timestamp,
|
133
134
|
}
|
134
135
|
end
|
135
136
|
|
@@ -10,7 +10,7 @@ class Puppet::Resource::Catalog::Puppetdb < Puppet::Indirector::REST
|
|
10
10
|
def save(request)
|
11
11
|
profile("catalog#save", [:puppetdb, :catalog, :save, request.key]) do
|
12
12
|
catalog = munge_catalog(request.instance, extract_extra_request_data(request))
|
13
|
-
submit_command(request.key, catalog, CommandReplaceCatalog,
|
13
|
+
submit_command(request.key, catalog, CommandReplaceCatalog, 6)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -22,11 +22,16 @@ class Puppet::Resource::Catalog::Puppetdb < Puppet::Indirector::REST
|
|
22
22
|
def extract_extra_request_data(request)
|
23
23
|
{
|
24
24
|
:transaction_uuid => request.options[:transaction_uuid],
|
25
|
-
:environment => request.environment,
|
26
|
-
:producer_timestamp => request.options[:producer_timestamp] || Time.now.iso8601,
|
25
|
+
:environment => request.environment.to_s,
|
26
|
+
:producer_timestamp => request.options[:producer_timestamp] || Time.now.iso8601(5),
|
27
27
|
}
|
28
28
|
end
|
29
29
|
|
30
|
+
def hashify_tags(hash)
|
31
|
+
hash["resources"] = hash["resources"].map { |resource| resource["tags"] = resource["tags"].to_data_hash; resource }
|
32
|
+
hash
|
33
|
+
end
|
34
|
+
|
30
35
|
def munge_catalog(catalog, extra_request_data = {})
|
31
36
|
profile("Munge catalog", [:puppetdb, :catalog, :munge]) do
|
32
37
|
data = profile("Convert catalog to JSON data hash", [:puppetdb, :catalog, :convert_to_hash]) do
|
@@ -37,6 +42,7 @@ class Puppet::Resource::Catalog::Puppetdb < Puppet::Indirector::REST
|
|
37
42
|
add_namevar_aliases(data, catalog)
|
38
43
|
stringify_titles(data)
|
39
44
|
stringify_version(data)
|
45
|
+
hashify_tags(data)
|
40
46
|
sort_unordered_metaparams(data)
|
41
47
|
munge_edges(data)
|
42
48
|
synthesize_edges(data, catalog)
|
@@ -44,6 +50,7 @@ class Puppet::Resource::Catalog::Puppetdb < Puppet::Indirector::REST
|
|
44
50
|
add_transaction_uuid(data, extra_request_data[:transaction_uuid])
|
45
51
|
add_environment(data, extra_request_data[:environment])
|
46
52
|
add_producer_timestamp(data, extra_request_data[:producer_timestamp])
|
53
|
+
change_name_to_certname(data)
|
47
54
|
|
48
55
|
data
|
49
56
|
end
|
@@ -60,6 +67,17 @@ class Puppet::Resource::Catalog::Puppetdb < Puppet::Indirector::REST
|
|
60
67
|
# fundamentally unordered
|
61
68
|
UnorderedMetaparams = [:alias, :audit, :before, :check, :notify, :require, :subscribe, :tag]
|
62
69
|
|
70
|
+
# Change the name field to certname
|
71
|
+
#
|
72
|
+
# @param hash [Hash] original data hash
|
73
|
+
# @return [Hash] returns original hash with 'name' changed to 'certname'
|
74
|
+
# @api private
|
75
|
+
def change_name_to_certname(hash)
|
76
|
+
hash['certname'] = hash.delete('name')
|
77
|
+
|
78
|
+
hash
|
79
|
+
end
|
80
|
+
|
63
81
|
# Include environment in hash, returning the complete hash.
|
64
82
|
#
|
65
83
|
# @param hash [Hash] original data hash
|
@@ -79,7 +97,7 @@ class Puppet::Resource::Catalog::Puppetdb < Puppet::Indirector::REST
|
|
79
97
|
# @return [Hash] returns original hash augmented with producer_timestamp
|
80
98
|
# @api private
|
81
99
|
def add_producer_timestamp(hash, producer_timestamp)
|
82
|
-
hash['
|
100
|
+
hash['producer_timestamp'] = producer_timestamp
|
83
101
|
|
84
102
|
hash
|
85
103
|
end
|
@@ -91,7 +109,7 @@ class Puppet::Resource::Catalog::Puppetdb < Puppet::Indirector::REST
|
|
91
109
|
# @return [Hash] returns original hash augmented with transaction_uuid
|
92
110
|
# @api private
|
93
111
|
def add_transaction_uuid(hash, transaction_uuid)
|
94
|
-
hash['
|
112
|
+
hash['transaction_uuid'] = transaction_uuid
|
95
113
|
|
96
114
|
hash
|
97
115
|
end
|
@@ -16,6 +16,14 @@ class Puppet::Node::Facts::Puppetdb < Puppet::Indirector::REST
|
|
16
16
|
trusted.to_h
|
17
17
|
end
|
18
18
|
|
19
|
+
def maybe_strip_internal(facts)
|
20
|
+
if Puppet::Node::Facts.method_defined? :strip_internal
|
21
|
+
facts.strip_internal
|
22
|
+
else
|
23
|
+
facts.values
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
19
27
|
def save(request)
|
20
28
|
profile("facts#save", [:puppetdb, :facts, :save, request.key]) do
|
21
29
|
payload = profile("Encode facts command submission payload",
|
@@ -27,27 +35,28 @@ class Puppet::Node::Facts::Puppetdb < Puppet::Indirector::REST
|
|
27
35
|
facts.values[:trusted] = get_trusted_info(request.node)
|
28
36
|
end
|
29
37
|
{
|
30
|
-
"
|
38
|
+
"certname" => facts.name,
|
31
39
|
"values" => facts.values,
|
32
40
|
# PDB-453: we call to_s to avoid a 'stack level too deep' error
|
33
41
|
# when we attempt to use ActiveSupport 2.3.16 on RHEL 5 with
|
34
42
|
# legacy storeconfigs.
|
35
43
|
"environment" => request.options[:environment] || request.environment.to_s,
|
36
|
-
"
|
44
|
+
"producer_timestamp" => request.options[:producer_timestamp] || Time.now.iso8601(5),
|
37
45
|
}
|
38
46
|
end
|
39
47
|
|
40
|
-
submit_command(request.key, payload, CommandReplaceFacts,
|
48
|
+
submit_command(request.key, payload, CommandReplaceFacts, 4)
|
41
49
|
end
|
42
50
|
end
|
43
51
|
|
44
52
|
def find(request)
|
45
53
|
profile("facts#find", [:puppetdb, :facts, :find, request.key]) do
|
46
54
|
begin
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
55
|
+
response = Http.action("/pdb/query/v4/nodes/#{CGI.escape(request.key)}/facts") do |http_instance, path|
|
56
|
+
profile("Query for nodes facts: #{URI.unescape(path)}",
|
57
|
+
[:puppetdb, :facts, :find, :query_nodes, request.key]) do
|
58
|
+
http_instance.get(path, headers)
|
59
|
+
end
|
51
60
|
end
|
52
61
|
log_x_deprecation_header(response)
|
53
62
|
|
@@ -55,24 +64,20 @@ class Puppet::Node::Facts::Puppetdb < Puppet::Indirector::REST
|
|
55
64
|
profile("Parse fact query response (size: #{response.body.size})",
|
56
65
|
[:puppetdb, :facts, :find, :parse_response, request.key]) do
|
57
66
|
result = JSON.parse(response.body)
|
58
|
-
|
59
|
-
# if the node isn't found. However, PuppetDB returns an empty array in
|
60
|
-
# this case; for now we will just look for that condition and assume that
|
61
|
-
# it means that the node wasn't found, so we will return nil. In the
|
62
|
-
# future we may want to improve the logic such that we can distinguish
|
63
|
-
# between the "node not found" and the "no facts for this node" cases.
|
64
|
-
if result.empty?
|
65
|
-
return nil
|
66
|
-
end
|
67
|
+
|
67
68
|
facts = result.inject({}) do |a,h|
|
68
69
|
a.merge(h['name'] => h['value'])
|
69
70
|
end
|
71
|
+
|
70
72
|
Puppet::Node::Facts.new(request.key, facts)
|
71
73
|
end
|
72
74
|
else
|
73
75
|
# Newline characters cause an HTTP error, so strip them
|
74
76
|
raise "[#{response.code} #{response.message}] #{response.body.gsub(/[\r\n]/, '')}"
|
75
77
|
end
|
78
|
+
rescue NotFoundError => e
|
79
|
+
# This is what the inventory service expects when there is no data
|
80
|
+
return nil
|
76
81
|
rescue => e
|
77
82
|
raise Puppet::Error, "Failed to find facts from PuppetDB at #{self.class.server}:#{self.class.port}: #{e}"
|
78
83
|
end
|
@@ -115,10 +120,11 @@ class Puppet::Node::Facts::Puppetdb < Puppet::Indirector::REST
|
|
115
120
|
query_param = CGI.escape(query.to_json)
|
116
121
|
|
117
122
|
begin
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
123
|
+
response = Http.action("/pdb/query/v4/nodes?query=#{query_param}") do |http_instance, path|
|
124
|
+
profile("Fact query request: #{URI.unescape(path)}",
|
125
|
+
[:puppetdb, :facts, :search, :query_request, request.key]) do
|
126
|
+
http_instance.get(path, headers)
|
127
|
+
end
|
122
128
|
end
|
123
129
|
log_x_deprecation_header(response)
|
124
130
|
|
@@ -132,7 +138,7 @@ class Puppet::Node::Facts::Puppetdb < Puppet::Indirector::REST
|
|
132
138
|
raise "[#{response.code} #{response.message}] #{response.body.gsub(/[\r\n]/, '')}"
|
133
139
|
end
|
134
140
|
rescue => e
|
135
|
-
raise Puppet::
|
141
|
+
raise Puppet::Util::Puppetdb::InventorySearchError, e.message
|
136
142
|
end
|
137
143
|
end
|
138
144
|
end
|
@@ -12,6 +12,8 @@ class Puppet::Node::Puppetdb < Puppet::Indirector::REST
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def destroy(request)
|
15
|
-
|
15
|
+
payload = { :certname => request.key,
|
16
|
+
:producer_timestamp => request.options[:producer_timestamp] || Time.now.iso8601(5) }
|
17
|
+
submit_command(request.key, payload, CommandDeactivateNode, 3)
|
16
18
|
end
|
17
19
|
end
|
@@ -27,11 +27,13 @@ class Puppet::Resource::Puppetdb < Puppet::Indirector::REST
|
|
27
27
|
query_param = CGI.escape(expr.to_json)
|
28
28
|
|
29
29
|
begin
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
response = Http.action("/pdb/query/v4/resources?query=#{query_param}") do |http_instance, path|
|
31
|
+
profile("Resources query: #{URI.unescape(path)}",
|
32
|
+
[:puppetdb, :resource, :search, :query, request.key]) do
|
33
|
+
http_instance.get(path, headers)
|
34
|
+
end
|
34
35
|
end
|
36
|
+
|
35
37
|
log_x_deprecation_header(response)
|
36
38
|
|
37
39
|
unless response.is_a? Net::HTTPSuccess
|
@@ -19,7 +19,7 @@ Puppet::Reports.register_report(:puppetdb) do
|
|
19
19
|
# @return [void]
|
20
20
|
def process
|
21
21
|
profile("report#process", [:puppetdb, :report, :process]) do
|
22
|
-
submit_command(self.host, report_to_hash, CommandStoreReport,
|
22
|
+
submit_command(self.host, report_to_hash, CommandStoreReport, 5)
|
23
23
|
end
|
24
24
|
|
25
25
|
nil
|
@@ -37,17 +37,24 @@ Puppet::Reports.register_report(:puppetdb) do
|
|
37
37
|
raise Puppet::Error, "Environment is nil, unable to submit report. This may be due a bug with Puppet. Ensure you are running the latest revision, see PUP-2508 for more details."
|
38
38
|
end
|
39
39
|
|
40
|
+
resource_events = build_events_list
|
41
|
+
is_noop = resource_events.any? {|rs| rs["status"] == 'noop'} && resource_events.none? {|rs| rs["status"] == 'failed'}
|
42
|
+
|
40
43
|
{
|
41
44
|
"certname" => host,
|
42
|
-
"
|
43
|
-
"
|
44
|
-
"
|
45
|
-
"
|
46
|
-
"
|
47
|
-
"
|
45
|
+
"puppet_version" => puppet_version,
|
46
|
+
"report_format" => report_format,
|
47
|
+
"configuration_version" => configuration_version.to_s,
|
48
|
+
"producer_timestamp" => Puppet::Util::Puppetdb.to_wire_time(Time.now),
|
49
|
+
"start_time" => Puppet::Util::Puppetdb.to_wire_time(time),
|
50
|
+
"end_time" => Puppet::Util::Puppetdb.to_wire_time(time + run_duration),
|
51
|
+
"resource_events" => resource_events,
|
48
52
|
"environment" => environment,
|
49
|
-
"
|
53
|
+
"transaction_uuid" => transaction_uuid,
|
50
54
|
"status" => status,
|
55
|
+
"noop" => is_noop,
|
56
|
+
"logs" => build_logs_list,
|
57
|
+
"metrics" => build_metrics_list,
|
51
58
|
}
|
52
59
|
end
|
53
60
|
end
|
@@ -69,6 +76,40 @@ Puppet::Reports.register_report(:puppetdb) do
|
|
69
76
|
end
|
70
77
|
end
|
71
78
|
|
79
|
+
# @return Array[Hash]
|
80
|
+
# @api private
|
81
|
+
def build_logs_list
|
82
|
+
profile("Build logs list (count: #{logs.count})",
|
83
|
+
[:puppetdb, :logs_list, :build]) do
|
84
|
+
logs.map do |log|
|
85
|
+
{
|
86
|
+
'file' => log.file,
|
87
|
+
'line' => log.line,
|
88
|
+
'level' => log.level,
|
89
|
+
'message' => log.message,
|
90
|
+
'source' => log.source,
|
91
|
+
'tags' => [*log.tags],
|
92
|
+
'time' => Puppet::Util::Puppetdb.to_wire_time(log.time),
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# @return Array[Hash}
|
99
|
+
# @api private
|
100
|
+
def build_metrics_list
|
101
|
+
profile("Build metrics list (count: #{metrics.count})",
|
102
|
+
[:puppetdb, :metrics_list, :build]) do
|
103
|
+
metrics_list = []
|
104
|
+
metrics.each do |name, data|
|
105
|
+
metric_hashes = data.values.map {|x| {"category" => data.name, "name" => x.first, "value" => x.last}}
|
106
|
+
metrics_list.concat(metric_hashes)
|
107
|
+
end
|
108
|
+
metrics_list
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
72
113
|
# @return Number
|
73
114
|
# @api private
|
74
115
|
def run_duration
|
@@ -97,15 +138,15 @@ Puppet::Reports.register_report(:puppetdb) do
|
|
97
138
|
{
|
98
139
|
"status" => event.status,
|
99
140
|
"timestamp" => Puppet::Util::Puppetdb.to_wire_time(event.time),
|
100
|
-
"
|
101
|
-
"
|
141
|
+
"resource_type" => resource_status.resource_type,
|
142
|
+
"resource_title" => resource_status.title.to_s,
|
102
143
|
"property" => event.property,
|
103
|
-
"
|
104
|
-
"
|
144
|
+
"new_value" => event.desired_value,
|
145
|
+
"old_value" => event.previous_value,
|
105
146
|
"message" => event.message,
|
106
147
|
"file" => resource_status.file,
|
107
148
|
"line" => resource_status.line,
|
108
|
-
"
|
149
|
+
"containment_path" => resource_status.containment_path,
|
109
150
|
}
|
110
151
|
end
|
111
152
|
|
@@ -118,15 +159,15 @@ Puppet::Reports.register_report(:puppetdb) do
|
|
118
159
|
{
|
119
160
|
"status" => event_status,
|
120
161
|
"timestamp" => Puppet::Util::Puppetdb.to_wire_time(resource_status.time),
|
121
|
-
"
|
122
|
-
"
|
162
|
+
"resource_type" => resource_status.resource_type,
|
163
|
+
"resource_title" => resource_status.title.to_s,
|
123
164
|
"property" => nil,
|
124
|
-
"
|
125
|
-
"
|
165
|
+
"new_value" => nil,
|
166
|
+
"old_value" => nil,
|
126
167
|
"message" => nil,
|
127
168
|
"file" => resource_status.file,
|
128
169
|
"line" => resource_status.line,
|
129
|
-
"
|
170
|
+
"containment_path" => resource_status.containment_path,
|
130
171
|
}
|
131
172
|
end
|
132
173
|
|
data/lib/puppet/util/puppetdb.rb
CHANGED
@@ -10,21 +10,19 @@ require 'fileutils'
|
|
10
10
|
|
11
11
|
module Puppet::Util::Puppetdb
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
class CommandSubmissionError < Puppet::Error
|
14
|
+
def initialize(msg, context)
|
15
|
+
super(msg)
|
16
|
+
@context = context
|
17
|
+
end
|
15
18
|
end
|
16
19
|
|
17
|
-
|
18
|
-
config.port
|
20
|
+
class InventorySearchError < Puppet::Error
|
19
21
|
end
|
20
|
-
|
21
|
-
def self.url_path(path)
|
22
|
-
unless path.start_with?("/")
|
23
|
-
path = "/" + path
|
24
|
-
end
|
25
|
-
config.url_prefix + path
|
22
|
+
class SoftWriteFailError < Puppet::Error
|
26
23
|
end
|
27
24
|
|
25
|
+
|
28
26
|
def self.config
|
29
27
|
@config ||= Puppet::Util::Puppetdb::Config.load
|
30
28
|
@config
|
@@ -34,23 +32,6 @@ module Puppet::Util::Puppetdb
|
|
34
32
|
defined?(Puppet::Parser::AST::HashOrArrayAccess)
|
35
33
|
end
|
36
34
|
|
37
|
-
# This magical stuff is needed so that the indirector termini will make requests to
|
38
|
-
# the correct host/port, because this module gets mixed in to our indirector
|
39
|
-
# termini.
|
40
|
-
module ClassMethods
|
41
|
-
def server
|
42
|
-
Puppet::Util::Puppetdb.server
|
43
|
-
end
|
44
|
-
|
45
|
-
def port
|
46
|
-
Puppet::Util::Puppetdb.port
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.included(child)
|
51
|
-
child.extend ClassMethods
|
52
|
-
end
|
53
|
-
|
54
35
|
# Given an instance of ruby's Time class, this method converts it to a String
|
55
36
|
# that conforms to PuppetDB's wire format for representing a date/time.
|
56
37
|
def self.to_wire_time(time)
|
@@ -74,7 +55,7 @@ module Puppet::Util::Puppetdb
|
|
74
55
|
|
75
56
|
# Submit a command to PuppetDB.
|
76
57
|
#
|
77
|
-
# @param certname [String]
|
58
|
+
# @param certname [String] The certname this command operates on
|
78
59
|
# @param payload [String] payload
|
79
60
|
# @param command_name [String] name of command
|
80
61
|
# @param version [Number] version number of command
|
@@ -26,8 +26,8 @@ module Puppet::Util::Puppetdb
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def is_event_blacklisted?(event)
|
29
|
-
@events.fetch(event["
|
30
|
-
fetch(event["
|
29
|
+
@events.fetch(event["resource_type"], {}).
|
30
|
+
fetch(event["resource_title"], {}).
|
31
31
|
fetch(event["status"], {}).
|
32
32
|
fetch(event["property"], false)
|
33
33
|
end
|
@@ -33,7 +33,7 @@ module CharEncoding
|
|
33
33
|
|
34
34
|
|
35
35
|
def self.utf8_string(str)
|
36
|
-
if RUBY_VERSION =~
|
36
|
+
if RUBY_VERSION =~ /^1.8/
|
37
37
|
# Ruby 1.8 doesn't have String#encode and related methods, and there
|
38
38
|
# appears to be a bug in iconv that will interpret some byte sequences
|
39
39
|
# as 6-byte characters. Thus, we are forced to resort to some unfortunate
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'puppet/error'
|
2
|
-
require 'puppet/network/http_pool'
|
3
2
|
require 'puppet/util/puppetdb'
|
3
|
+
require 'puppet/util/puppetdb/http'
|
4
4
|
require 'puppet/util/puppetdb/command_names'
|
5
5
|
require 'puppet/util/puppetdb/char_encoding'
|
6
6
|
require 'json'
|
@@ -9,7 +9,7 @@ class Puppet::Util::Puppetdb::Command
|
|
9
9
|
include Puppet::Util::Puppetdb
|
10
10
|
include Puppet::Util::Puppetdb::CommandNames
|
11
11
|
|
12
|
-
CommandsUrl = "/
|
12
|
+
CommandsUrl = "/pdb/cmd/v1"
|
13
13
|
|
14
14
|
# Public instance methods
|
15
15
|
|
@@ -28,7 +28,21 @@ class Puppet::Util::Puppetdb::Command
|
|
28
28
|
@version = version
|
29
29
|
@certname = certname
|
30
30
|
profile("Format payload", [:puppetdb, :payload, :format]) do
|
31
|
-
@payload =
|
31
|
+
@payload = Puppet::Util::Puppetdb::CharEncoding.utf8_string({
|
32
|
+
:command => command,
|
33
|
+
:version => version,
|
34
|
+
:payload => payload,
|
35
|
+
# We use to_pson still here, to work around the support for shifting
|
36
|
+
# binary data from a catalog to PuppetDB. Attempting to use to_json
|
37
|
+
# we get to_json conversion errors:
|
38
|
+
#
|
39
|
+
# Puppet source sequence is illegal/malformed utf-8
|
40
|
+
# json/ext/GeneratorMethods.java:71:in `to_json'
|
41
|
+
# puppet/util/puppetdb/command.rb:31:in `initialize'
|
42
|
+
#
|
43
|
+
# This is roughly inline with how Puppet serializes for catalogs as of
|
44
|
+
# Puppet 4.1.0. We need a better answer to non-utf8 data end-to-end.
|
45
|
+
}.to_pson)
|
32
46
|
end
|
33
47
|
end
|
34
48
|
|
@@ -44,9 +58,9 @@ class Puppet::Util::Puppetdb::Command
|
|
44
58
|
|
45
59
|
begin
|
46
60
|
response = profile("Submit command HTTP post", [:puppetdb, :command, :submit]) do
|
47
|
-
|
48
|
-
|
49
|
-
|
61
|
+
Http.action("#{CommandsUrl}?checksum=#{checksum}") do |http_instance, path|
|
62
|
+
http_instance.post(path, payload, headers)
|
63
|
+
end
|
50
64
|
end
|
51
65
|
|
52
66
|
Puppet::Util::Puppetdb.log_x_deprecation_header(response)
|
@@ -65,42 +79,30 @@ class Puppet::Util::Puppetdb::Command
|
|
65
79
|
end
|
66
80
|
end
|
67
81
|
rescue => e
|
68
|
-
error = "Failed to submit '#{command}' command#{for_whom} to PuppetDB at #{config.server}:#{config.port}: #{e}"
|
69
82
|
if config.soft_write_failure
|
70
|
-
Puppet.err
|
83
|
+
Puppet.err e.message
|
71
84
|
else
|
72
85
|
# TODO: Use new exception handling methods from Puppet 3.0 here as soon as
|
73
86
|
# we are able to do so (can't call them yet w/o breaking backwards
|
74
87
|
# compatibility.) We should either be using a nested exception or calling
|
75
88
|
# Puppet::Util::Logging#log_exception or #log_and_raise here; w/o them
|
76
89
|
# we lose context as to where the original exception occurred.
|
77
|
-
|
78
|
-
|
90
|
+
if Puppet[:trace]
|
91
|
+
Puppet.err(e)
|
92
|
+
Puppet.err(e.backtrace)
|
93
|
+
end
|
94
|
+
raise Puppet::Util::Puppetdb::CommandSubmissionError.new(e.message, {:command => command, :for_whom => for_whom})
|
79
95
|
end
|
80
96
|
end
|
81
97
|
end
|
82
98
|
|
83
|
-
|
84
|
-
# @!group Private class methods
|
85
|
-
|
86
|
-
# @api private
|
87
|
-
def self.format_payload(command, version, payload)
|
88
|
-
message = {
|
89
|
-
:command => command,
|
90
|
-
:version => version,
|
91
|
-
:payload => payload,
|
92
|
-
}.to_pson
|
93
|
-
|
94
|
-
Puppet::Util::Puppetdb::CharEncoding.utf8_string(message)
|
95
|
-
end
|
96
|
-
|
97
99
|
# @!group Private instance methods
|
98
100
|
|
99
101
|
# @api private
|
100
102
|
def headers
|
101
103
|
{
|
102
104
|
"Accept" => "application/json",
|
103
|
-
"Content-Type" => "application/json",
|
105
|
+
"Content-Type" => "application/json; charset=utf-8",
|
104
106
|
}
|
105
107
|
end
|
106
108
|
|
@@ -1,41 +1,43 @@
|
|
1
1
|
require 'puppet/util/puppetdb/command_names'
|
2
2
|
require 'puppet/util/puppetdb/blacklist'
|
3
|
+
require 'uri'
|
3
4
|
|
4
5
|
module Puppet::Util::Puppetdb
|
5
|
-
class Config
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
6
|
+
class Config
|
7
|
+
include Puppet::Util::Puppetdb::CommandNames
|
8
|
+
|
9
|
+
# Public class methods
|
10
|
+
|
11
|
+
def self.load(config_file = nil)
|
12
|
+
defaults = {
|
13
|
+
:server => "puppetdb",
|
14
|
+
:port => 8081,
|
15
|
+
:soft_write_failure => false,
|
16
|
+
:ignore_blacklisted_events => true,
|
17
|
+
:server_url_timeout => 30
|
18
|
+
}
|
19
|
+
|
20
|
+
config_file ||= File.join(Puppet[:confdir], "puppetdb.conf")
|
21
|
+
|
22
|
+
if File.exists?(config_file)
|
23
|
+
Puppet.debug("Configuring PuppetDB terminuses with config file #{config_file}")
|
24
|
+
content = File.read(config_file)
|
25
|
+
else
|
26
|
+
Puppet.debug("No #{config_file} file found; falling back to default server and port #{defaults[:server]}:#{defaults[:port]}")
|
27
|
+
content = ''
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
result = {}
|
31
|
+
section = nil
|
32
|
+
content.lines.each_with_index do |line,number|
|
33
|
+
# Gotta track the line numbers properly
|
34
|
+
number += 1
|
35
|
+
case line
|
35
36
|
when /^\[(\w+)\s*\]$/
|
36
37
|
section = $1
|
37
38
|
result[section] ||= {}
|
38
|
-
|
39
|
+
|
40
|
+
when /^\s*(\w+)\s*=\s*(\S+|[\S+\s*\,\s*\S]+)\s*$/
|
39
41
|
raise "Setting '#{line}' is illegal outside of section in PuppetDB config #{config_file}:#{number}" unless section
|
40
42
|
result[section][$1] = $2
|
41
43
|
when /^\s*[#;]/
|
@@ -44,86 +46,115 @@ class Config
|
|
44
46
|
# Skip blank lines
|
45
47
|
else
|
46
48
|
raise "Unparseable line '#{line}' in PuppetDB config #{config_file}:#{number}"
|
49
|
+
end
|
47
50
|
end
|
48
|
-
end
|
49
51
|
|
52
|
+
main_section = result['main'] || {}
|
53
|
+
# symbolize the keys
|
54
|
+
main_section = main_section.inject({}) {|h, (k,v)| h[k.to_sym] = v ; h}
|
55
|
+
# merge with defaults but filter out anything except the legal settings
|
56
|
+
config_hash = defaults.merge(main_section).reject do |k, v|
|
57
|
+
!([:server,
|
58
|
+
:port,
|
59
|
+
:ignore_blacklisted_events,
|
60
|
+
:soft_write_failure,
|
61
|
+
:server_urls,
|
62
|
+
:server_url_timeout].include?(k))
|
63
|
+
end
|
50
64
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
65
|
+
if config_hash[:server_urls]
|
66
|
+
uses_server_urls = true
|
67
|
+
config_hash[:server_urls] = config_hash[:server_urls].split(",").map {|s| s.strip}
|
68
|
+
else
|
69
|
+
uses_server_urls = false
|
70
|
+
config_hash[:server_urls] = ["https://#{config_hash[:server].strip}:#{config_hash[:port].to_s}"]
|
71
|
+
end
|
72
|
+
config_hash[:server_urls] = convert_and_validate_urls(config_hash[:server_urls])
|
73
|
+
|
74
|
+
config_hash[:server_url_timeout] = config_hash[:server_url_timeout].to_i
|
75
|
+
config_hash[:ignore_blacklisted_events] = Puppet::Util::Puppetdb.to_bool(config_hash[:ignore_blacklisted_events])
|
76
|
+
config_hash[:soft_write_failure] = Puppet::Util::Puppetdb.to_bool(config_hash[:soft_write_failure])
|
77
|
+
|
78
|
+
self.new(config_hash, uses_server_urls)
|
79
|
+
rescue => detail
|
80
|
+
Puppet.warning "Could not configure PuppetDB terminuses: #{detail}"
|
81
|
+
Puppet.warning detail.backtrace if Puppet[:trace]
|
82
|
+
raise
|
57
83
|
end
|
58
84
|
|
59
|
-
|
60
|
-
config_hash[:port] = config_hash[:port].to_i
|
61
|
-
config_hash[:url_prefix] = normalize_url_prefix(config_hash[:url_prefix].strip)
|
62
|
-
config_hash[:ignore_blacklisted_events] =
|
63
|
-
Puppet::Util::Puppetdb.to_bool(config_hash[:ignore_blacklisted_events])
|
64
|
-
config_hash[:soft_write_failure] =
|
65
|
-
Puppet::Util::Puppetdb.to_bool(config_hash[:soft_write_failure])
|
66
|
-
|
67
|
-
self.new(config_hash)
|
68
|
-
rescue => detail
|
69
|
-
puts detail.backtrace if Puppet[:trace]
|
70
|
-
Puppet.warning "Could not configure PuppetDB terminuses: #{detail}"
|
71
|
-
raise
|
72
|
-
end
|
73
|
-
|
74
|
-
# @!group Public instance methods
|
85
|
+
# @!group Public instance methods
|
75
86
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
87
|
+
def initialize(config_hash = {}, uses_server_urls=nil)
|
88
|
+
@config = config_hash
|
89
|
+
initialize_blacklisted_events()
|
90
|
+
if !uses_server_urls
|
91
|
+
Puppet.warning("Specification of server and port in puppetdb.conf is deprecated. Use the setting server_urls.")
|
92
|
+
end
|
93
|
+
# To provide accurate error messages to users about HTTP failures, we
|
94
|
+
# need to know whether they initially defined their config via the old
|
95
|
+
# server/port combo or the new server_urls. This boolean keeps track
|
96
|
+
# of how the user defined that config so that we can give them a
|
97
|
+
# better error message
|
98
|
+
@server_url_config = uses_server_urls
|
99
|
+
end
|
84
100
|
|
85
|
-
|
86
|
-
|
87
|
-
|
101
|
+
def server_url_config?
|
102
|
+
@server_url_config
|
103
|
+
end
|
88
104
|
|
89
|
-
|
90
|
-
|
91
|
-
|
105
|
+
def server_urls
|
106
|
+
config[:server_urls]
|
107
|
+
end
|
92
108
|
|
93
|
-
|
94
|
-
|
95
|
-
|
109
|
+
def server_url_timeout
|
110
|
+
config[:server_url_timeout]
|
111
|
+
end
|
96
112
|
|
97
|
-
|
98
|
-
|
99
|
-
|
113
|
+
def ignore_blacklisted_events?
|
114
|
+
config[:ignore_blacklisted_events]
|
115
|
+
end
|
100
116
|
|
101
|
-
|
102
|
-
|
103
|
-
|
117
|
+
def is_event_blacklisted?(event)
|
118
|
+
@blacklist.is_event_blacklisted? event
|
119
|
+
end
|
104
120
|
|
105
|
-
|
106
|
-
|
107
|
-
if prefix == ""
|
108
|
-
prefix
|
109
|
-
elsif prefix.start_with?("/")
|
110
|
-
prefix
|
111
|
-
else
|
112
|
-
"/" + prefix
|
121
|
+
def soft_write_failure
|
122
|
+
config[:soft_write_failure]
|
113
123
|
end
|
114
|
-
end
|
115
124
|
|
116
|
-
|
125
|
+
# @!group Private instance methods
|
117
126
|
|
118
|
-
|
119
|
-
|
120
|
-
|
127
|
+
# @!attribute [r] count
|
128
|
+
# @api private
|
129
|
+
attr_reader :config
|
121
130
|
|
122
|
-
|
131
|
+
Blacklist = Puppet::Util::Puppetdb::Blacklist
|
132
|
+
|
133
|
+
# @api private
|
134
|
+
def initialize_blacklisted_events(events = Blacklist::BlacklistedEvents)
|
135
|
+
@blacklist = Blacklist.new(events)
|
136
|
+
end
|
123
137
|
|
124
|
-
|
125
|
-
|
126
|
-
|
138
|
+
def self.convert_and_validate_urls(uri_strings)
|
139
|
+
uri_strings.map do |uri_string|
|
140
|
+
|
141
|
+
begin
|
142
|
+
uri = URI(uri_string.strip)
|
143
|
+
rescue URI::InvalidURIError => e
|
144
|
+
raise URI::InvalidURIError.new, "Error parsing URL '#{uri_string}' in PuppetDB 'server_urls', error message was '#{e.message}'"
|
145
|
+
end
|
146
|
+
|
147
|
+
if uri.scheme != 'https'
|
148
|
+
raise "PuppetDB 'server_urls' must be https, found '#{uri_string}'"
|
149
|
+
end
|
150
|
+
|
151
|
+
if uri.path != '' && uri.path != '/'
|
152
|
+
raise "PuppetDB 'server_urls' cannot contain URL paths, found '#{uri_string}'"
|
153
|
+
end
|
154
|
+
uri.path = ''
|
155
|
+
|
156
|
+
uri
|
157
|
+
end
|
158
|
+
end
|
127
159
|
end
|
128
160
|
end
|
129
|
-
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'puppet/network/http_pool'
|
3
|
+
require 'net/http'
|
4
|
+
require 'timeout'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
module Puppet::Util::Puppetdb
|
8
|
+
class Http
|
9
|
+
|
10
|
+
SERVER_URL_FAIL_MSG = "Failing over to the next PuppetDB url in the 'server_urls' list"
|
11
|
+
|
12
|
+
# Concat two url snippets, taking into account a trailing/leading slash to
|
13
|
+
# ensure a correct url is constructed
|
14
|
+
#
|
15
|
+
# @param snippet1 [String] first URL snippet
|
16
|
+
# @param snippet2 [String] second URL snippet
|
17
|
+
# @return [String] returns http response
|
18
|
+
# @api private
|
19
|
+
def self.concat_url_snippets(snippet1, snippet2)
|
20
|
+
if snippet1.end_with?('/') and snippet2.start_with?('/')
|
21
|
+
snippet1 + snippet2[1..-1]
|
22
|
+
elsif !snippet1.end_with?('/') and !snippet2.start_with?('/')
|
23
|
+
snippet1 + '/' + snippet2
|
24
|
+
else
|
25
|
+
snippet1 + snippet2
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Setup an http connection, provide a block that will do something with that http
|
30
|
+
# connection. The block should be a two argument block, accepting the connection (which
|
31
|
+
# you can call get or post on for example) and the properly constructed path, which
|
32
|
+
# will be the concatenated version of any url_prefix and the path passed in.
|
33
|
+
#
|
34
|
+
# @param path_suffix [String] path for the get/post of the http action
|
35
|
+
# @param http_callback [Proc] proc containing the code calling the action on the http connection
|
36
|
+
# @return [Response] returns http response
|
37
|
+
def self.action(path_suffix, &http_callback)
|
38
|
+
|
39
|
+
response = nil
|
40
|
+
config = Puppet::Util::Puppetdb.config
|
41
|
+
server_url_config = config.server_url_config?
|
42
|
+
|
43
|
+
for url in Puppet::Util::Puppetdb.config.server_urls
|
44
|
+
begin
|
45
|
+
route = concat_url_snippets(url.request_uri, path_suffix)
|
46
|
+
http = Puppet::Network::HttpPool.http_instance(url.host, url.port)
|
47
|
+
request_timeout = config.server_url_timeout
|
48
|
+
|
49
|
+
response = timeout(request_timeout) do
|
50
|
+
http_callback.call(http, route)
|
51
|
+
end
|
52
|
+
|
53
|
+
if response.is_a? Net::HTTPServerError
|
54
|
+
Puppet.warning("Error connecting to #{url.host} on #{url.port} at route #{route}, error message received was '#{response.message}'. #{SERVER_URL_FAIL_MSG if server_url_config}")
|
55
|
+
response = nil
|
56
|
+
elsif response.is_a? Net::HTTPNotFound
|
57
|
+
if response.body && response.body.chars.first == "{"
|
58
|
+
# If it appears to be json, we've probably gotten an authentic 'not found' message.
|
59
|
+
Puppet.debug("HTTP 404 (probably normal) when connecting to #{url.host} on #{url.port} at route #{route}, error message received was '#{response.message}'. #{SERVER_URL_FAIL_MSG if server_url_config}")
|
60
|
+
response = :notfound
|
61
|
+
else
|
62
|
+
# But we can also get 404s when conneting to a puppetdb that's still starting or due to misconfiguration.
|
63
|
+
Puppet.warning("Error connecting to #{url.host} on #{url.port} at route #{route}, error message received was '#{response.message}'. #{SERVER_URL_FAIL_MSG if server_url_config}")
|
64
|
+
response = nil
|
65
|
+
end
|
66
|
+
else
|
67
|
+
break
|
68
|
+
end
|
69
|
+
rescue Timeout::Error => e
|
70
|
+
Puppet.warning("Request to #{url.host} on #{url.port} at route #{route} timed out after #{request_timeout} seconds. #{SERVER_URL_FAIL_MSG if server_url_config}")
|
71
|
+
|
72
|
+
rescue SocketError, OpenSSL::SSL::SSLError, SystemCallError, Net::ProtocolError, IOError, Net::HTTPNotFound => e
|
73
|
+
Puppet.warning("Error connecting to #{url.host} on #{url.port} at route #{route}, error message received was '#{e.message}'. #{SERVER_URL_FAIL_MSG if server_url_config}")
|
74
|
+
|
75
|
+
rescue Puppet::Util::Puppetdb::InventorySearchError => e
|
76
|
+
Puppet.warning("Could not perform inventory search from PuppetDB at #{url.host}:#{url.port}: '#{e.message}' #{SERVER_URL_FAIL_MSG if server_url_config}")
|
77
|
+
|
78
|
+
rescue Puppet::Util::Puppetdb::CommandSubmissionError => e
|
79
|
+
error = "Failed to submit '#{e.context[:command]}' command for '#{e.context[:for_whom]}' to PuppetDB at #{url.host}:#{url.port}: '#{e.message}'."
|
80
|
+
if config.soft_write_failure
|
81
|
+
Puppet.err error
|
82
|
+
else
|
83
|
+
Puppet.warning(error + " #{SERVER_URL_FAIL_MSG if server_url_config}")
|
84
|
+
end
|
85
|
+
rescue Puppet::Util::Puppetdb::SoftWriteFailError => e
|
86
|
+
Puppet.warning("Failed to submit '#{e.context[:command]}' command for '#{e.context[:for_whom]}' to PuppetDB at #{url.host}:#{url.port}: '#{e.message}' #{SERVER_URL_FAIL_MSG if server_url_config}")
|
87
|
+
rescue Puppet::Error => e
|
88
|
+
if e.message =~ /did not match server certificate; expected one of/
|
89
|
+
Puppet.warning("Error connecting to #{url.host} on #{url.port} at route #{route}, error message received was '#{e.message}'. #{SERVER_URL_FAIL_MSG if server_url_config}")
|
90
|
+
else
|
91
|
+
raise
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
if response.nil? or response == :notfound
|
97
|
+
if server_url_config
|
98
|
+
server_url_strings = Puppet::Util::Puppetdb.config.server_urls.map {|url| url.to_s}.join(', ')
|
99
|
+
if response == :notfound
|
100
|
+
raise NotFoundError, "Failed to find '#{path_suffix}' on any of the following 'server_urls': #{server_url_strings}"
|
101
|
+
else
|
102
|
+
raise Puppet::Error, "Failed to execute '#{path_suffix}' on any of the following 'server_urls': #{server_url_strings}"
|
103
|
+
end
|
104
|
+
else
|
105
|
+
uri = Puppet::Util::Puppetdb.config.server_urls.first
|
106
|
+
if response == :notfound
|
107
|
+
raise NotFoundError, "Failed to find '#{path_suffix}' on server: '#{uri.host}' and port: '#{uri.port}'"
|
108
|
+
else
|
109
|
+
raise Puppet::Error, "Failed to execute '#{path_suffix}' on server: '#{uri.host}' and port: '#{uri.port}'"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
response
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class NotFoundError < Puppet::Error
|
120
|
+
end
|
121
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quixoten-puppetdb-terminus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Devin Christensen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,7 @@ files:
|
|
66
66
|
- lib/puppet/util/puppetdb/command.rb
|
67
67
|
- lib/puppet/util/puppetdb/command_names.rb
|
68
68
|
- lib/puppet/util/puppetdb/config.rb
|
69
|
+
- lib/puppet/util/puppetdb/http.rb
|
69
70
|
- lib/puppetdb-terminus.rb
|
70
71
|
- lib/puppetdb/terminus.rb
|
71
72
|
- lib/puppetdb/terminus/version.rb
|
@@ -91,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
92
|
version: '0'
|
92
93
|
requirements: []
|
93
94
|
rubyforge_project:
|
94
|
-
rubygems_version: 2.5.
|
95
|
+
rubygems_version: 2.5.2
|
95
96
|
signing_key:
|
96
97
|
specification_version: 4
|
97
98
|
summary: PuppetDB Terminus
|