quixoten-puppetdb-terminus 2.3.8 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|