choria-mcorpc-support 2.22.1 → 2.23.3
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 -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 +3 -68
- 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 -26
- 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 +73 -82
- 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 +752 -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,71 +1,6 @@
|
|
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
|
-
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def validate_configuration(configuration)
|
9
|
-
raise "Please specify a fact to report for" unless configuration.include?(:fact)
|
10
|
-
end
|
11
|
-
|
12
|
-
def show_single_fact_report(fact, facts, verbose=false)
|
13
|
-
puts("Report for fact: #{fact}\n\n")
|
14
|
-
|
15
|
-
facts = stringify_facts_hash(facts)
|
16
|
-
|
17
|
-
field_size = MCollective::Util.field_size(facts.keys)
|
18
|
-
facts.keys.sort.each do |k|
|
19
|
-
printf(" %-#{field_size}s found %d times\n", k, facts[k].size)
|
20
|
-
|
21
|
-
if verbose
|
22
|
-
puts
|
23
|
-
|
24
|
-
facts[k].sort.each do |f|
|
25
|
-
puts(" #{f}")
|
26
|
-
end
|
27
|
-
|
28
|
-
puts
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
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
|
-
|
39
|
-
def main
|
40
|
-
rpcutil = rpcclient("rpcutil")
|
41
|
-
rpcutil.progress = false
|
42
|
-
|
43
|
-
facts = {}
|
44
|
-
|
45
|
-
rpcutil.get_fact(:fact => configuration[:fact]) do |resp|
|
46
|
-
begin
|
47
|
-
value = resp[:body][:data][:value].to_s
|
48
|
-
|
49
|
-
if resp[:body][:data].include?(:value)
|
50
|
-
if facts.include?(value)
|
51
|
-
facts[value] << resp[:senderid]
|
52
|
-
else
|
53
|
-
facts[value] = [ resp[:senderid] ]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
rescue Exception => e
|
57
|
-
STDERR.puts "Could not parse facts for #{resp[:senderid]}: #{e.class}: #{e}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
if facts.empty?
|
62
|
-
puts "No values found for fact #{configuration[:fact]}\n"
|
63
|
-
else
|
64
|
-
show_single_fact_report(configuration[:fact], facts, options[:verbose])
|
65
|
-
end
|
66
|
-
|
67
|
-
printrpcstats
|
68
|
-
|
69
|
-
halt rpcutil.stats
|
70
|
-
end
|
4
|
+
external(:command => "choria", :args => ["facts"])
|
5
|
+
external_help(:command => "choria", :args => ["facts", "--help"])
|
71
6
|
end
|
@@ -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
|