choria-mcorpc-support 2.21.1 → 2.23.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 +4 -4
- data/lib/mcollective.rb +1 -2
- data/lib/mcollective/agent/bolt_tasks.ddl +253 -0
- data/lib/mcollective/agent/bolt_tasks.json +365 -0
- data/lib/mcollective/agent/bolt_tasks.rb +178 -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 +8 -4
- 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 +189 -0
- data/lib/mcollective/application/completion.rb +6 -6
- data/lib/mcollective/application/facts.rb +11 -11
- data/lib/mcollective/application/federation.rb +237 -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 +5 -51
- 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 +425 -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 +10 -13
- data/lib/mcollective/discovery.rb +24 -39
- 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/message.rb +8 -39
- data/lib/mcollective/monkey_patches.rb +2 -4
- data/lib/mcollective/optionparser.rb +2 -1
- data/lib/mcollective/pluginmanager.rb +3 -5
- data/lib/mcollective/pluginpackager.rb +1 -3
- data/lib/mcollective/pluginpackager/agent_definition.rb +3 -8
- 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 +13 -56
- 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 +946 -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 +751 -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 +6 -1
- 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
- metadata +65 -6
- data/lib/mcollective/application/describe_filter.rb +0 -87
- data/lib/mcollective/matcher.rb +0 -220
- data/lib/mcollective/matcher/parser.rb +0 -128
- data/lib/mcollective/matcher/scanner.rb +0 -241
|
@@ -0,0 +1,189 @@
|
|
|
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
|
+
show_config - shows the active configuration parameters
|
|
12
|
+
|
|
13
|
+
USAGE
|
|
14
|
+
|
|
15
|
+
exclude_argument_sections "common", "filter", "rpc"
|
|
16
|
+
|
|
17
|
+
def post_option_parser(configuration)
|
|
18
|
+
if ARGV.length >= 1
|
|
19
|
+
configuration[:command] = ARGV.shift
|
|
20
|
+
else
|
|
21
|
+
abort("Please specify a command, valid commands are: %s" % valid_commands.join(", "))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Validates the configuration
|
|
26
|
+
#
|
|
27
|
+
# @return [void]
|
|
28
|
+
def validate_configuration(configuration)
|
|
29
|
+
Util.loadclass("MCollective::Util::Choria")
|
|
30
|
+
|
|
31
|
+
abort("Unknown command %s, valid commands are: %s" % [configuration[:command], valid_commands.join(", ")]) unless valid_commands.include?(configuration[:command])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def main
|
|
35
|
+
send("%s_command" % configuration[:command])
|
|
36
|
+
rescue Util::Choria::UserError
|
|
37
|
+
warn("Encountered a critical error: %s" % Util.colorize(:red, $!.to_s))
|
|
38
|
+
rescue Util::Choria::Abort
|
|
39
|
+
exit(1)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Requests a certificate from the CA
|
|
43
|
+
#
|
|
44
|
+
# @return [void]
|
|
45
|
+
def request_cert_command
|
|
46
|
+
puts("Please use 'choria enroll' to enroll in the security subsystem")
|
|
47
|
+
raise(Util::Choria::Abort, "1")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def show_config_command # rubocop:disable Metrics/MethodLength
|
|
51
|
+
disconnect
|
|
52
|
+
|
|
53
|
+
puts "Active Choria configuration:"
|
|
54
|
+
puts
|
|
55
|
+
puts "The active configuration used in Choria comes from using Puppet AIO defaults, querying SRV"
|
|
56
|
+
puts "records and reading configuration files. The below information shows the completely resolved"
|
|
57
|
+
puts "configuration that will be used when running MCollective commands"
|
|
58
|
+
puts
|
|
59
|
+
puts "MCollective related:"
|
|
60
|
+
puts
|
|
61
|
+
puts " MCollective Version: %s" % MCollective::VERSION
|
|
62
|
+
puts " Choria Version: %s" % Util::Choria::VERSION
|
|
63
|
+
puts " Client Config File: %s" % Util.config_file_for_user
|
|
64
|
+
puts " Active Config File: %s" % Config.instance.configfile
|
|
65
|
+
puts " Plugin Config Dir: %s" % File.join(Config.instance.configdir, "plugin.d")
|
|
66
|
+
puts " Using SRV Records: %s" % choria.should_use_srv?
|
|
67
|
+
puts " Federated: %s" % choria.federated?
|
|
68
|
+
puts " SRV Domain: %s" % choria.srv_domain
|
|
69
|
+
puts " NATS NGS: %s" % choria.ngs?
|
|
70
|
+
|
|
71
|
+
middleware_servers = choria.middleware_servers("puppet", 4222).map {|s, p| "%s:%s" % [s, p]}.join(", ")
|
|
72
|
+
|
|
73
|
+
puts " Middleware Servers: %s" % middleware_servers
|
|
74
|
+
|
|
75
|
+
if choria.federated?
|
|
76
|
+
fed_servers = choria.federation_middleware_servers
|
|
77
|
+
if fed_servers
|
|
78
|
+
puts " Federation Servers: %s" % fed_servers.map {|s, p| "%s:%s" % [s, p]}.join(", ")
|
|
79
|
+
else
|
|
80
|
+
puts " Federation Servers: %s (fallback to normal client settings)" % middleware_servers
|
|
81
|
+
end
|
|
82
|
+
puts " Federation Collectives: %s" % choria.federation_collectives.join(", ")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
puts
|
|
86
|
+
|
|
87
|
+
puppet_server = choria.puppet_server
|
|
88
|
+
puppetca_server = choria.puppetca_server
|
|
89
|
+
puppetdb_server = choria.puppetdb_server
|
|
90
|
+
|
|
91
|
+
puts "Puppet related:"
|
|
92
|
+
puts
|
|
93
|
+
puts " Puppet Server: %s:%s" % [puppet_server[:target], puppet_server[:port]]
|
|
94
|
+
puts " PuppetCA Server: %s:%s" % [puppetca_server[:target], puppetca_server[:port]]
|
|
95
|
+
puts " PuppetDB Server: %s:%s" % [puppetdb_server[:target], puppetdb_server[:port]]
|
|
96
|
+
|
|
97
|
+
if choria.proxied_discovery?
|
|
98
|
+
proxy_server = choria.discovery_server
|
|
99
|
+
puts " Discovery Proxy: %s:%s" % [proxy_server[:target], proxy_server[:port]]
|
|
100
|
+
else
|
|
101
|
+
puts " Discovery Proxy: not using a proxy"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
puts " Facter Command: %s" % choria.facter_cmd
|
|
105
|
+
puts " Facter Domain: %s" % choria.facter_domain
|
|
106
|
+
|
|
107
|
+
puts
|
|
108
|
+
|
|
109
|
+
puts "Security setup:"
|
|
110
|
+
puts
|
|
111
|
+
|
|
112
|
+
valid_ssl = choria.check_ssl_setup(false) rescue false
|
|
113
|
+
|
|
114
|
+
if valid_ssl
|
|
115
|
+
puts " Valid SSL Setup: %s" % [Util.colorize(:green, "yes")]
|
|
116
|
+
else
|
|
117
|
+
puts " Valid SSL Setup: %s try running 'choria enroll'" % [Util.colorize(:red, "no")]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
puts " Security Provider: %s" % [choria.security_provider]
|
|
121
|
+
puts " Certname: %s" % [choria.certname]
|
|
122
|
+
puts " SSL Directory: %s (%s)" % [choria.ssl_dir, File.exist?(choria.ssl_dir) ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
|
123
|
+
puts " Client Public Cert: %s (%s)" % [choria.client_public_cert, choria.has_client_public_cert? ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
|
124
|
+
puts " Client Private Key: %s (%s)" % [choria.client_private_key, choria.has_client_private_key? ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
|
125
|
+
puts " CA Path: %s (%s)" % [choria.ca_path, choria.has_ca? ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
|
126
|
+
puts " CSR Path: %s (%s)" % [choria.csr_path, choria.has_csr? ? Util.colorize(:green, "found") : Util.colorize(:red, "absent")]
|
|
127
|
+
|
|
128
|
+
if choria.has_client_public_cert?
|
|
129
|
+
cn = choria.valid_certificate?(File.read(choria.client_public_cert), choria.certname, false)
|
|
130
|
+
|
|
131
|
+
puts " Public Cert CN: %s (%s)" % [cn, cn == choria.certname ? Util.colorize(:green, "match") : Util.colorize(:red, "does not match certname")]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
if choria.credential_file?
|
|
135
|
+
puts " NATS Credentials: %s (%s)" % [
|
|
136
|
+
choria.credential_file,
|
|
137
|
+
File.exist?(choria.credential_file) ? Util.colorize(:green, "exit") : Util.colorize(:red, "does not exist")
|
|
138
|
+
]
|
|
139
|
+
puts " 'nkeys' gem: %s" % choria.nkeys?
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
puts
|
|
143
|
+
|
|
144
|
+
puts "Active Choria configuration settings as found in configuration files:"
|
|
145
|
+
puts
|
|
146
|
+
|
|
147
|
+
choria_settings = Config.instance.pluginconf.select {|k, _| k.start_with?("choria")}
|
|
148
|
+
padding = choria_settings.empty? ? 2 : choria_settings.keys.map(&:length).max + 2
|
|
149
|
+
|
|
150
|
+
if choria_settings.empty?
|
|
151
|
+
puts " No custom Choria settings found in your configuration files"
|
|
152
|
+
else
|
|
153
|
+
choria_settings.each do |k, v|
|
|
154
|
+
puts "%#{padding}s: %s" % [k, v]
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
puts
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Creates and cache a Choria helper class
|
|
162
|
+
#
|
|
163
|
+
# @return [Util::Choria]
|
|
164
|
+
def choria
|
|
165
|
+
@_choria ||= Util::Choria.new(false)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# List of valid commands this application respond to
|
|
169
|
+
#
|
|
170
|
+
# @return [Array<String>] like `plan` and `run`
|
|
171
|
+
def valid_commands
|
|
172
|
+
methods.grep(/_command$/).map {|c| c.to_s.gsub("_command", "")}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Asks the user to confirm something on the CLI
|
|
176
|
+
#
|
|
177
|
+
# @note exits the application on no
|
|
178
|
+
# @param msg [String] the message to ask
|
|
179
|
+
# @return [void]
|
|
180
|
+
def confirm(msg)
|
|
181
|
+
print("%s (y/n) " % msg)
|
|
182
|
+
|
|
183
|
+
$stdout.flush
|
|
184
|
+
|
|
185
|
+
exit(1) unless $stdin.gets.strip.match?(/^(?:y|yes)$/i)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
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,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)
|
|
@@ -18,15 +18,15 @@ class MCollective::Application::Facts<MCollective::Application
|
|
|
18
18
|
facts.keys.sort.each do |k|
|
|
19
19
|
printf(" %-#{field_size}s found %d times\n", k, facts[k].size)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
puts
|
|
21
|
+
next unless verbose
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
puts(" #{f}")
|
|
26
|
-
end
|
|
23
|
+
puts
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
facts[k].sort.each do |f|
|
|
26
|
+
puts(" #{f}")
|
|
29
27
|
end
|
|
28
|
+
|
|
29
|
+
puts
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -50,11 +50,11 @@ class MCollective::Application::Facts<MCollective::Application
|
|
|
50
50
|
if facts.include?(value)
|
|
51
51
|
facts[value] << resp[:senderid]
|
|
52
52
|
else
|
|
53
|
-
facts[value] = [
|
|
53
|
+
facts[value] = [resp[:senderid]]
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
|
-
rescue Exception => e
|
|
57
|
-
|
|
56
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
57
|
+
warn "Could not parse facts for #{resp[:senderid]}: #{e.class}: #{e}"
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
@@ -0,0 +1,237 @@
|
|
|
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
|
+
abort("A certificate is needed from the Puppet CA for `%s`, please use the `choria enroll` command" % choria.certname) unless choria.has_client_public_cert?
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def main
|
|
224
|
+
send("%s_command" % configuration[:command])
|
|
225
|
+
rescue Interrupt
|
|
226
|
+
exit
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# List of valid commands this application respond to
|
|
230
|
+
#
|
|
231
|
+
# @return [Array<String>] like `plan` and `run`
|
|
232
|
+
def valid_commands
|
|
233
|
+
methods.grep(/_command$/).map {|c| c.to_s.gsub("_command", "")}
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|