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.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mcollective.rb +1 -2
  3. data/lib/mcollective/agent/bolt_tasks.ddl +253 -0
  4. data/lib/mcollective/agent/bolt_tasks.json +365 -0
  5. data/lib/mcollective/agent/bolt_tasks.rb +178 -0
  6. data/lib/mcollective/agent/choria_util.ddl +152 -0
  7. data/lib/mcollective/agent/choria_util.json +244 -0
  8. data/lib/mcollective/agent/rpcutil.ddl +8 -4
  9. data/lib/mcollective/agent/rpcutil.json +333 -0
  10. data/lib/mcollective/agent/scout.ddl +169 -0
  11. data/lib/mcollective/agent/scout.json +224 -0
  12. data/lib/mcollective/agents.rb +7 -6
  13. data/lib/mcollective/aggregate.rb +4 -4
  14. data/lib/mcollective/aggregate/average.rb +2 -2
  15. data/lib/mcollective/aggregate/base.rb +2 -2
  16. data/lib/mcollective/aggregate/result.rb +3 -3
  17. data/lib/mcollective/aggregate/result/collection_result.rb +2 -2
  18. data/lib/mcollective/aggregate/result/numeric_result.rb +2 -2
  19. data/lib/mcollective/aggregate/sum.rb +2 -2
  20. data/lib/mcollective/aggregate/summary.rb +3 -4
  21. data/lib/mcollective/application.rb +57 -21
  22. data/lib/mcollective/application/choria.rb +189 -0
  23. data/lib/mcollective/application/completion.rb +6 -6
  24. data/lib/mcollective/application/facts.rb +11 -11
  25. data/lib/mcollective/application/federation.rb +237 -0
  26. data/lib/mcollective/application/find.rb +4 -4
  27. data/lib/mcollective/application/help.rb +3 -3
  28. data/lib/mcollective/application/inventory.rb +3 -341
  29. data/lib/mcollective/application/ping.rb +5 -51
  30. data/lib/mcollective/application/playbook.rb +207 -0
  31. data/lib/mcollective/application/plugin.rb +106 -106
  32. data/lib/mcollective/application/rpc.rb +3 -108
  33. data/lib/mcollective/application/tasks.rb +425 -0
  34. data/lib/mcollective/applications.rb +11 -10
  35. data/lib/mcollective/audit/choria.rb +33 -0
  36. data/lib/mcollective/cache.rb +2 -4
  37. data/lib/mcollective/client.rb +11 -10
  38. data/lib/mcollective/config.rb +21 -34
  39. data/lib/mcollective/connector/base.rb +2 -1
  40. data/lib/mcollective/connector/nats.ddl +9 -0
  41. data/lib/mcollective/connector/nats.rb +450 -0
  42. data/lib/mcollective/data.rb +8 -3
  43. data/lib/mcollective/data/agent_data.rb +1 -1
  44. data/lib/mcollective/data/base.rb +6 -5
  45. data/lib/mcollective/data/bolt_task_data.ddl +90 -0
  46. data/lib/mcollective/data/bolt_task_data.rb +32 -0
  47. data/lib/mcollective/data/collective_data.rb +1 -1
  48. data/lib/mcollective/data/fact_data.rb +6 -6
  49. data/lib/mcollective/data/fstat_data.rb +2 -4
  50. data/lib/mcollective/data/result.rb +7 -2
  51. data/lib/mcollective/ddl/agentddl.rb +5 -17
  52. data/lib/mcollective/ddl/base.rb +10 -13
  53. data/lib/mcollective/discovery.rb +24 -39
  54. data/lib/mcollective/discovery/choria.ddl +11 -0
  55. data/lib/mcollective/discovery/choria.rb +223 -0
  56. data/lib/mcollective/discovery/flatfile.rb +7 -8
  57. data/lib/mcollective/discovery/mc.rb +2 -2
  58. data/lib/mcollective/discovery/stdin.rb +17 -18
  59. data/lib/mcollective/exceptions.rb +13 -0
  60. data/lib/mcollective/facts/base.rb +9 -9
  61. data/lib/mcollective/facts/yaml_facts.rb +12 -12
  62. data/lib/mcollective/generators.rb +3 -3
  63. data/lib/mcollective/generators/agent_generator.rb +3 -4
  64. data/lib/mcollective/generators/base.rb +14 -15
  65. data/lib/mcollective/generators/data_generator.rb +5 -6
  66. data/lib/mcollective/log.rb +2 -2
  67. data/lib/mcollective/logger/base.rb +3 -2
  68. data/lib/mcollective/logger/console_logger.rb +10 -10
  69. data/lib/mcollective/logger/file_logger.rb +7 -7
  70. data/lib/mcollective/logger/syslog_logger.rb +11 -15
  71. data/lib/mcollective/message.rb +8 -39
  72. data/lib/mcollective/monkey_patches.rb +2 -4
  73. data/lib/mcollective/optionparser.rb +2 -1
  74. data/lib/mcollective/pluginmanager.rb +3 -5
  75. data/lib/mcollective/pluginpackager.rb +1 -3
  76. data/lib/mcollective/pluginpackager/agent_definition.rb +3 -8
  77. data/lib/mcollective/pluginpackager/forge_packager.rb +7 -9
  78. data/lib/mcollective/pluginpackager/standard_definition.rb +1 -2
  79. data/lib/mcollective/registration/base.rb +18 -16
  80. data/lib/mcollective/rpc.rb +2 -4
  81. data/lib/mcollective/rpc/actionrunner.rb +16 -18
  82. data/lib/mcollective/rpc/agent.rb +26 -43
  83. data/lib/mcollective/rpc/audit.rb +1 -0
  84. data/lib/mcollective/rpc/client.rb +67 -85
  85. data/lib/mcollective/rpc/helpers.rb +55 -62
  86. data/lib/mcollective/rpc/progress.rb +2 -2
  87. data/lib/mcollective/rpc/reply.rb +17 -19
  88. data/lib/mcollective/rpc/request.rb +7 -5
  89. data/lib/mcollective/rpc/result.rb +6 -8
  90. data/lib/mcollective/rpc/stats.rb +49 -58
  91. data/lib/mcollective/security/base.rb +13 -56
  92. data/lib/mcollective/security/choria.rb +765 -0
  93. data/lib/mcollective/shell.rb +9 -4
  94. data/lib/mcollective/signer/base.rb +28 -0
  95. data/lib/mcollective/signer/choria.rb +185 -0
  96. data/lib/mcollective/ssl.rb +8 -6
  97. data/lib/mcollective/util.rb +58 -55
  98. data/lib/mcollective/util/bolt_support.rb +176 -0
  99. data/lib/mcollective/util/bolt_support/plan_runner.rb +167 -0
  100. data/lib/mcollective/util/bolt_support/task_result.rb +94 -0
  101. data/lib/mcollective/util/bolt_support/task_results.rb +128 -0
  102. data/lib/mcollective/util/choria.rb +946 -0
  103. data/lib/mcollective/util/indifferent_hash.rb +12 -0
  104. data/lib/mcollective/util/natswrapper.rb +242 -0
  105. data/lib/mcollective/util/playbook.rb +435 -0
  106. data/lib/mcollective/util/playbook/data_stores.rb +201 -0
  107. data/lib/mcollective/util/playbook/data_stores/base.rb +99 -0
  108. data/lib/mcollective/util/playbook/data_stores/consul_data_store.rb +88 -0
  109. data/lib/mcollective/util/playbook/data_stores/environment_data_store.rb +33 -0
  110. data/lib/mcollective/util/playbook/data_stores/etcd_data_store.rb +42 -0
  111. data/lib/mcollective/util/playbook/data_stores/file_data_store.rb +106 -0
  112. data/lib/mcollective/util/playbook/data_stores/shell_data_store.rb +103 -0
  113. data/lib/mcollective/util/playbook/inputs.rb +265 -0
  114. data/lib/mcollective/util/playbook/nodes.rb +207 -0
  115. data/lib/mcollective/util/playbook/nodes/mcollective_nodes.rb +86 -0
  116. data/lib/mcollective/util/playbook/nodes/pql_nodes.rb +40 -0
  117. data/lib/mcollective/util/playbook/nodes/shell_nodes.rb +55 -0
  118. data/lib/mcollective/util/playbook/nodes/terraform_nodes.rb +65 -0
  119. data/lib/mcollective/util/playbook/nodes/yaml_nodes.rb +47 -0
  120. data/lib/mcollective/util/playbook/playbook_logger.rb +47 -0
  121. data/lib/mcollective/util/playbook/puppet_logger.rb +51 -0
  122. data/lib/mcollective/util/playbook/report.rb +152 -0
  123. data/lib/mcollective/util/playbook/task_result.rb +55 -0
  124. data/lib/mcollective/util/playbook/tasks.rb +196 -0
  125. data/lib/mcollective/util/playbook/tasks/base.rb +45 -0
  126. data/lib/mcollective/util/playbook/tasks/graphite_event_task.rb +64 -0
  127. data/lib/mcollective/util/playbook/tasks/mcollective_task.rb +356 -0
  128. data/lib/mcollective/util/playbook/tasks/shell_task.rb +93 -0
  129. data/lib/mcollective/util/playbook/tasks/slack_task.rb +105 -0
  130. data/lib/mcollective/util/playbook/tasks/webhook_task.rb +136 -0
  131. data/lib/mcollective/util/playbook/template_util.rb +98 -0
  132. data/lib/mcollective/util/playbook/uses.rb +169 -0
  133. data/lib/mcollective/util/tasks_support.rb +751 -0
  134. data/lib/mcollective/util/tasks_support/cli.rb +260 -0
  135. data/lib/mcollective/util/tasks_support/default_formatter.rb +138 -0
  136. data/lib/mcollective/util/tasks_support/json_formatter.rb +108 -0
  137. data/lib/mcollective/validator.rb +6 -1
  138. data/lib/mcollective/validator/bolt_task_name_validator.ddl +7 -0
  139. data/lib/mcollective/validator/bolt_task_name_validator.rb +11 -0
  140. data/lib/mcollective/validator/length_validator.rb +1 -3
  141. metadata +65 -6
  142. data/lib/mcollective/application/describe_filter.rb +0 -87
  143. data/lib/mcollective/matcher.rb +0 -220
  144. data/lib/mcollective/matcher/parser.rb +0 -128
  145. 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" % [ agent, ddl.meta[:description] ]
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{|k| k.to_s}.grep(/^list_/)
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 if ARGV.size > 0
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
- if verbose
22
- puts
21
+ next unless verbose
23
22
 
24
- facts[k].sort.each do |f|
25
- puts(" #{f}")
26
- end
23
+ puts
27
24
 
28
- puts
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] = [ resp[:senderid] ]
53
+ facts[value] = [resp[:senderid]]
54
54
  end
55
55
  end
56
- rescue Exception => e
57
- STDERR.puts "Could not parse facts for #{resp[:senderid]}: #{e.class}: #{e}"
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