choria-mcorpc-support 2.22.0 → 2.23.2

Sign up to get free protection for your applications and to get access to all the features.
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 +73 -82
  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
@@ -1,111 +1,6 @@
1
- class MCollective::Application::Rpc<MCollective::Application
1
+ class MCollective::Application::Rpc < MCollective::Application # rubocop:disable Style/ClassAndModuleChildren
2
2
  description "Generic RPC agent client application"
3
3
 
4
- usage "mco rpc [options] [filters] --agent <agent> --action <action> [--argument <key=val> --argument ...]"
5
- usage "mco rpc [options] [filters] <agent> <action> [<key=val> <key=val> ...]"
6
-
7
- option :show_results,
8
- :description => "Do not process results, just send request",
9
- :arguments => ["--no-results", "--nr"],
10
- :default => true,
11
- :type => :bool
12
-
13
- option :agent,
14
- :description => "Agent to call",
15
- :arguments => ["-a", "--agent AGENT"]
16
-
17
- option :action,
18
- :description => "Action to call",
19
- :arguments => ["--action ACTION"]
20
-
21
- option :arguments,
22
- :description => "Arguments to pass to agent",
23
- :arguments => ["--arg", "--argument ARGUMENT"],
24
- :type => :array,
25
- :default => [],
26
- :validate => Proc.new {|val| val.match(/^(.+?)=(.+)$/) ? true : "Could not parse --arg #{val} should be of the form key=val" }
27
-
28
- def post_option_parser(configuration)
29
- # handle the alternative format that optparse cant parse
30
- unless (configuration.include?(:agent) && configuration.include?(:action))
31
- if ARGV.length >= 2
32
- configuration[:agent] = ARGV[0]
33
- ARGV.delete_at(0)
34
-
35
- configuration[:action] = ARGV[0]
36
- ARGV.delete_at(0)
37
-
38
- ARGV.each do |v|
39
- if v =~ /^(.+?)=(.+)$/
40
- configuration[:arguments] = [] unless configuration.include?(:arguments)
41
- configuration[:arguments] << v
42
- else
43
- STDERR.puts("Could not parse --arg #{v}")
44
- exit(1)
45
- end
46
- end
47
- else
48
- STDERR.puts("No agent, action and arguments specified")
49
- exit(1)
50
- end
51
- end
52
-
53
- # convert arguments to symbols for keys to comply with simplerpc conventions
54
- args = configuration[:arguments].clone
55
- configuration[:arguments] = {}
56
-
57
- args.each do |v|
58
- if v =~ /^(.+?)=(.+)$/
59
- configuration[:arguments][$1.to_sym] = $2
60
- end
61
- end
62
- end
63
-
64
- def string_to_ddl_type(arguments, ddl)
65
- return if ddl.empty?
66
-
67
- arguments.keys.each do |key|
68
- if ddl[:input].keys.include?(key)
69
- case ddl[:input][key][:type]
70
- when :boolean
71
- arguments[key] = MCollective::DDL.string_to_boolean(arguments[key])
72
-
73
- when :number, :integer, :float
74
- arguments[key] = MCollective::DDL.string_to_number(arguments[key])
75
- end
76
- end
77
- end
78
- end
79
-
80
- def main
81
- mc = rpcclient(configuration[:agent])
82
-
83
- mc.agent_filter(configuration[:agent])
84
-
85
- string_to_ddl_type(configuration[:arguments], mc.ddl.action_interface(configuration[:action])) if mc.ddl
86
-
87
- mc.validate_request(configuration[:action], configuration[:arguments])
88
-
89
- if mc.reply_to
90
- configuration[:arguments][:process_results] = true
91
-
92
- puts "Request sent with id: " + mc.send(configuration[:action], configuration[:arguments]) + " replies to #{mc.reply_to}"
93
- elsif !configuration[:show_results]
94
- configuration[:arguments][:process_results] = false
95
-
96
- puts "Request sent with id: " + mc.send(configuration[:action], configuration[:arguments])
97
- else
98
- discover_args = {:verbose => true}
99
-
100
- mc.detect_and_set_stdin_discovery
101
-
102
- mc.discover discover_args
103
-
104
- printrpc mc.send(configuration[:action], configuration[:arguments])
105
-
106
- printrpcstats :summarize => true, :caption => "#{configuration[:agent]}##{configuration[:action]} call stats" if mc.discover.size > 0
107
-
108
- halt mc.stats
109
- end
110
- end
4
+ external(:command => "choria", :args => ["req"])
5
+ external_help(:command => "choria", :args => ["req", "--help"])
111
6
  end
