choria-mcorpc-support 2.23.0 → 2.24.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|