choria-mcorpc-support 2.23.0 → 2.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/lib/mcollective.rb +3 -3
- data/lib/mcollective/agent/bolt_tasks.ddl +18 -0
- data/lib/mcollective/agent/bolt_tasks.json +18 -0
- data/lib/mcollective/agent/bolt_tasks.rb +4 -2
- data/lib/mcollective/agent/rpcutil.ddl +2 -2
- data/lib/mcollective/agent/rpcutil.json +2 -2
- data/lib/mcollective/application/choria.rb +3 -63
- data/lib/mcollective/application/facts.rb +2 -67
- data/lib/mcollective/application/federation.rb +1 -3
- data/lib/mcollective/application/find.rb +1 -1
- data/lib/mcollective/application/ping.rb +31 -3
- data/lib/mcollective/application/plugin.rb +2 -15
- data/lib/mcollective/application/tasks.rb +9 -0
- data/lib/mcollective/client.rb +1 -1
- data/lib/mcollective/config.rb +135 -103
- data/lib/mcollective/ddl.rb +0 -1
- data/lib/mcollective/discovery.rb +12 -65
- data/lib/mcollective/discovery/broadcast.ddl +11 -0
- data/lib/mcollective/discovery/choria.ddl +6 -4
- data/lib/mcollective/discovery/delegate.ddl +13 -0
- data/lib/mcollective/discovery/delegate.rb +73 -0
- data/lib/mcollective/discovery/external.ddl +13 -0
- data/lib/mcollective/discovery/file.ddl +13 -0
- data/lib/mcollective/discovery/flatfile.ddl +7 -5
- data/lib/mcollective/discovery/inventory.ddl +13 -0
- data/lib/mcollective/discovery/mc.ddl +3 -3
- data/lib/mcollective/generators.rb +0 -1
- data/lib/mcollective/message.rb +0 -24
- data/lib/mcollective/optionparser.rb +2 -2
- data/lib/mcollective/pluginpackager/forge_packager.rb +1 -1
- data/lib/mcollective/rpc/client.rb +6 -4
- data/lib/mcollective/security/base.rb +1 -37
- data/lib/mcollective/util.rb +23 -31
- data/lib/mcollective/util/choria.rb +0 -157
- data/lib/mcollective/util/tasks_support.rb +22 -3
- metadata +9 -27
- data/lib/mcollective/application/describe_filter.rb +0 -87
- data/lib/mcollective/data.rb +0 -96
- data/lib/mcollective/data/agent_data.ddl +0 -22
- data/lib/mcollective/data/agent_data.rb +0 -17
- data/lib/mcollective/data/base.rb +0 -68
- data/lib/mcollective/data/bolt_task_data.ddl +0 -90
- data/lib/mcollective/data/bolt_task_data.rb +0 -32
- data/lib/mcollective/data/collective_data.ddl +0 -20
- data/lib/mcollective/data/collective_data.rb +0 -9
- data/lib/mcollective/data/fact_data.ddl +0 -28
- data/lib/mcollective/data/fact_data.rb +0 -55
- data/lib/mcollective/data/fstat_data.ddl +0 -89
- data/lib/mcollective/data/fstat_data.rb +0 -54
- data/lib/mcollective/data/result.rb +0 -50
- data/lib/mcollective/ddl/dataddl.rb +0 -56
- data/lib/mcollective/discovery/choria.rb +0 -223
- data/lib/mcollective/discovery/flatfile.rb +0 -47
- data/lib/mcollective/discovery/stdin.ddl +0 -11
- data/lib/mcollective/discovery/stdin.rb +0 -67
- data/lib/mcollective/generators/data_generator.rb +0 -50
- data/lib/mcollective/generators/templates/data_input_snippet.erb +0 -7
- data/lib/mcollective/matcher.rb +0 -220
- data/lib/mcollective/matcher/parser.rb +0 -118
- data/lib/mcollective/matcher/scanner.rb +0 -236
@@ -0,0 +1,13 @@
|
|
1
|
+
metadata :name => "delegate",
|
2
|
+
:description => "Choria CLI based delegated discovery",
|
3
|
+
:author => "R.I.Pienaar <rip@devco.net>",
|
4
|
+
:license => "Apache-2.0",
|
5
|
+
:version => "0.1",
|
6
|
+
:url => "https://choria.io/",
|
7
|
+
:timeout => 2
|
8
|
+
|
9
|
+
discovery do
|
10
|
+
capabilities [:classes, :facts, :identity, :agents, :compound]
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module MCollective
|
2
|
+
class Discovery
|
3
|
+
class Delegate
|
4
|
+
def self.binary_name
|
5
|
+
"choria"
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.discover(filter, timeout, limit, client)
|
9
|
+
raise("Cannot find the choria binary in your path") unless Util.command_in_path?("choria")
|
10
|
+
|
11
|
+
cmd = [binary_name, "discover", "-j", "--silent"]
|
12
|
+
|
13
|
+
cmd << "-T" << filter["collective"] if filter["collective"]
|
14
|
+
|
15
|
+
filter.fetch("identity", []).each do |i|
|
16
|
+
cmd << "-I" << i
|
17
|
+
end
|
18
|
+
|
19
|
+
filter.fetch("cf_class", []).each do |c|
|
20
|
+
cmd << "-C" << c
|
21
|
+
end
|
22
|
+
|
23
|
+
filter.fetch("fact", []).each do |f|
|
24
|
+
cmd << "-F" << "%s%s%s" % [f[:fact], f[:operator], f[:value]]
|
25
|
+
end
|
26
|
+
|
27
|
+
filter.fetch("agent", []).each do |a|
|
28
|
+
cmd << "-A" << a
|
29
|
+
end
|
30
|
+
|
31
|
+
filter.fetch("compound", []).each do |c|
|
32
|
+
next unless c.is_a?(Array)
|
33
|
+
|
34
|
+
cmd << "-S" << c.first["expr"]
|
35
|
+
end
|
36
|
+
|
37
|
+
client.options.fetch(:discovery_options, []).each do |opt|
|
38
|
+
cmd << "--do" << opt
|
39
|
+
end
|
40
|
+
|
41
|
+
cmd << "--dm" << (client.options.fetch(:discovery_method, "broadcast") rescue "broadcast")
|
42
|
+
|
43
|
+
run_discover(cmd, timeout)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.run_discover(cmd, timeout)
|
47
|
+
nodes = []
|
48
|
+
|
49
|
+
Log.debug("Executing choria for discovery using: %s" % cmd.join(" "))
|
50
|
+
|
51
|
+
Open3.popen3(ENV, *cmd) do |stdin, stdout, stderr, wait_thr|
|
52
|
+
stdin.close
|
53
|
+
|
54
|
+
begin
|
55
|
+
Timeout.timeout(timeout + 0.5) do
|
56
|
+
status = wait_thr.value
|
57
|
+
|
58
|
+
raise("Choria discovery failed: %s" % stderr.read) unless status.exitstatus == 0
|
59
|
+
end
|
60
|
+
rescue Timeout::Error
|
61
|
+
Log.warn("Timeout waiting for Choria to perform discovery")
|
62
|
+
Process.kill("KILL", wait_thr[:pid])
|
63
|
+
raise("Choria failed to complete discovery within %d timeout" % timeout)
|
64
|
+
end
|
65
|
+
|
66
|
+
nodes.concat(JSON.parse(stdout.read))
|
67
|
+
end
|
68
|
+
|
69
|
+
nodes
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
metadata :name => "external",
|
2
|
+
:description => "External executable based discovery",
|
3
|
+
:author => "R.I.Pienaar <rip@devco.net>",
|
4
|
+
:license => "Apache-2.0",
|
5
|
+
:version => "0.1",
|
6
|
+
:url => "https://choria.io/",
|
7
|
+
:timeout => 2
|
8
|
+
|
9
|
+
discovery do
|
10
|
+
capabilities [:classes, :facts, :identity, :agents, :compound]
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
metadata :name => "file",
|
2
|
+
:description => "Discovers from JSON, YAML and Text files",
|
3
|
+
:author => "R.I.Pienaar <rip@devco.net>",
|
4
|
+
:license => "Apache-2.0",
|
5
|
+
:version => "0.1",
|
6
|
+
:url => "https://choria.io/",
|
7
|
+
:timeout => 2
|
8
|
+
|
9
|
+
discovery do
|
10
|
+
capabilities [:identity]
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -1,11 +1,13 @@
|
|
1
1
|
metadata :name => "flatfile",
|
2
|
-
:description => "
|
2
|
+
:description => "Discovers from JSON, YAML and Text files",
|
3
3
|
:author => "R.I.Pienaar <rip@devco.net>",
|
4
|
-
:license => "
|
4
|
+
:license => "Apache-2.0",
|
5
5
|
:version => "0.1",
|
6
|
-
:url => "https://
|
7
|
-
:timeout =>
|
6
|
+
:url => "https://choria.io/",
|
7
|
+
:timeout => 2
|
8
8
|
|
9
9
|
discovery do
|
10
|
-
capabilities :identity
|
10
|
+
capabilities [:identity]
|
11
11
|
end
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
metadata :name => "delegate",
|
2
|
+
:description => "Choria CLI based delegated discovery",
|
3
|
+
:author => "R.I.Pienaar <rip@devco.net>",
|
4
|
+
:license => "Apache 2.0",
|
5
|
+
:version => "0.1",
|
6
|
+
:url => "https://choria.io/",
|
7
|
+
:timeout => 2
|
8
|
+
|
9
|
+
discovery do
|
10
|
+
capabilities [:classes, :facts, :identity, :agents, :compound]
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -1,9 +1,9 @@
|
|
1
1
|
metadata :name => "mc",
|
2
|
-
:description => "
|
2
|
+
:description => "Choria Broadcast based discovery",
|
3
3
|
:author => "R.I.Pienaar <rip@devco.net>",
|
4
|
-
:license => "
|
4
|
+
:license => "Apache-2.0",
|
5
5
|
:version => "0.1",
|
6
|
-
:url => "https://
|
6
|
+
:url => "https://choria.io",
|
7
7
|
:timeout => 2
|
8
8
|
|
9
9
|
discovery do
|
data/lib/mcollective/message.rb
CHANGED
@@ -148,8 +148,6 @@ module MCollective
|
|
148
148
|
@requestid = request.payload[:requestid]
|
149
149
|
@payload = PluginManager["security_plugin"].encodereply(agent, payload, requestid, request.payload[:callerid])
|
150
150
|
when :request, :direct_request
|
151
|
-
validate_compound_filter(@filter["compound"]) unless @filter["compound"].empty?
|
152
|
-
|
153
151
|
@requestid ||= create_reqid
|
154
152
|
@payload = PluginManager["security_plugin"].encoderequest(Config.instance.identity, payload, requestid, filter, agent, collective, ttl)
|
155
153
|
else
|
@@ -157,28 +155,6 @@ module MCollective
|
|
157
155
|
end
|
158
156
|
end
|
159
157
|
|
160
|
-
def validate_compound_filter(compound_filter)
|
161
|
-
compound_filter.each do |filter|
|
162
|
-
filter.each do |statement|
|
163
|
-
next unless statement["fstatement"]
|
164
|
-
|
165
|
-
functionname = statement["fstatement"]["name"]
|
166
|
-
pluginname = Data.pluginname(functionname)
|
167
|
-
value = statement["fstatement"]["value"]
|
168
|
-
|
169
|
-
ddl = DDL.new(pluginname, :data)
|
170
|
-
|
171
|
-
# parses numbers and booleans entered as strings into proper
|
172
|
-
# types of data so that DDL validation will pass
|
173
|
-
statement["fstatement"]["params"] = Data.ddl_transform_input(ddl, statement["fstatement"]["params"])
|
174
|
-
|
175
|
-
Data.ddl_validate(ddl, statement["fstatement"]["params"])
|
176
|
-
|
177
|
-
raise(DDLValidationError, "Data plugin '%s()' does not return a '%s' value" % [functionname, value]) unless value && Data.ddl_has_output?(ddl, value)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
158
|
def decode!
|
183
159
|
raise "Cannot decode message type #{type}" unless [:request, :reply].include?(type)
|
184
160
|
|
@@ -86,7 +86,7 @@ module MCollective
|
|
86
86
|
end
|
87
87
|
|
88
88
|
@parser.on("-S", "--select FILTER", "Compound filter combining facts and classes") do |f|
|
89
|
-
@options[:filter]["compound"] <<
|
89
|
+
@options[:filter]["compound"] << [{"expr" => f}]
|
90
90
|
end
|
91
91
|
|
92
92
|
@parser.on("-F", "--wf", "--with-fact fact=val", "Match hosts with a certain fact") do |f|
|
@@ -168,7 +168,7 @@ module MCollective
|
|
168
168
|
raise "Cannot read the discovery file #{v}" unless File.readable?(v)
|
169
169
|
|
170
170
|
@options[:discovery_method] = "flatfile"
|
171
|
-
@options[:discovery_options] << v
|
171
|
+
@options[:discovery_options] << "file=%s" % v
|
172
172
|
end
|
173
173
|
|
174
174
|
@parser.on("--publish_timeout TIMEOUT", Integer, "Timeout for publishing requests to remote agents.") do |pt|
|
@@ -442,7 +442,7 @@ module MCollective
|
|
442
442
|
|
443
443
|
# Set a compound filter
|
444
444
|
def compound_filter(filter)
|
445
|
-
@filter["compound"] = @filter["compound"] | [
|
445
|
+
@filter["compound"] = @filter["compound"] | [[{"expr" => filter}]]
|
446
446
|
reset
|
447
447
|
end
|
448
448
|
|
@@ -533,6 +533,8 @@ module MCollective
|
|
533
533
|
|
534
534
|
# All else fails we do it the hard way using a traditional broadcast
|
535
535
|
unless @discovered_agents
|
536
|
+
raise("Invalid discovery method %s" % discovery_method) unless @client.discoverer.find_known_methods.include?(discovery_method)
|
537
|
+
|
536
538
|
@stats.time_discovery :start
|
537
539
|
|
538
540
|
@client.options = options
|
@@ -548,9 +550,9 @@ module MCollective
|
|
548
550
|
actual_timeout = @client.discoverer.discovery_timeout(discovery_timeout, options[:filter])
|
549
551
|
|
550
552
|
if actual_timeout > 0
|
551
|
-
@stderr.print("Discovering hosts using the %s method for %d second(s) .... " % [
|
553
|
+
@stderr.print("Discovering hosts using the %s method for %d second(s) .... " % [discovery_method, actual_timeout])
|
552
554
|
else
|
553
|
-
@stderr.print("Discovering hosts using the %s method .... " %
|
555
|
+
@stderr.print("Discovering hosts using the %s method .... " % discovery_method)
|
554
556
|
end
|
555
557
|
end
|
556
558
|
|
@@ -822,7 +824,7 @@ module MCollective
|
|
822
824
|
@stdout.print twirl.twirl(respcount, discovered.size)
|
823
825
|
end
|
824
826
|
|
825
|
-
if batch_size =~ /^(\d+)%$/
|
827
|
+
if batch_size.is_a?(String) && batch_size =~ /^(\d+)%$/
|
826
828
|
# determine batch_size as a percentage of the discovered array's size
|
827
829
|
batch_size = (discovered.size / 100.0 * Integer($1)).ceil
|
828
830
|
else
|
@@ -72,43 +72,7 @@ module MCollective
|
|
72
72
|
end
|
73
73
|
|
74
74
|
when "compound"
|
75
|
-
|
76
|
-
result = false
|
77
|
-
truth_values = []
|
78
|
-
|
79
|
-
begin
|
80
|
-
compound.each do |expression|
|
81
|
-
case expression.keys.first
|
82
|
-
when "statement"
|
83
|
-
truth_values << Matcher.eval_compound_statement(expression).to_s
|
84
|
-
when "fstatement"
|
85
|
-
truth_values << Matcher.eval_compound_fstatement(expression.values.first)
|
86
|
-
when "and"
|
87
|
-
truth_values << "&&"
|
88
|
-
when "or"
|
89
|
-
truth_values << "||"
|
90
|
-
when "("
|
91
|
-
truth_values << "("
|
92
|
-
when ")"
|
93
|
-
truth_values << ")"
|
94
|
-
when "not"
|
95
|
-
truth_values << "!"
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
result = eval(truth_values.join(" ")) # rubocop:disable Security/Eval
|
100
|
-
rescue DDLValidationError
|
101
|
-
result = false
|
102
|
-
end
|
103
|
-
|
104
|
-
if result
|
105
|
-
Log.debug("Passing based on class and fact composition")
|
106
|
-
passed += 1
|
107
|
-
else
|
108
|
-
Log.debug("Failing based on class and fact composition")
|
109
|
-
failed += 1
|
110
|
-
end
|
111
|
-
end
|
75
|
+
# removed while rebuilding compound filters, this whole method is probably unused now
|
112
76
|
|
113
77
|
when "agent"
|
114
78
|
filter[key].each do |f|
|
data/lib/mcollective/util.rb
CHANGED
@@ -156,19 +156,23 @@ module MCollective
|
|
156
156
|
File.join(Dir::COMMON_APPDATA, "ChoriaIO", "choria")
|
157
157
|
end
|
158
158
|
|
159
|
-
def self.
|
159
|
+
def self.config_paths_for_user
|
160
160
|
config_paths = []
|
161
161
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
162
|
+
["~/.choriarc", "~/.mcollective"].each do |f|
|
163
|
+
begin
|
164
|
+
# File.expand_path will raise if HOME isn't set, catch it
|
165
|
+
config_paths << File.expand_path(f)
|
166
|
+
rescue ArgumentError # rubocop:disable Lint/SuppressedException
|
167
|
+
end
|
167
168
|
end
|
168
169
|
|
169
170
|
if windows?
|
171
|
+
config_paths << File.join(choria_windows_prefix, "etc", "client.conf")
|
170
172
|
config_paths << File.join(windows_prefix, "etc", "client.cfg")
|
171
173
|
else
|
174
|
+
config_paths << "/etc/choria/client.conf"
|
175
|
+
config_paths << "/usr/local/etc/choria/client.conf"
|
172
176
|
config_paths << "/etc/puppetlabs/mcollective/client.cfg"
|
173
177
|
config_paths << "/etc/mcollective/client.cfg"
|
174
178
|
config_paths << "/usr/local/etc/mcollective/client.cfg"
|
@@ -177,42 +181,30 @@ module MCollective
|
|
177
181
|
config_paths
|
178
182
|
end
|
179
183
|
|
180
|
-
def self.choria_config_paths_for_user
|
181
|
-
config_paths = []
|
182
|
-
|
183
|
-
begin
|
184
|
-
# File.expand_path will raise if HOME isn't set, catch it
|
185
|
-
user_path = File.expand_path("~/.choriarc")
|
186
|
-
config_paths << user_path
|
187
|
-
rescue Exception # rubocop:disable Lint/RescueException, Lint/SuppressedException
|
188
|
-
end
|
189
|
-
|
190
|
-
if windows?
|
191
|
-
config_paths << File.join(choria_windows_prefix, "etc", "client.conf")
|
192
|
-
else
|
193
|
-
config_paths << "/etc/choria/client.conf"
|
194
|
-
config_paths << "/usr/local/etc/choria/client.conf"
|
195
|
-
end
|
196
|
-
|
197
|
-
config_paths
|
198
|
-
end
|
199
|
-
|
200
184
|
# Picks the default user config file, priorities are first Choria ones then old MCollective ones
|
201
185
|
#
|
202
186
|
# In roughly this order, first to exist is used:
|
203
187
|
#
|
204
188
|
# - ~/.choriarc
|
205
|
-
# - APPData/ChoriaIO/choria/etc/client.conf on windows
|
206
|
-
# - /etc/choria/client.conf then
|
207
|
-
# - /usr/local/etc/choria/client.conf on unix
|
208
189
|
# - ~/.mcollective
|
209
|
-
#
|
190
|
+
#
|
191
|
+
# On Unix:
|
192
|
+
#
|
193
|
+
# - /etc/choria/client.conf
|
194
|
+
# - /usr/local/etc/choria/client.conf
|
210
195
|
# - /etc/puppetlabs/mcollective/client.cfg
|
211
196
|
# - /etc/mcollective/client.cfg
|
212
197
|
# - /usr/local/etc/mcollective/client.cfg
|
198
|
+
#
|
199
|
+
# On Windows:
|
200
|
+
#
|
201
|
+
# - APPData/ChoriaIO/choria/etc/client.conf on windows
|
202
|
+
# - APPData/PuppetLabs/mcollective/etc/client.cfg on windows
|
213
203
|
def self.config_file_for_user
|
214
|
-
config_paths =
|
204
|
+
config_paths = config_paths_for_user
|
205
|
+
|
215
206
|
found = config_paths.find_index { |file| File.readable?(file) } || 0
|
207
|
+
|
216
208
|
config_paths[found]
|
217
209
|
end
|
218
210
|
|
@@ -86,14 +86,6 @@ module MCollective
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
-
# Which port to provide stats over HTTP on
|
90
|
-
#
|
91
|
-
# @return [Integer,nil]
|
92
|
-
# @raise [StandardError] when not numeric
|
93
|
-
def stats_port
|
94
|
-
Integer(get_option("choria.stats_port", "")) if has_option?("choria.stats_port")
|
95
|
-
end
|
96
|
-
|
97
89
|
# Determines if there are any federations configured
|
98
90
|
#
|
99
91
|
# @return [Boolean]
|
@@ -888,15 +880,6 @@ module MCollective
|
|
888
880
|
File.exist?(csr_path)
|
889
881
|
end
|
890
882
|
|
891
|
-
# The formatted string representation of the CSR fingerprint
|
892
|
-
#
|
893
|
-
# @return [String]
|
894
|
-
def csr_fingerprint
|
895
|
-
require "puppet"
|
896
|
-
csr = OpenSSL::X509::Request.new(File.read(csr_path))
|
897
|
-
Puppet::SSL::Digest.new(nil, csr.to_der)
|
898
|
-
end
|
899
|
-
|
900
883
|
# Searches the PATH for an executable command
|
901
884
|
#
|
902
885
|
# @param command [String] a command to search for
|
@@ -927,146 +910,6 @@ module MCollective
|
|
927
910
|
which("facter")
|
928
911
|
end
|
929
912
|
|
930
|
-
# Creates any missing SSL directories
|
931
|
-
#
|
932
|
-
# This prepares a Puppet like SSL tree in case Puppet
|
933
|
-
# has not been initialized yet
|
934
|
-
#
|
935
|
-
# @return [void]
|
936
|
-
def make_ssl_dirs
|
937
|
-
return if file_security?
|
938
|
-
|
939
|
-
FileUtils.mkdir_p(ssl_dir, :mode => 0o0771)
|
940
|
-
|
941
|
-
["certificate_requests", "certs", "public_keys"].each do |dir|
|
942
|
-
FileUtils.mkdir_p(File.join(ssl_dir, dir), :mode => 0o0755)
|
943
|
-
end
|
944
|
-
|
945
|
-
["private_keys", "private"].each do |dir|
|
946
|
-
FileUtils.mkdir_p(File.join(ssl_dir, dir), :mode => 0o0750)
|
947
|
-
end
|
948
|
-
end
|
949
|
-
|
950
|
-
# Creates a RSA key of a certain strenth
|
951
|
-
#
|
952
|
-
# @return [OpenSSL::PKey::RSA]
|
953
|
-
def create_rsa_key(bits)
|
954
|
-
OpenSSL::PKey::RSA.new(bits)
|
955
|
-
end
|
956
|
-
|
957
|
-
# Writes a new 4096 bit key in the puppet default locatioj
|
958
|
-
#
|
959
|
-
# @return [OpenSSL::PKey::RSA]
|
960
|
-
# @raise [StandardError] when the key already exist
|
961
|
-
def write_key
|
962
|
-
raise("Refusing to overwrite existing key in %s" % client_private_key) if has_client_private_key?
|
963
|
-
|
964
|
-
key = create_rsa_key(4096)
|
965
|
-
File.open(client_private_key, "w", 0o0640) {|f| f.write(key.to_pem)}
|
966
|
-
|
967
|
-
key
|
968
|
-
end
|
969
|
-
|
970
|
-
# Creates a basic CSR
|
971
|
-
#
|
972
|
-
# @return [OpenSSL::X509::Request] signed CSR
|
973
|
-
def create_csr(comonname, orgunit, key)
|
974
|
-
csr = OpenSSL::X509::Request.new
|
975
|
-
csr.version = 0
|
976
|
-
csr.public_key = key.public_key
|
977
|
-
csr.subject = OpenSSL::X509::Name.new(
|
978
|
-
[
|
979
|
-
["CN", comonname, OpenSSL::ASN1::UTF8STRING],
|
980
|
-
["OU", orgunit, OpenSSL::ASN1::UTF8STRING]
|
981
|
-
]
|
982
|
-
)
|
983
|
-
csr.sign(key, OpenSSL::Digest.new("SHA1"))
|
984
|
-
|
985
|
-
csr
|
986
|
-
end
|
987
|
-
|
988
|
-
# Creates a new CSR signed by the given key
|
989
|
-
#
|
990
|
-
# @param key [OpenSSL::PKey::RSA]
|
991
|
-
# @return [String] PEM encoded CSR
|
992
|
-
def write_csr(key)
|
993
|
-
raise("Refusing to overwrite existing CSR in %s" % csr_path) if has_csr?
|
994
|
-
|
995
|
-
csr = create_csr(certname, "mcollective", key)
|
996
|
-
|
997
|
-
File.open(csr_path, "w", 0o0644) {|f| f.write(csr.to_pem)}
|
998
|
-
|
999
|
-
csr.to_pem
|
1000
|
-
end
|
1001
|
-
|
1002
|
-
# Fetch and save the CA from Puppet
|
1003
|
-
#
|
1004
|
-
# @return [Boolean]
|
1005
|
-
def fetch_ca
|
1006
|
-
return true if has_ca?
|
1007
|
-
|
1008
|
-
server = puppetca_server
|
1009
|
-
|
1010
|
-
req = http_get("/puppet-ca/v1/certificate/ca?environment=production", "Accept" => "text/plain")
|
1011
|
-
resp, _ = https(server).request(req)
|
1012
|
-
|
1013
|
-
if resp.code == "200"
|
1014
|
-
File.open(ca_path, "w", 0o0644) {|f| f.write(resp.body)}
|
1015
|
-
else
|
1016
|
-
raise(UserError, "Failed to fetch CA from %s:%s: %s: %s" % [server[:target], server[:port], resp.code, resp.message])
|
1017
|
-
end
|
1018
|
-
|
1019
|
-
has_ca?
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
# Requests a certificate from the Puppet CA
|
1023
|
-
#
|
1024
|
-
# This will attempt to create a new key, write a CSR and
|
1025
|
-
# then sends it to the CA for signing
|
1026
|
-
#
|
1027
|
-
# @return [Boolean]
|
1028
|
-
# @raise [UserError] when requesting the cert fails
|
1029
|
-
def request_cert
|
1030
|
-
key = write_key
|
1031
|
-
csr = write_csr(key)
|
1032
|
-
|
1033
|
-
server = puppetca_server
|
1034
|
-
|
1035
|
-
req = Net::HTTP::Put.new("/puppet-ca/v1/certificate_request/%s?environment=production" % certname, "Content-Type" => "text/plain")
|
1036
|
-
req.body = csr
|
1037
|
-
resp, _ = https(server).request(req)
|
1038
|
-
|
1039
|
-
if resp.code == "200"
|
1040
|
-
true
|
1041
|
-
else
|
1042
|
-
raise(UserError, "Failed to request certificate from %s:%s: %s: %s: %s" % [server[:target], server[:port], resp.code, resp.message, resp.body])
|
1043
|
-
end
|
1044
|
-
end
|
1045
|
-
|
1046
|
-
# Attempts to fetch a cert from the CA
|
1047
|
-
#
|
1048
|
-
# @return [Boolean]
|
1049
|
-
def attempt_fetch_cert
|
1050
|
-
return true if has_client_public_cert?
|
1051
|
-
|
1052
|
-
req = http_get("/puppet-ca/v1/certificate/%s?environment=production" % certname, "Accept" => "text/plain")
|
1053
|
-
resp, _ = https(puppetca_server).request(req)
|
1054
|
-
|
1055
|
-
if resp.code == "200"
|
1056
|
-
File.open(client_public_cert, "w", 0o0644) {|f| f.write(resp.body)}
|
1057
|
-
true
|
1058
|
-
else
|
1059
|
-
false
|
1060
|
-
end
|
1061
|
-
end
|
1062
|
-
|
1063
|
-
# Determines if a CSR has been sent but not yet retrieved
|
1064
|
-
#
|
1065
|
-
# @return [Boolean]
|
1066
|
-
def waiting_for_cert?
|
1067
|
-
!has_client_public_cert? && has_client_private_key?
|
1068
|
-
end
|
1069
|
-
|
1070
913
|
# Gets a config option
|
1071
914
|
#
|
1072
915
|
# @param opt [String] config option to look up
|