@@ -0,0 +1,425 @@
1
+ module MCollective
2
+ class Application
3
+ class Tasks < Application
4
+ description "Puppet Task Orchestrator"
5
+
6
+ usage <<-USAGE
7
+
8
+ mco tasks [--detail]
9
+ mco tasks <TASK NAME>
10
+ mco tasks run <TASK NAME> [OPTIONS]
11
+ mco tasks status <REQUEST> [FLAGS]
12
+
13
+ The Task Orchestrator is designed to provide a consistent
14
+ management environment for Puppet Tasks.
15
+
16
+ It will download tasks from your Puppet Server onto all nodes
17
+ and after verifying they were able to correctly download the
18
+ same task across the entire fleet will run the task.
19
+
20
+ Tasks are run in the background, the CLI can wait for up to 60
21
+ seconds for your task to complete and show the status or you
22
+ can use the status comment to review a completed task later.
23
+ USAGE
24
+
25
+ exclude_argument_sections "rpc"
26
+
27
+ def post_option_parser(configuration)
28
+ configuration[:__command] = ARGV.shift || "list"
29
+ end
30
+
31
+ def list_options
32
+ self.class.option :__detail,
33
+ :arguments => ["--detail"],
34
+ :description => "Show command descriptions",
35
+ :default => false,
36
+ :type => :boolean
37
+ end
38
+
39
+ def status_options
40
+ application_options[:usage].clear
41
+
42
+ self.class.usage <<-USAGE
43
+
44
+ mco tasks status <REQUEST> [FLAGS]
45
+
46
+ Retrieves the status for a task you previously requested. It can be running or completed.
47
+
48
+ By default only failed exuecutions are shown, use --verbose to see them all.
49
+
50
+ USAGE
51
+
52
+ self.class.option :__summary,
53
+ :arguments => ["--summary"],
54
+ :description => "Only show a overall summary of the task",
55
+ :default => false,
56
+ :type => :boolean
57
+
58
+ self.class.option :__metadata,
59
+ :arguments => ["--metadata"],
60
+ :description => "Only show task metadata for each node",
61
+ :default => false,
62
+ :type => :boolean
63
+
64
+ self.class.option :__json_format,
65
+ :arguments => ["--json"],
66
+ :description => "Display results in JSON format",
67
+ :default => false,
68
+ :type => :boolean
69
+ end
70
+
71
+ def run_options # rubocop:disable Metrics/MethodLength
72
+ application_options[:usage].clear
73
+
74
+ self.class.usage <<-USAGE
75
+
76
+ mco tasks run <TASK NAME> [OPTIONS]
77
+
78
+ Runs a task in the background and wait up to 50 seconds for it to complete.
79
+
80
+ Task inputs are handled using --argument=value for basic String, Numeric and Boolean
81
+ types, others can be passed using --input
82
+
83
+ Input can also be read from a file using "--input @file.json" or "--input @file.yaml".
84
+
85
+ For complex data types like Hashes, Arrays or Variants you have to supply input
86
+ as YAML or JSON.
87
+
88
+ Once a task is run the task ID will be displayed which can later be used with
89
+ the "mco tasks status" command to extract results.
90
+
91
+ Examples:
92
+
93
+ Run myapp::upgrade task in the background and wait for it to complete:
94
+
95
+ mco tasks run myapp::upgrade --version 1.0.0
96
+
97
+ Run myapp::upgrade task in the background and return immediately:
98
+
99
+ mco tasks run myapp::upgrade --version 1.0.0 --background
100
+
101
+ Supply complex data input to the task:
102
+
103
+ Should input be given on both the CLI arguments and a file
104
+ the CLI arguments will override the file
105
+
106
+ mco tasks run myapp::upgrade --input @input.json
107
+ mco tasks run myapp::upgrade --input @input.yaml
108
+ mco tasks run myapp::upgrade --version 1.0.0 --input \\
109
+ '{"source": {
110
+ "url": "http://repo/archive-1.0.0.tgz",
111
+ "hash": "68b329da9893e34099c7d8ad5cb9c940"}}'
112
+
113
+ USAGE
114
+
115
+ task = ARGV[1]
116
+
117
+ abort("Please specify a task to run") unless task
118
+
119
+ cli.create_task_options(task, "production", self)
120
+
121
+ self.class.option :__summary,
122
+ :arguments => ["--summary"],
123
+ :description => "Only show a overall summary of the task",
124
+ :default => false,
125
+ :type => :boolean
126
+
127
+ self.class.option :__background,
128
+ :arguments => ["--background"],
129
+ :description => "Do not wait for the task to complete",
130
+ :default => false,
131
+ :type => :boolean
132
+
133
+ self.class.option :__json_input,
134
+ :arguments => ["--input INPUT"],
135
+ :description => "JSON input to pass to the task",
136
+ :required => false,
137
+ :type => String
138
+
139
+ self.class.option :__batch_size,
140
+ :arguments => ["--batch SIZE"],
141
+ :description => "Run tasks on nodes in batches",
142
+ :required => false,
143
+ :type => String
144
+
145
+ self.class.option :__batch_sleep,
146
+ :arguments => ["--batch-sleep SECONDS"],
147
+ :description => "Time to sleep between invocations of batches of nodes",
148
+ :required => false,
149
+ :default => 1,
150
+ :type => Integer
151
+
152
+ self.class.option :__run_as,
153
+ :arguments => ["--run-as USERNAME"],
154
+ :description => "Run task as user USERNAME",
155
+ :required => false,
156
+ :default => nil,
157
+ :type => String
158
+ end
159
+
160
+ def say(msg="")
161
+ puts(msg) unless configuration[:__json_format]
162
+ end
163
+
164
+ def run_command
165
+ task = ARGV.shift
166
+
167
+ input = cli.task_input(configuration)
168
+
169
+ say("Retrieving task metadata for task %s from the Puppet Server" % task)
170
+
171
+ begin
172
+ meta = cli.task_metadata(task, "production")
173
+ rescue
174
+ abort($!.to_s)
175
+ end
176
+
177
+ cli.transform_hash_strings(meta, input)
178
+ cli.validate_task_input(task, meta, input)
179
+
180
+ say("Attempting to download and run task %s on %d nodes" % [Util.colorize(:bold, task), bolt_tasks.discover.size])
181
+ say
182
+
183
+ download_files(task, meta["files"])
184
+
185
+ request = {
186
+ :task => task,
187
+ :files => meta["files"].to_json
188
+ }
189
+
190
+ request[:run_as] = configuration[:__run_as] if configuration[:__run_as]
191
+
192
+ request[:input] = input.to_json if input
193
+
194
+ if configuration[:__background]
195
+ puts("Starting task %s in the background" % [Util.colorize(:bold, task)])
196
+
197
+ if configuration[:__batch_size]
198
+ bolt_tasks.batch_size = configuration[:__batch_size]
199
+ bolt_tasks.batch_sleep_time = configuration[:__batch_sleep]
200
+ bolt_tasks.progress = true
201
+ end
202
+
203
+ printrpc bolt_tasks.run_no_wait(request)
204
+ printrpcstats
205
+
206
+ if bolt_tasks.stats.okcount > 0
207
+ puts
208
+ puts("Request detailed status for the task using 'mco tasks status %s'" % [Util.colorize(:bold, bolt_tasks.stats.requestid)])
209
+ end
210
+ else
211
+ say("Running task %s and waiting up to %s seconds for it to complete" % [
212
+ Util.colorize(:bold, task),
213
+ Util.colorize(:bold, bolt_tasks.ddl.meta[:timeout])
214
+ ])
215
+
216
+ request_and_report(:run_and_wait, request)
217
+ end
218
+ ensure
219
+ reset_client!
220
+ end
221
+
222
+ def download_files(task, files)
223
+ bolt_tasks.batch_size = 50
224
+ bolt_tasks.batch_sleep_time = 1
225
+
226
+ failed = false
227
+
228
+ downloads = []
229
+ cnt = bolt_tasks.discover.size
230
+ idx = 0
231
+
232
+ bolt_tasks.download(:environment => "production", :task => task, :files => files.to_json) do |_, s|
233
+ unless configuration[:__json_format]
234
+ print(cli.twirl("Downloading and verifying %d file(s) from the Puppet Server to all nodes:" % [files.size], cnt, idx + 1))
235
+ puts if cnt == idx + 1
236
+ end
237
+
238
+ idx += 1
239
+ downloads << s
240
+ end
241
+
242
+ downloads.select {|d| d[:statuscode] > 0}.each_with_index do |download, i|
243
+ failed = true
244
+ puts if i == 0
245
+ puts(" %s: %s" % [Util.colorize(:red, "Could not download files onto %s" % download[:sender]), download[:statusmsg]])
246
+ end
247
+
248
+ unless bolt_tasks.stats.noresponsefrom.empty?
249
+ puts
250
+ puts bolt_tasks.stats.no_response_report
251
+ failed = true
252
+ end
253
+
254
+ if failed
255
+ puts
256
+ abort("Could not download the task %s onto all nodes" % task)
257
+ end
258
+ end
259
+
260
+ def status_command
261
+ taskid = ARGV.shift
262
+
263
+ abort("Please specify a task id to display") unless taskid
264
+
265
+ if configuration[:__metadata]
266
+ say("Requesting task metadata for request %s" % Util.colorize(:bold, taskid)) unless options[:verbose]
267
+
268
+ bolt_tasks.task_status(:task_id => taskid).each do |status|
269
+ cli.print_result_metadata(status)
270
+ end
271
+
272
+ cli.print_rpc_stats(bolt_tasks.stats)
273
+ else
274
+ say("Requesting task status for request %s, showing failures only pass --verbose for all output" % Util.colorize(:bold, taskid)) unless options[:verbose]
275
+
276
+ request_and_report(:task_status, {:task_id => taskid}, taskid)
277
+ end
278
+ end
279
+
280
+ def request_and_report(action, arguments, taskid=nil) # rubocop:disable Metrics/MethodLength
281
+ task_not_known_nodes = 0
282
+ wrapper_failure = 0
283
+ completed_nodes = 0
284
+ running_nodes = 0
285
+ runtime = 0.0
286
+ success_nodes = 0
287
+ fail_nodes = 0
288
+ progress = configuration[:__summary] || configuration[:__batch_size] ? RPC::Progress.new : nil
289
+ cnt = 0
290
+ expected = bolt_tasks.discover.size
291
+ task_names = []
292
+ callers = []
293
+
294
+ if configuration[:__batch_size]
295
+ bolt_tasks.batch_size = configuration[:__batch_size]
296
+ bolt_tasks.batch_sleep_time = configuration[:__batch_sleep]
297
+ end
298
+
299
+ say
300
+
301
+ bolt_tasks.send(action, arguments) do |_, reply|
302
+ status = reply[:data]
303
+
304
+ if reply[:statuscode] == 3
305
+ fail_nodes += 1
306
+ task_not_known_nodes += 1
307
+ elsif [-1, 0].include?(status[:exitcode])
308
+ status[:completed] ? completed_nodes += 1 : running_nodes += 1
309
+ runtime += status[:runtime]
310
+ reply[:statuscode] == 0 ? success_nodes += 1 : fail_nodes += 1
311
+ elsif reply[:statuscode] == 5
312
+ wrapper_failure += 1
313
+ fail_nodes += 1
314
+ else
315
+ fail_nodes += 1
316
+ end
317
+
318
+ task_names << status[:task] if status[:task]
319
+ callers << status[:callerid] if status[:callerid]
320
+
321
+ if progress
322
+ print(progress.twirl(cnt + 1, expected))
323
+
324
+ say if cnt + 1 == expected
325
+ else
326
+ cli.print_result(reply)
327
+ end
328
+
329
+ cnt += 1
330
+ end
331
+
332
+ taskid ||= bolt_tasks.stats.requestid
333
+
334
+ callers.compact!
335
+ callers.uniq!
336
+ task_names.compact!
337
+ task_names.uniq!
338
+
339
+ say
340
+
341
+ cli.print_task_summary(
342
+ taskid,
343
+ task_names,
344
+ callers,
345
+ completed_nodes,
346
+ running_nodes,
347
+ task_not_known_nodes,
348
+ wrapper_failure,
349
+ success_nodes,
350
+ fail_nodes,
351
+ runtime,
352
+ bolt_tasks.stats
353
+ )
354
+ ensure
355
+ reset_client!
356
+ end
357
+
358
+ def list_command
359
+ cli.show_task_list("production", configuration[:__detail])
360
+ end
361
+
362
+ def run
363
+ command = ARGV[0]
364
+ command = "list" unless valid_commands.include?(command)
365
+
366
+ send("%s_options" % command)
367
+
368
+ super
369
+ end
370
+
371
+ def show_task_help(task)
372
+ cli.show_task_help(task, "production")
373
+ end
374
+
375
+ def bolt_tasks
376
+ @_bolt_tasks ||= rpcclient("bolt_tasks")
377
+ end
378
+
379
+ def reset_client!
380
+ bolt_tasks.batch_size = 0
381
+ bolt_tasks.progress = options[:verbose]
382
+ end
383
+
384
+ def extract_environment_from_argv
385
+ idx = ARGV.index("--environment")
386
+
387
+ return "production" unless idx
388
+
389
+ ARGV[idx + 1]
390
+ end
391
+
392
+ def valid_commands
393
+ methods.grep(/_command$/).map {|c| c.to_s.gsub("_command", "")}
394
+ end
395
+
396
+ def choria
397
+ Util.loadclass("MCollective::Util::Choria")
398
+
399
+ @_choria ||= Util::Choria.new
400
+ end
401
+
402
+ def tasks_support
403
+ @_tasks_support ||= choria.tasks_support
404
+ end
405
+
406
+ def cli
407
+ format = configuration[:__json_format] ? :json : :default
408
+
409
+ if options
410
+ @_cli ||= tasks_support.cli(format, options[:verbose])
411
+ else
412
+ tasks_support.cli(format, false)
413
+ end
414
+ end
415
+
416
+ def main
417
+ if valid_commands.include?(configuration[:__command])
418
+ send("%s_command" % configuration[:__command])
419
+ else
420
+ show_task_help(configuration[:__command])
421
+ end
422
+ end
423
+ end
424
+ end
425
+ end