choria-mcorpc-support 2.20.8 → 2.23.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mcollective.rb +1 -1
- data/lib/mcollective/agent/bolt_tasks.ddl +235 -0
- data/lib/mcollective/agent/bolt_tasks.json +347 -0
- data/lib/mcollective/agent/bolt_tasks.rb +176 -0
- data/lib/mcollective/agent/choria_util.ddl +152 -0
- data/lib/mcollective/agent/choria_util.json +244 -0
- data/lib/mcollective/agent/rpcutil.ddl +7 -3
- data/lib/mcollective/agent/rpcutil.json +333 -0
- data/lib/mcollective/agent/scout.ddl +169 -0
- data/lib/mcollective/agent/scout.json +224 -0
- data/lib/mcollective/agents.rb +7 -6
- data/lib/mcollective/aggregate.rb +4 -4
- data/lib/mcollective/aggregate/average.rb +2 -2
- data/lib/mcollective/aggregate/base.rb +2 -2
- data/lib/mcollective/aggregate/result.rb +3 -3
- data/lib/mcollective/aggregate/result/collection_result.rb +2 -2
- data/lib/mcollective/aggregate/result/numeric_result.rb +2 -2
- data/lib/mcollective/aggregate/sum.rb +2 -2
- data/lib/mcollective/aggregate/summary.rb +3 -4
- data/lib/mcollective/application.rb +57 -21
- data/lib/mcollective/application/choria.rb +249 -0
- data/lib/mcollective/application/completion.rb +6 -6
- data/lib/mcollective/application/describe_filter.rb +20 -20
- data/lib/mcollective/application/facts.rb +19 -11
- data/lib/mcollective/application/federation.rb +239 -0
- data/lib/mcollective/application/find.rb +4 -4
- data/lib/mcollective/application/help.rb +3 -3
- data/lib/mcollective/application/inventory.rb +3 -341
- data/lib/mcollective/application/ping.rb +3 -77
- data/lib/mcollective/application/playbook.rb +207 -0
- data/lib/mcollective/application/plugin.rb +106 -106
- data/lib/mcollective/application/rpc.rb +3 -108
- data/lib/mcollective/application/tasks.rb +416 -0
- data/lib/mcollective/applications.rb +11 -10
- data/lib/mcollective/audit/choria.rb +33 -0
- data/lib/mcollective/cache.rb +2 -4
- data/lib/mcollective/client.rb +11 -10
- data/lib/mcollective/config.rb +21 -34
- data/lib/mcollective/connector/base.rb +2 -1
- data/lib/mcollective/connector/nats.ddl +9 -0
- data/lib/mcollective/connector/nats.rb +450 -0
- data/lib/mcollective/data.rb +8 -3
- data/lib/mcollective/data/agent_data.rb +1 -1
- data/lib/mcollective/data/base.rb +6 -5
- data/lib/mcollective/data/bolt_task_data.ddl +90 -0
- data/lib/mcollective/data/bolt_task_data.rb +32 -0
- data/lib/mcollective/data/collective_data.rb +1 -1
- data/lib/mcollective/data/fact_data.rb +6 -6
- data/lib/mcollective/data/fstat_data.rb +2 -4
- data/lib/mcollective/data/result.rb +7 -2
- data/lib/mcollective/ddl/agentddl.rb +5 -17
- data/lib/mcollective/ddl/base.rb +11 -14
- data/lib/mcollective/discovery.rb +12 -26
- data/lib/mcollective/discovery/choria.ddl +11 -0
- data/lib/mcollective/discovery/choria.rb +223 -0
- data/lib/mcollective/discovery/flatfile.rb +7 -8
- data/lib/mcollective/discovery/mc.rb +2 -2
- data/lib/mcollective/discovery/stdin.rb +17 -18
- data/lib/mcollective/exceptions.rb +13 -0
- data/lib/mcollective/facts/base.rb +9 -9
- data/lib/mcollective/facts/yaml_facts.rb +12 -12
- data/lib/mcollective/generators.rb +3 -3
- data/lib/mcollective/generators/agent_generator.rb +3 -4
- data/lib/mcollective/generators/base.rb +14 -15
- data/lib/mcollective/generators/data_generator.rb +5 -6
- data/lib/mcollective/log.rb +2 -2
- data/lib/mcollective/logger/base.rb +3 -2
- data/lib/mcollective/logger/console_logger.rb +10 -10
- data/lib/mcollective/logger/file_logger.rb +7 -7
- data/lib/mcollective/logger/syslog_logger.rb +11 -15
- data/lib/mcollective/matcher.rb +14 -14
- data/lib/mcollective/matcher/parser.rb +31 -41
- data/lib/mcollective/matcher/scanner.rb +69 -74
- data/lib/mcollective/message.rb +10 -17
- data/lib/mcollective/monkey_patches.rb +2 -4
- data/lib/mcollective/optionparser.rb +1 -0
- data/lib/mcollective/pluginmanager.rb +3 -5
- data/lib/mcollective/pluginpackager.rb +1 -3
- data/lib/mcollective/pluginpackager/agent_definition.rb +10 -11
- data/lib/mcollective/pluginpackager/forge_packager.rb +7 -9
- data/lib/mcollective/pluginpackager/standard_definition.rb +1 -2
- data/lib/mcollective/registration/base.rb +18 -16
- data/lib/mcollective/rpc.rb +2 -4
- data/lib/mcollective/rpc/actionrunner.rb +16 -18
- data/lib/mcollective/rpc/agent.rb +26 -43
- data/lib/mcollective/rpc/audit.rb +1 -0
- data/lib/mcollective/rpc/client.rb +67 -85
- data/lib/mcollective/rpc/helpers.rb +55 -62
- data/lib/mcollective/rpc/progress.rb +2 -2
- data/lib/mcollective/rpc/reply.rb +17 -19
- data/lib/mcollective/rpc/request.rb +7 -5
- data/lib/mcollective/rpc/result.rb +6 -8
- data/lib/mcollective/rpc/stats.rb +49 -58
- data/lib/mcollective/security/base.rb +29 -36
- data/lib/mcollective/security/choria.rb +765 -0
- data/lib/mcollective/shell.rb +9 -4
- data/lib/mcollective/signer/base.rb +28 -0
- data/lib/mcollective/signer/choria.rb +185 -0
- data/lib/mcollective/ssl.rb +8 -6
- data/lib/mcollective/util.rb +58 -55
- data/lib/mcollective/util/bolt_support.rb +176 -0
- data/lib/mcollective/util/bolt_support/plan_runner.rb +167 -0
- data/lib/mcollective/util/bolt_support/task_result.rb +94 -0
- data/lib/mcollective/util/bolt_support/task_results.rb +128 -0
- data/lib/mcollective/util/choria.rb +1103 -0
- data/lib/mcollective/util/indifferent_hash.rb +12 -0
- data/lib/mcollective/util/natswrapper.rb +242 -0
- data/lib/mcollective/util/playbook.rb +435 -0
- data/lib/mcollective/util/playbook/data_stores.rb +201 -0
- data/lib/mcollective/util/playbook/data_stores/base.rb +99 -0
- data/lib/mcollective/util/playbook/data_stores/consul_data_store.rb +88 -0
- data/lib/mcollective/util/playbook/data_stores/environment_data_store.rb +33 -0
- data/lib/mcollective/util/playbook/data_stores/etcd_data_store.rb +42 -0
- data/lib/mcollective/util/playbook/data_stores/file_data_store.rb +106 -0
- data/lib/mcollective/util/playbook/data_stores/shell_data_store.rb +103 -0
- data/lib/mcollective/util/playbook/inputs.rb +265 -0
- data/lib/mcollective/util/playbook/nodes.rb +207 -0
- data/lib/mcollective/util/playbook/nodes/mcollective_nodes.rb +86 -0
- data/lib/mcollective/util/playbook/nodes/pql_nodes.rb +40 -0
- data/lib/mcollective/util/playbook/nodes/shell_nodes.rb +55 -0
- data/lib/mcollective/util/playbook/nodes/terraform_nodes.rb +65 -0
- data/lib/mcollective/util/playbook/nodes/yaml_nodes.rb +47 -0
- data/lib/mcollective/util/playbook/playbook_logger.rb +47 -0
- data/lib/mcollective/util/playbook/puppet_logger.rb +51 -0
- data/lib/mcollective/util/playbook/report.rb +152 -0
- data/lib/mcollective/util/playbook/task_result.rb +55 -0
- data/lib/mcollective/util/playbook/tasks.rb +196 -0
- data/lib/mcollective/util/playbook/tasks/base.rb +45 -0
- data/lib/mcollective/util/playbook/tasks/graphite_event_task.rb +64 -0
- data/lib/mcollective/util/playbook/tasks/mcollective_task.rb +356 -0
- data/lib/mcollective/util/playbook/tasks/shell_task.rb +93 -0
- data/lib/mcollective/util/playbook/tasks/slack_task.rb +105 -0
- data/lib/mcollective/util/playbook/tasks/webhook_task.rb +136 -0
- data/lib/mcollective/util/playbook/template_util.rb +98 -0
- data/lib/mcollective/util/playbook/uses.rb +169 -0
- data/lib/mcollective/util/tasks_support.rb +733 -0
- data/lib/mcollective/util/tasks_support/cli.rb +260 -0
- data/lib/mcollective/util/tasks_support/default_formatter.rb +138 -0
- data/lib/mcollective/util/tasks_support/json_formatter.rb +108 -0
- data/lib/mcollective/validator.rb +8 -3
- data/lib/mcollective/validator/bolt_task_name_validator.ddl +7 -0
- data/lib/mcollective/validator/bolt_task_name_validator.rb +11 -0
- data/lib/mcollective/validator/length_validator.rb +1 -3
- data/lib/mcollective/validator/typecheck_validator.rb +4 -0
- metadata +67 -4
@@ -0,0 +1,249 @@
|
|
1
|
+
module MCollective
|
2
|
+
class Application
|
3
|
+
class Choria < Application
|
4
|
+
description "Choria Orchestrator Management and Configuration"
|
5
|
+
|
6
|
+
usage <<-USAGE
|
7
|
+
mco choria [OPTIONS] <ACTION>
|
8
|
+
|
9
|
+
The ACTION can be one of the following:
|
10
|
+
|
11
|
+
request_cert - requests a certificate from the Puppet CA
|
12
|
+
show_config - shows the active configuration parameters
|
13
|
+
|
14
|
+
The environment is chosen using --environment and the concurrent
|
15
|
+
runs may be limited using --batch.
|
16
|
+
|
17
|
+
The batching works a bit different than typical, it will only batch
|
18
|
+
based on a sorted list of certificate names, this means the batches
|
19
|
+
will always run in predictable order.
|
20
|
+
USAGE
|
21
|
+
|
22
|
+
exclude_argument_sections "common", "filter", "rpc"
|
23
|
+
|
24
|
+
option :ca,
|
25
|
+
:arguments => ["--ca SERVER"],
|
26
|
+
:description => "Address of your Puppet CA",
|
27
|
+
:type => String
|
28
|
+
|
29
|
+
option :certname,
|
30
|
+
:arguments => ["--certname CERTNAME"],
|
31
|
+
:description => "Override the default certificate name",
|
32
|
+
:type => String
|
33
|
+
|
34
|
+
def post_option_parser(configuration)
|
35
|
+
if ARGV.length >= 1
|
36
|
+
configuration[:command] = ARGV.shift
|
37
|
+
else
|
38
|
+
abort("Please specify a command, valid commands are: %s" % valid_commands.join(", "))
|
39
|
+
end
|
40
|
+
|
41
|
+
ENV["MCOLLECTIVE_CERTNAME"] = configuration[:certname] if configuration[:certname]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Validates the configuration
|
45
|
+
#
|
46
|
+
# @return [void]
|
47
|
+
def validate_configuration(configuration)
|
48
|
+
Util.loadclass("MCollective::Util::Choria")
|
49
|
+
|
50
|
+
abort("Unknown command %s, valid commands are: %s" % [configuration[:command], valid_commands.join(", ")]) unless valid_commands.include?(configuration[:command])
|
51
|
+
|
52
|
+
if !choria.has_client_public_cert? && !["request_cert", "show_config"].include?(configuration[:command])
|
53
|
+
abort("A certificate is needed from the Puppet CA for `%s`, please use the `request_cert` command" % choria.certname)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def main
|
58
|
+
send("%s_command" % configuration[:command])
|
59
|
+
rescue Util::Choria::UserError
|
60
|
+
warn("Encountered a critical error: %s" % Util.colorize(:red, $!.to_s))
|
61
|
+
rescue Util::Choria::Abort
|
62
|
+
exit(1)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Requests a certificate from the CA
|
66
|
+
#
|
67
|
+
# @return [void]
|
68
|
+
def request_cert_command
|
69
|
+
disconnect
|
70
|
+
|
71
|
+
raise(Util::Choria::UserError, "Cannot only request certificates in Puppet security mode") unless choria.puppet_security?
|
72
|
+
|
73
|
+
raise(Util::Choria::UserError, "Already have a certificate '%s', cannot request a new one" % choria.client_public_cert) if choria.has_client_public_cert?
|
74
|
+
|
75
|
+
choria.ca = configuration[:ca] if configuration[:ca]
|
76
|
+
|
77
|
+
certname = choria.client_public_cert
|
78
|
+
|
79
|
+
choria.make_ssl_dirs
|
80
|
+
choria.fetch_ca
|
81
|
+
|
82
|
+
if choria.waiting_for_cert?
|
83
|
+
puts("Certificate %s has already been requested, attempting to retrieve it" % certname)
|
84
|
+
else
|
85
|
+
puts("Requesting certificate for '%s'" % certname)
|
86
|
+
choria.request_cert
|
87
|
+
end
|
88
|
+
|
89
|
+
puts("Waiting up to 240 seconds for it to be signed")
|
90
|
+
puts
|
91
|
+
|
92
|
+
puts("Key fingerprint: %s" % choria.csr_fingerprint)
|
93
|
+
puts
|
94
|
+
|
95
|
+
24.times do |time|
|
96
|
+
print "Attempting to download certificate %s: %d / 24\r" % [certname, time]
|
97
|
+
|
98
|
+
break if choria.attempt_fetch_cert
|
99
|
+
|
100
|
+
sleep 10
|
101
|
+
end
|
102
|
+
|
103
|
+
unless choria.has_client_public_cert?
|
104
|
+
raise(Util::Choria::UserError, "Could not fetch the certificate after 240 seconds, please ensure it gets signed and rerun this command")
|
105
|
+
end
|
106
|
+
|
107
|
+
puts("Certificate %s has been stored in %s" % [certname, choria.ssl_dir])
|
108
|
+
end
|
109
|
+
|
110
|
+
def show_config_command # rubocop:disable Metrics/MethodLength
|
111
|
+
disconnect
|
112
|
+
|
113
|
+
puts "Active Choria configuration:"
|
114
|
+
puts
|
115
|
+
puts "The active configuration used in Choria comes from using Puppet AIO defaults, querying SRV"
|
116
|
+
puts "records and reading configuration files. The below information shows the completely resolved"
|
117
|
+
puts "configuration that will be used when running MCollective commands"
|
118
|
+
puts
|
119
|
+
puts "MCollective related:"
|
120
|
+
puts
|
121
|
+
puts " MCollective Version: %s" % MCollective::VERSION
|
122
|
+
puts " Choria Version: %s" % Util::Choria::VERSION
|
123
|
+
puts " Client Config File: %s" % Util.config_file_for_user
|
124
|
+
puts " Active Config File: %s" % Config.instance.configfile
|
125
|
+
puts " Plugin Config Dir: %s" % File.join(Config.instance.configdir, "plugin.d")
|
126
|
+
puts " Using SRV Records: %s" % choria.should_use_srv?
|
127
|
+
puts " Federated: %s" % choria.federated?
|
128
|
+
puts " SRV Domain: %s" % choria.srv_domain
|
129
|
+
puts " NATS NGS: %s" % choria.ngs?
|
130
|
+
|
131
|
+
middleware_servers = choria.middleware_servers("puppet", 4222).map {|s, p| "%s:%s" % [s, p]}.join(", ")
|
132
|
+
|
133
|
+
puts " Middleware Servers: %s" % middleware_servers
|
134
|
+
|
135
|
+
if choria.federated?
|
136
|
+
fed_servers = choria.federation_middleware_servers
|
137
|
+
if fed_servers
|
138
|
+
puts " Federation Servers: %s" % fed_servers.map {|s, p| "%s:%s" % [s, p]}.join(", ")
|
139
|
+
else
|
140
|
+
puts " Federation Servers: %s (fallback to normal client settings)" % middleware_servers
|
141
|
+
end
|
142
|
+
puts " Federation Collectives: %s" % choria.federation_collectives.join(", ")
|
143
|
+
end
|
144
|
+
|
145
|
+
puts
|
146
|
+
|
147
|
+
puppet_server = choria.puppet_server
|
148
|
+
puppetca_server = choria.puppetca_server
|
149
|
+
puppetdb_server = choria.puppetdb_server
|
150
|
+
|
151
|
+
puts "Puppet related:"
|
152
|
+
puts
|
153
|
+
puts " Puppet Server: %s:%s" % [puppet_server[:target], puppet_server[:port]]
|
154
|
+
puts " PuppetCA Server: %s:%s" % [puppetca_server[:target], puppetca_server[:port]]
|
155
|
+
puts " PuppetDB Server: %s:%s" % [puppetdb_server[:target], puppetdb_server[:port]]
|
156
|
+
|
157
|
+
if choria.proxied_discovery?
|
158
|
+
proxy_server = choria.discovery_server
|
159
|
+
puts " Discovery Proxy: %s:%s" % [proxy_server[:target], proxy_server[:port]]
|
160
|
+
else
|
161
|
+
puts " Discovery Proxy: not using a proxy"
|
162
|
+
end
|
163
|
+
|
164
|
+
puts " Facter Command: %s" % choria.facter_cmd
|
165
|
+
puts " Facter Domain: %s" % choria.facter_domain
|
166
|
+
|
167
|
+
puts
|
168
|
+
|
169
|
+
puts "Security setup:"
|
170
|
+
puts
|
171
|
+
|
172
|
+
valid_ssl = choria.check_ssl_setup(false) rescue false
|
173
|
+
|
174
|
+
if valid_ssl
|
175
|
+
puts " Valid SSL Setup: %s" % [Util.colorize(:green, "yes")]
|
176
|
+
else
|
177
|
+
puts " Valid SSL Setup: %s try running 'mco choria request_cert'" % [Util.colorize(:red, "no")]
|
178
|
+
end
|
179
|
+
|
180
|
+
puts " Security Provider: %s" % [choria.security_provider]
|
181
|
+
puts " Certname: %s" % [choria.certname]
|
182
|
+
puts " SSL Directory: %s (%s)" % [choria.ssl_dir, File.exist?(choria.ssl_dir) ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
183
|
+
puts " Client Public Cert: %s (%s)" % [choria.client_public_cert, choria.has_client_public_cert? ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
184
|
+
puts " Client Private Key: %s (%s)" % [choria.client_private_key, choria.has_client_private_key? ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
185
|
+
puts " CA Path: %s (%s)" % [choria.ca_path, choria.has_ca? ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
186
|
+
puts " CSR Path: %s (%s)" % [choria.csr_path, choria.has_csr? ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
187
|
+
|
188
|
+
if choria.has_client_public_cert?
|
189
|
+
cn = choria.valid_certificate?(File.read(choria.client_public_cert), choria.certname, false)
|
190
|
+
|
191
|
+
puts " Public Cert CN: %s (%s)" % [cn, cn == choria.certname ? Util.colorize(:green, "match") : Util.colorize(:red, "does not match certname")]
|
192
|
+
end
|
193
|
+
|
194
|
+
if choria.credential_file?
|
195
|
+
puts " NATS Credentials: %s (%s)" % [
|
196
|
+
choria.credential_file,
|
197
|
+
File.exist?(choria.credential_file) ? Util.colorize(:green, "exit") : Util.colorize(:red, "does not exist")
|
198
|
+
]
|
199
|
+
puts " 'nkeys' gem: %s" % choria.nkeys?
|
200
|
+
end
|
201
|
+
|
202
|
+
puts
|
203
|
+
|
204
|
+
puts "Active Choria configuration settings as found in configuration files:"
|
205
|
+
puts
|
206
|
+
|
207
|
+
choria_settings = Config.instance.pluginconf.select {|k, _| k.start_with?("choria")}
|
208
|
+
padding = choria_settings.empty? ? 2 : choria_settings.keys.map(&:length).max + 2
|
209
|
+
|
210
|
+
if choria_settings.empty?
|
211
|
+
puts " No custom Choria settings found in your configuration files"
|
212
|
+
else
|
213
|
+
choria_settings.each do |k, v|
|
214
|
+
puts "%#{padding}s: %s" % [k, v]
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
puts
|
219
|
+
end
|
220
|
+
|
221
|
+
# Creates and cache a Choria helper class
|
222
|
+
#
|
223
|
+
# @return [Util::Choria]
|
224
|
+
def choria
|
225
|
+
@_choria ||= Util::Choria.new(false)
|
226
|
+
end
|
227
|
+
|
228
|
+
# List of valid commands this application respond to
|
229
|
+
#
|
230
|
+
# @return [Array<String>] like `plan` and `run`
|
231
|
+
def valid_commands
|
232
|
+
methods.grep(/_command$/).map {|c| c.to_s.gsub("_command", "")}
|
233
|
+
end
|
234
|
+
|
235
|
+
# Asks the user to confirm something on the CLI
|
236
|
+
#
|
237
|
+
# @note exits the application on no
|
238
|
+
# @param msg [String] the message to ask
|
239
|
+
# @return [void]
|
240
|
+
def confirm(msg)
|
241
|
+
print("%s (y/n) " % msg)
|
242
|
+
|
243
|
+
$stdout.flush
|
244
|
+
|
245
|
+
exit(1) unless $stdin.gets.strip.match?(/^(?:y|yes)$/i)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module MCollective
|
2
|
-
class Application::Completion<MCollective::Application
|
2
|
+
class Application::Completion < MCollective::Application # rubocop:disable Style/ClassAndModuleChildren
|
3
3
|
description "Helper for shell completion systems"
|
4
4
|
|
5
5
|
exclude_argument_sections "common", "filter", "rpc"
|
@@ -43,8 +43,8 @@ module MCollective
|
|
43
43
|
PluginManager.find(:agent, "ddl").each do |agent|
|
44
44
|
begin
|
45
45
|
ddl = DDL.new(agent)
|
46
|
-
puts "%s:%s" % [
|
47
|
-
rescue
|
46
|
+
puts "%s:%s" % [agent, ddl.meta[:description]]
|
47
|
+
rescue # rubocop:disable Lint/SuppressedException
|
48
48
|
end
|
49
49
|
end
|
50
50
|
else
|
@@ -64,7 +64,7 @@ module MCollective
|
|
64
64
|
else
|
65
65
|
DDL.new(configuration[:agent], :agent).actions.sort.each {|a| puts a}
|
66
66
|
end
|
67
|
-
rescue
|
67
|
+
rescue # rubocop:disable Lint/SuppressedException
|
68
68
|
end
|
69
69
|
|
70
70
|
def list_inputs
|
@@ -79,7 +79,7 @@ module MCollective
|
|
79
79
|
else
|
80
80
|
DDL.new(configuration[:agent], :agent).action_interface(configuration[:action])[:input].keys.sort.each {|i| puts i}
|
81
81
|
end
|
82
|
-
rescue
|
82
|
+
rescue # rubocop:disable Lint/SuppressedException
|
83
83
|
end
|
84
84
|
|
85
85
|
def list_applications
|
@@ -93,7 +93,7 @@ module MCollective
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def main
|
96
|
-
actions = configuration.keys.map
|
96
|
+
actions = configuration.keys.map(&:to_s).grep(/^list_/)
|
97
97
|
|
98
98
|
abort "Please choose either --list-[agents|actions|inputs|applications]" if actions.empty?
|
99
99
|
abort "Please choose only one of --list-[agents|actions|inputs|applications]" if actions.size > 1
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module MCollective
|
2
|
-
class Application::Describe_filter<Application
|
2
|
+
class Application::Describe_filter < Application # rubocop:disable Style/ClassAndModuleChildren
|
3
3
|
exclude_argument_sections "common", "rpc"
|
4
4
|
|
5
5
|
description "Display human readable interpretation of filters"
|
@@ -12,30 +12,29 @@ module MCollective
|
|
12
12
|
puts "-S Query expands to the following instructions:"
|
13
13
|
puts
|
14
14
|
stack.each do |token|
|
15
|
-
|
15
|
+
case token.keys[0]
|
16
|
+
when "statement"
|
16
17
|
if token.values[0] =~ /(<=|>=|=|=~|=)/
|
17
18
|
op = $1
|
18
|
-
k,v = token.values[0].split(op)
|
19
|
+
k, v = token.values[0].split(op)
|
19
20
|
puts indent + get_fact_string(k, v, op)
|
20
21
|
else
|
21
22
|
puts indent + get_class_string(token.values[0])
|
22
23
|
end
|
23
|
-
|
24
|
+
when "fstatement"
|
24
25
|
v = token.values[0]
|
25
|
-
result_string = indent + "Execute the Data Query '#{v[
|
26
|
-
if v["params"]
|
27
|
-
result_string += " with parameters (#{v["params"]})"
|
28
|
-
end
|
26
|
+
result_string = indent + "Execute the Data Query '#{v['name']}'"
|
27
|
+
result_string += " with parameters (#{v['params']})" if v["params"]
|
29
28
|
result_string += ". "
|
30
|
-
result_string += "Check if the query's '#{v[
|
29
|
+
result_string += "Check if the query's '#{v['value']}' value #{v['operator']} '#{v['r_compare']}' "
|
31
30
|
puts result_string
|
32
|
-
|
33
|
-
puts indent
|
31
|
+
when "("
|
32
|
+
puts "#{indent}("
|
34
33
|
old_indent = indent
|
35
34
|
indent *= 2
|
36
|
-
|
35
|
+
when ")"
|
37
36
|
indent = old_indent
|
38
|
-
puts indent
|
37
|
+
puts "#{indent})"
|
39
38
|
else
|
40
39
|
puts indent + token.keys[0].upcase
|
41
40
|
end
|
@@ -46,7 +45,7 @@ module MCollective
|
|
46
45
|
puts "-F filter expands to the following fact comparisons:"
|
47
46
|
puts
|
48
47
|
facts.each do |f|
|
49
|
-
puts "
|
48
|
+
puts " #{get_fact_string(f[:fact], f[:value], f[:operator])}"
|
50
49
|
end
|
51
50
|
end
|
52
51
|
|
@@ -54,30 +53,31 @@ module MCollective
|
|
54
53
|
puts "-C filter expands to the following class checks:"
|
55
54
|
puts
|
56
55
|
classes.each do |c|
|
57
|
-
puts "
|
56
|
+
puts " #{get_class_string(c)}"
|
58
57
|
end
|
59
58
|
end
|
60
59
|
|
61
60
|
def main
|
62
|
-
|
61
|
+
unless @options[:filter]["fact"].empty?
|
63
62
|
describe_f_filter(@options[:filter]["fact"])
|
64
63
|
puts
|
65
64
|
end
|
66
65
|
|
67
|
-
|
66
|
+
unless @options[:filter]["cf_class"].empty?
|
68
67
|
describe_c_filter(@options[:filter]["cf_class"])
|
69
68
|
puts
|
70
69
|
end
|
71
70
|
|
72
|
-
|
71
|
+
unless @options[:filter]["compound"].empty?
|
73
72
|
describe_s_filter(@options[:filter]["compound"][0])
|
74
73
|
puts
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
78
77
|
private
|
79
|
-
|
80
|
-
|
78
|
+
|
79
|
+
def get_fact_string(fact, value, oper)
|
80
|
+
"Check if fact '#{fact}' #{oper} '#{value}'"
|
81
81
|
end
|
82
82
|
|
83
83
|
def get_class_string(classname)
|
@@ -1,8 +1,8 @@
|
|
1
|
-
class MCollective::Application::Facts<MCollective::Application
|
1
|
+
class MCollective::Application::Facts < MCollective::Application # rubocop:disable Style/ClassAndModuleChildren
|
2
2
|
description "Reports on usage for a specific fact"
|
3
3
|
|
4
4
|
def post_option_parser(configuration)
|
5
|
-
configuration[:fact] = ARGV.shift
|
5
|
+
configuration[:fact] = ARGV.shift unless ARGV.empty?
|
6
6
|
end
|
7
7
|
|
8
8
|
def validate_configuration(configuration)
|
@@ -12,22 +12,30 @@ class MCollective::Application::Facts<MCollective::Application
|
|
12
12
|
def show_single_fact_report(fact, facts, verbose=false)
|
13
13
|
puts("Report for fact: #{fact}\n\n")
|
14
14
|
|
15
|
+
facts = stringify_facts_hash(facts)
|
16
|
+
|
15
17
|
field_size = MCollective::Util.field_size(facts.keys)
|
16
18
|
facts.keys.sort.each do |k|
|
17
19
|
printf(" %-#{field_size}s found %d times\n", k, facts[k].size)
|
18
20
|
|
19
|
-
|
20
|
-
puts
|
21
|
+
next unless verbose
|
21
22
|
|
22
|
-
|
23
|
-
puts(" #{f}")
|
24
|
-
end
|
23
|
+
puts
|
25
24
|
|
26
|
-
|
25
|
+
facts[k].sort.each do |f|
|
26
|
+
puts(" #{f}")
|
27
27
|
end
|
28
|
+
|
29
|
+
puts
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
33
|
+
def stringify_facts_hash(facts)
|
34
|
+
res = Hash.new([])
|
35
|
+
facts.each { |k, v| res[k.to_s] += v }
|
36
|
+
res
|
37
|
+
end
|
38
|
+
|
31
39
|
def main
|
32
40
|
rpcutil = rpcclient("rpcutil")
|
33
41
|
rpcutil.progress = false
|
@@ -42,11 +50,11 @@ class MCollective::Application::Facts<MCollective::Application
|
|
42
50
|
if facts.include?(value)
|
43
51
|
facts[value] << resp[:senderid]
|
44
52
|
else
|
45
|
-
facts[value] = [
|
53
|
+
facts[value] = [resp[:senderid]]
|
46
54
|
end
|
47
55
|
end
|
48
|
-
rescue Exception => e
|
49
|
-
|
56
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
57
|
+
warn "Could not parse facts for #{resp[:senderid]}: #{e.class}: #{e}"
|
50
58
|
end
|
51
59
|
end
|
52
60
|
|
@@ -0,0 +1,239 @@
|
|
1
|
+
module MCollective
|
2
|
+
class Application
|
3
|
+
class Federation < Application
|
4
|
+
description "Choria Federation Broker Utilities"
|
5
|
+
|
6
|
+
usage <<-USAGE
|
7
|
+
mco federation [OPTIONS] <ACTION>
|
8
|
+
|
9
|
+
The ACTION can be one of the following:
|
10
|
+
|
11
|
+
trace - trace the path to a client
|
12
|
+
|
13
|
+
USAGE
|
14
|
+
|
15
|
+
exclude_argument_sections "common", "filter", "rpc"
|
16
|
+
|
17
|
+
option :collective,
|
18
|
+
:description => "Target messages to a specific sub collective",
|
19
|
+
:arguments => ["-T", "--target COLLECTIVE"],
|
20
|
+
:type => String,
|
21
|
+
:required => false
|
22
|
+
|
23
|
+
# Publish a specially crafted 'ping' with seen-by headers
|
24
|
+
# embedded, this signals to the entire collective to record
|
25
|
+
# their route
|
26
|
+
def trace_node(node)
|
27
|
+
options[:filter] = Util.empty_filter
|
28
|
+
|
29
|
+
request = Message.new("ping", nil,
|
30
|
+
:agent => "discovery",
|
31
|
+
:filter => options[:filter],
|
32
|
+
:collective => options[:collective],
|
33
|
+
:type => :request,
|
34
|
+
:headers => {"seen-by" => []},
|
35
|
+
:options => options)
|
36
|
+
|
37
|
+
request.discovered_hosts = [node]
|
38
|
+
|
39
|
+
client = Client.new(options)
|
40
|
+
found_time = 0
|
41
|
+
route = []
|
42
|
+
|
43
|
+
stats = client.req(request) do |reply, message|
|
44
|
+
abort("Tracing requests requires MCollective 2.10.3 or newer") unless message
|
45
|
+
|
46
|
+
found_time = Time.now.to_f
|
47
|
+
|
48
|
+
abort("Received a response from %s while expecting a response from %s" % [reply[:senderid], node]) unless reply[:senderid] == node
|
49
|
+
|
50
|
+
route = message.headers["seen-by"]
|
51
|
+
end
|
52
|
+
|
53
|
+
raise("Did not receive any responses to trace request") if stats[:responses] == 0
|
54
|
+
|
55
|
+
{:route => route, :stats => stats, :response_time => (found_time - stats[:starttime]), :request => request.requestid}
|
56
|
+
end
|
57
|
+
|
58
|
+
def route_to(route, destination)
|
59
|
+
route.take_while {|hop| hop[1] != destination}
|
60
|
+
end
|
61
|
+
|
62
|
+
def route_back(route, destination)
|
63
|
+
route.reverse.take_while {|hop| hop.size == 2 || hop[1] != destination}.reverse
|
64
|
+
end
|
65
|
+
|
66
|
+
def destination_hop(route)
|
67
|
+
route[route_to(route, destination).size]
|
68
|
+
end
|
69
|
+
|
70
|
+
def extract_federation_brokers(route, destination)
|
71
|
+
abort("Unexpected route size %d found" % route.size) unless route.size == 5
|
72
|
+
|
73
|
+
[route_to(route, destination).last[1], route_back(route, destination).first[1]]
|
74
|
+
end
|
75
|
+
|
76
|
+
def draw_cluster(left, right, direction, indent)
|
77
|
+
if left.last == right.first && direction == :out
|
78
|
+
"%s└── %s" % [" " * indent, left.last]
|
79
|
+
elsif left.last == right.first
|
80
|
+
"%s┌── %s" % [" " * indent, left.last]
|
81
|
+
elsif direction == :out
|
82
|
+
[
|
83
|
+
"%s└─┐ %s" % [" " * indent, left.last],
|
84
|
+
"%s └ %s" % [" " * indent, right.first]
|
85
|
+
].join("\n")
|
86
|
+
else
|
87
|
+
[
|
88
|
+
"%s ┌ %s" % [" " * indent, left.last],
|
89
|
+
"%s┌─┘ %s" % [" " * indent, right.first]
|
90
|
+
].join("\n")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# @todo this is aweful brute force rubbish while I dont know what I want, make some algo
|
95
|
+
def display_unfederated_route(route)
|
96
|
+
c_out, node, c_in = route
|
97
|
+
|
98
|
+
if c_out[1] == node[0] && node[2] == c_out[1] && node[0] == c_out[1]
|
99
|
+
puts " Shared Middleware"
|
100
|
+
puts
|
101
|
+
puts " %s" % Util.colorize(:cyan, c_out[0])
|
102
|
+
puts draw_cluster(c_out, node, :out, 7)
|
103
|
+
puts " └── %s" % Util.colorize(:yellow, node[1])
|
104
|
+
|
105
|
+
elsif c_out[1] == c_in[0] && node[0] == node[2]
|
106
|
+
puts " NATS Cluster with Symetrical Path"
|
107
|
+
puts
|
108
|
+
puts " %s" % Util.colorize(:cyan, c_out[0])
|
109
|
+
puts draw_cluster(c_out, node, :out, 7)
|
110
|
+
puts " └── %s" % Util.colorize(:yellow, node[1])
|
111
|
+
|
112
|
+
else
|
113
|
+
puts " NATS Cluster with Asymmetrical Path"
|
114
|
+
puts
|
115
|
+
puts " %s" % Util.colorize(:cyan, c_out[0])
|
116
|
+
puts draw_cluster(c_out, node, :out, 5)
|
117
|
+
puts " ├── %s" % Util.colorize(:yellow, node[1])
|
118
|
+
puts draw_cluster(node, c_in, :in, 5)
|
119
|
+
puts " %s" % Util.colorize(:cyan, c_in[1])
|
120
|
+
end
|
121
|
+
puts
|
122
|
+
puts "[%s] Client [%s] Server [%s] Middleware" % [
|
123
|
+
Util.colorize(:cyan, "█"), Util.colorize(:yellow, "█"), "█"
|
124
|
+
]
|
125
|
+
puts
|
126
|
+
end
|
127
|
+
|
128
|
+
# @todo this is aweful brute force rubbish while I dont know what I want, make some algo
|
129
|
+
def display_federated_route(route)
|
130
|
+
c_out, fb1, node, fb2, c_in = route
|
131
|
+
|
132
|
+
puts " %s" % Util.colorize(:bold, "Request:")
|
133
|
+
puts " %s" % Util.colorize(:cyan, c_out[0])
|
134
|
+
puts draw_cluster(c_out, fb1, :out, 7)
|
135
|
+
puts " └─ %s" % Util.colorize(:green, fb1[1])
|
136
|
+
puts draw_cluster(fb1, node, :out, 15)
|
137
|
+
puts " └── %s" % Util.colorize(:yellow, node[1])
|
138
|
+
puts
|
139
|
+
puts " %s" % Util.colorize(:bold, "Reply:")
|
140
|
+
puts " ┌── %s" % Util.colorize(:yellow, node[1])
|
141
|
+
puts draw_cluster(node, fb2, :int, 15)
|
142
|
+
puts " ┌─ %s" % Util.colorize(:green, fb2[1])
|
143
|
+
puts draw_cluster(fb2, c_in, :in, 7)
|
144
|
+
puts " %s" % Util.colorize(:cyan, c_in[1])
|
145
|
+
puts
|
146
|
+
puts "[%s] Client [%s] Federation Broker [%s] Server [%s] Middleware" % [
|
147
|
+
Util.colorize(:cyan, "█"), Util.colorize(:green, "█"), Util.colorize(:yellow, "█"), "█"
|
148
|
+
]
|
149
|
+
puts
|
150
|
+
end
|
151
|
+
|
152
|
+
def trace_command
|
153
|
+
result = trace_node(configuration[:host])
|
154
|
+
|
155
|
+
abort("No routes were reported, are your nodes running a supported version?") if result[:route].empty?
|
156
|
+
|
157
|
+
puts "Received response from %s in %.2fms for message %s" % [configuration[:host], result[:response_time] * 1000, result[:request]]
|
158
|
+
puts
|
159
|
+
|
160
|
+
route = result[:route]
|
161
|
+
puts "Reported Route:"
|
162
|
+
puts
|
163
|
+
case route.size
|
164
|
+
when 5
|
165
|
+
display_federated_route(route)
|
166
|
+
when 3
|
167
|
+
display_unfederated_route(route)
|
168
|
+
end
|
169
|
+
|
170
|
+
puts
|
171
|
+
|
172
|
+
puts "Federation Brokers Instances:"
|
173
|
+
puts
|
174
|
+
if choria.federated?
|
175
|
+
extract_federation_brokers(result[:route], configuration[:host]).sort.uniq.each do |broker|
|
176
|
+
puts " %s" % broker
|
177
|
+
end
|
178
|
+
else
|
179
|
+
puts " Unfederated"
|
180
|
+
end
|
181
|
+
puts
|
182
|
+
|
183
|
+
puts "Known Federation Broker Clusters:"
|
184
|
+
puts
|
185
|
+
if choria.federated?
|
186
|
+
puts " %s" % choria.federation_collectives.join(", ")
|
187
|
+
else
|
188
|
+
puts " Unfederated"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Creates and cache a Choria helper class
|
193
|
+
#
|
194
|
+
# @return [Util::Choria]
|
195
|
+
def choria
|
196
|
+
@_choria ||= Util::Choria.new
|
197
|
+
end
|
198
|
+
|
199
|
+
def post_option_parser(configuration)
|
200
|
+
if ARGV.length >= 1
|
201
|
+
configuration[:command] = ARGV.shift
|
202
|
+
else
|
203
|
+
abort("Please specify a command, valid commands are: %s" % valid_commands.join(", "))
|
204
|
+
end
|
205
|
+
|
206
|
+
if configuration[:command] == "trace"
|
207
|
+
if ARGV.length >= 1
|
208
|
+
configuration[:host] = ARGV.shift
|
209
|
+
else
|
210
|
+
abort("Please specify a host to trace, example: mco federation trace node1.prod.example.net")
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def validate_configuration(configuration)
|
216
|
+
Util.loadclass("MCollective::Util::Choria")
|
217
|
+
|
218
|
+
abort("Unknown command %s, valid commands are: %s" % [configuration[:command], valid_commands.join(", ")]) unless valid_commands.include?(configuration[:command])
|
219
|
+
|
220
|
+
if !choria.has_client_public_cert? && !["request_cert", "show_config"].include?(configuration[:command])
|
221
|
+
abort("A certificate is needed from the Puppet CA for `%s`, please use the `request_cert` command" % choria.certname)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def main
|
226
|
+
send("%s_command" % configuration[:command])
|
227
|
+
rescue Interrupt
|
228
|
+
exit
|
229
|
+
end
|
230
|
+
|
231
|
+
# List of valid commands this application respond to
|
232
|
+
#
|
233
|
+
# @return [Array<String>] like `plan` and `run`
|
234
|
+
def valid_commands
|
235
|
+
methods.grep(/_command$/).map {|c| c.to_s.gsub("_command", "")}
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|