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,260 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Util
|
|
3
|
+
class TasksSupport
|
|
4
|
+
class CLI
|
|
5
|
+
attr_reader :output
|
|
6
|
+
|
|
7
|
+
def initialize(support, format, verbose)
|
|
8
|
+
@support = support
|
|
9
|
+
|
|
10
|
+
if format == :json
|
|
11
|
+
require_relative "json_formatter"
|
|
12
|
+
@output = CLI::JSONFormatter.new(self, verbose)
|
|
13
|
+
else
|
|
14
|
+
require_relative "default_formatter"
|
|
15
|
+
@output = CLI::DefaultFormatter.new(self, verbose)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Shows the task list
|
|
20
|
+
#
|
|
21
|
+
# @param environment [String] the environment to query
|
|
22
|
+
# @param detail [Boolean] show task descriptions
|
|
23
|
+
# @param out [IO]
|
|
24
|
+
def show_task_list(environment, detail, out=$stdout)
|
|
25
|
+
out.puts "Known tasks in the %s environment" % environment
|
|
26
|
+
out.puts
|
|
27
|
+
|
|
28
|
+
known_tasks = task_list(environment, detail, out)
|
|
29
|
+
|
|
30
|
+
out.print("\r")
|
|
31
|
+
|
|
32
|
+
padding = known_tasks.keys.map(&:size).max + 2
|
|
33
|
+
|
|
34
|
+
if detail
|
|
35
|
+
known_tasks.each do |name, description|
|
|
36
|
+
out.puts " %-#{padding}s %s" % [name, description]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
out.puts
|
|
40
|
+
out.puts("Use mco task <TASK> to see task help")
|
|
41
|
+
else
|
|
42
|
+
known_tasks.keys.in_groups_of(3) do |tasks|
|
|
43
|
+
out.puts " %s" % tasks.compact.map {|t| "%-#{padding}s" % t }.join(" ")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
out.puts
|
|
47
|
+
out.puts("Use mco task <TASK> to see task help")
|
|
48
|
+
out.puts("Pass option --detail to see task descriptions")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Retrieves the task list
|
|
53
|
+
#
|
|
54
|
+
# @param environment [String] the environment to query
|
|
55
|
+
# @param detail [Boolean] show task descriptions
|
|
56
|
+
def task_list(environment, detail, out=$stdout)
|
|
57
|
+
tasks = {}
|
|
58
|
+
|
|
59
|
+
out.print("Retrieving tasks....")
|
|
60
|
+
|
|
61
|
+
known_tasks = @support.tasks(environment)
|
|
62
|
+
|
|
63
|
+
known_tasks.each_with_index do |task, idx|
|
|
64
|
+
description = nil
|
|
65
|
+
if detail
|
|
66
|
+
out.print(twirl("Retrieving tasks....", known_tasks.size, idx))
|
|
67
|
+
meta = task_metadata(task["name"], environment)
|
|
68
|
+
description = meta["metadata"]["description"]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
tasks[task["name"]] = description || ""
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
tasks
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Creates help for a task
|
|
78
|
+
#
|
|
79
|
+
# @param task [String] task name
|
|
80
|
+
# @param environment [String] environment to feetch task from
|
|
81
|
+
# @param out [IO]
|
|
82
|
+
def show_task_help(task, environment, out=$stdout)
|
|
83
|
+
out.puts("Retrieving task metadata for task %s from the Puppet Server" % task)
|
|
84
|
+
|
|
85
|
+
begin
|
|
86
|
+
meta = task_metadata(task, environment)
|
|
87
|
+
rescue
|
|
88
|
+
abort($!.to_s)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
out.puts
|
|
92
|
+
|
|
93
|
+
out.puts("%s - %s" % [Util.colorize(:bold, task), meta["metadata"]["description"]])
|
|
94
|
+
out.puts
|
|
95
|
+
|
|
96
|
+
if meta["metadata"]["parameters"].nil? || meta["metadata"]["parameters"].empty?
|
|
97
|
+
out.puts("The task takes no parameters or have none defined")
|
|
98
|
+
out.puts
|
|
99
|
+
else
|
|
100
|
+
out.puts("Task Parameters:")
|
|
101
|
+
|
|
102
|
+
meta["metadata"]["parameters"].sort_by {|n, _| n}.each do |name, details|
|
|
103
|
+
out.puts(" %-30s %s (%s)" % [name, details["description"], details["type"]])
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
out.puts
|
|
108
|
+
out.puts "Task Files:"
|
|
109
|
+
meta["files"].each do |file|
|
|
110
|
+
out.puts(" %-30s %s bytes" % [file["filename"], file["size_bytes"]])
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
out.puts
|
|
114
|
+
out.puts("Use 'mco tasks run %s' to run this task" % [task])
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# (see DefaultFormatter.print_task_summary)
|
|
118
|
+
def print_task_summary(*args)
|
|
119
|
+
@output.print_task_summary(*args)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# (see DefaultFormatter.print_result)
|
|
123
|
+
def print_result(*args)
|
|
124
|
+
@output.print_result(*args)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# (see DefaultFormatter.print_rpc_stats)
|
|
128
|
+
def print_rpc_stats(*args)
|
|
129
|
+
@output.print_rpc_stats(*args)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# (see DefaultFormatter.print_result_metadata)
|
|
133
|
+
def print_result_metadata(*args)
|
|
134
|
+
@output.print_result_metadata(*args)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Parses the given CLI input string and creates results based on it
|
|
138
|
+
#
|
|
139
|
+
# @param configuration [Hash] the mcollective Application configuration
|
|
140
|
+
# @return [Hash]
|
|
141
|
+
def task_input(configuration)
|
|
142
|
+
result = {}
|
|
143
|
+
|
|
144
|
+
input = configuration[:__json_input]
|
|
145
|
+
|
|
146
|
+
if input
|
|
147
|
+
if input.start_with?("@")
|
|
148
|
+
input.sub!("@", "")
|
|
149
|
+
result = JSON.parse(File.read(input)) if input.end_with?("json")
|
|
150
|
+
result = YAML.safe_load(File.read(input)) if input.end_with?("yaml")
|
|
151
|
+
else
|
|
152
|
+
result = JSON.parse(input)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
configuration.each do |item, value|
|
|
157
|
+
next if item.to_s.start_with?("__")
|
|
158
|
+
|
|
159
|
+
result[item.to_s] = value
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
result
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Validates the inputs provided on the CLI would be acceptable to the task
|
|
166
|
+
#
|
|
167
|
+
# @param task [String] task name
|
|
168
|
+
# @param meta [Hash] task metadata
|
|
169
|
+
# @param input [Hash] proposed input to pass to the task
|
|
170
|
+
# @return [Boolean]
|
|
171
|
+
# @raize [Exit] on failure
|
|
172
|
+
def validate_task_input(task, meta, input)
|
|
173
|
+
ok, reason = @support.validate_task_inputs(input, meta)
|
|
174
|
+
|
|
175
|
+
return true if ok
|
|
176
|
+
|
|
177
|
+
abort(reason)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Adds CLI options for all defined input
|
|
181
|
+
#
|
|
182
|
+
# @param meta [Hash] the task metadata
|
|
183
|
+
# @param application [Application]
|
|
184
|
+
def create_task_options(task, environment, application)
|
|
185
|
+
meta = task_metadata(task, environment)
|
|
186
|
+
|
|
187
|
+
return if meta["metadata"]["parameters"].nil? || meta["metadata"]["parameters"].empty?
|
|
188
|
+
|
|
189
|
+
meta["metadata"]["parameters"].sort_by {|n, _| n}.each do |name, details|
|
|
190
|
+
type, array, _ = @support.puppet_type_to_ruby(details["type"])
|
|
191
|
+
|
|
192
|
+
properties = {
|
|
193
|
+
:description => "%s (%s)" % [details["description"], details["type"]],
|
|
194
|
+
:arguments => ["--%s %s" % [name.downcase, name.upcase]],
|
|
195
|
+
:type => type
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
properties[:type] = :array if array
|
|
199
|
+
|
|
200
|
+
if type == Hash
|
|
201
|
+
properties[:arguments] = ["--%s JSON" % name.downcase]
|
|
202
|
+
properties[:type] = String
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
properties[:arguments] = ["--[no-]%s" % name.downcase] if type == :boolean
|
|
206
|
+
|
|
207
|
+
application.class.option(name.intern, properties)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Transform hash inputs given as json strings to hashes
|
|
212
|
+
#
|
|
213
|
+
# @param meta [Hash] task metadata
|
|
214
|
+
# @param input [Hash] proposed input to pass to the task
|
|
215
|
+
def transform_hash_strings(meta, input)
|
|
216
|
+
return unless meta["metadata"]["parameters"]
|
|
217
|
+
|
|
218
|
+
meta["metadata"]["parameters"].each do |name, details|
|
|
219
|
+
type, _, _ = @support.puppet_type_to_ruby(details["type"])
|
|
220
|
+
|
|
221
|
+
next unless type == Hash && input[name].is_a?(String)
|
|
222
|
+
|
|
223
|
+
begin
|
|
224
|
+
input[name] = JSON.parse(input[name])
|
|
225
|
+
rescue
|
|
226
|
+
raise("Could not parse input '%s' as JSON data: %s: %s" % [name, $!.class, $!.message])
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Retrieves task metadata from Puppet Server and cache it
|
|
232
|
+
#
|
|
233
|
+
# @param task [String] the task to fetch
|
|
234
|
+
# @param environment [String] Puppet environment
|
|
235
|
+
def task_metadata(task, environment)
|
|
236
|
+
@_metadata ||= {}
|
|
237
|
+
|
|
238
|
+
return @_metadata[task] if @_metadata[task]
|
|
239
|
+
|
|
240
|
+
@_metadata[task] = @support.task_metadata(task, environment)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Draw a compact CLI progress indicator
|
|
244
|
+
#
|
|
245
|
+
# @param msg [String] the message to prefix
|
|
246
|
+
# @param max [Integer] the biggest number to expect
|
|
247
|
+
# @param current [Integer] the current number
|
|
248
|
+
def twirl(msg, max, current)
|
|
249
|
+
charset = ["▖", "▘", "▝", "▗"]
|
|
250
|
+
index = current % charset.size
|
|
251
|
+
char = charset[index]
|
|
252
|
+
char = Util.colorize(:green, "✓") if max == current
|
|
253
|
+
|
|
254
|
+
format = "\r%s %s %#{@max.to_s.size}d / %d"
|
|
255
|
+
format % [msg, char, current, max]
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Util
|
|
3
|
+
class TasksSupport
|
|
4
|
+
class CLI
|
|
5
|
+
class DefaultFormatter
|
|
6
|
+
attr_reader :out
|
|
7
|
+
|
|
8
|
+
def initialize(cli, verbose=false, out=$stdout)
|
|
9
|
+
@cli = cli
|
|
10
|
+
@verbose = verbose
|
|
11
|
+
@out = out
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Prints the summary of a task over a number of machines
|
|
15
|
+
#
|
|
16
|
+
# @param taskid [String] the task id
|
|
17
|
+
# @param names [Array<String>] list of unique task names seen in the estate
|
|
18
|
+
# @param callers [Array<String>] list of unique callers seen in the estate
|
|
19
|
+
# @param completed [Integer] nodes that completed the task - success or fails
|
|
20
|
+
# @param running [Integer] nodes still running the task
|
|
21
|
+
# @param task_not_known [Integer] nodes where the task is unknown
|
|
22
|
+
# @param wrapper_failure [Integer] nodes where the wrapper executable failed to launch
|
|
23
|
+
# @param success [Integer] nodes that completed the task succesfully
|
|
24
|
+
# @param fails [Integer] nodes that did not complete the task succesfully
|
|
25
|
+
# @param runtime [Float] total run time across all nodes
|
|
26
|
+
# @param rpcstats [RPC::Stats] the stats from the RPC client that fetched the statusses
|
|
27
|
+
def print_task_summary(taskid, names, callers, completed, running, task_not_known, wrapper_failure, success, fails, runtime, rpcstats)
|
|
28
|
+
if callers.size > 1 || names.size > 1
|
|
29
|
+
out.puts
|
|
30
|
+
out.puts("%s received more than 1 task name or caller name for this task, this should not happen" % Util.colorize(:red, "WARNING"))
|
|
31
|
+
out.puts("happen in normal operations and might indicate forged requests were made or cache corruption.")
|
|
32
|
+
out.puts
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
out.puts("Summary for task %s" % [Util.colorize(:bold, taskid)])
|
|
36
|
+
out.puts
|
|
37
|
+
out.puts(" Task Name: %s" % names.join(","))
|
|
38
|
+
out.puts(" Caller: %s" % callers.join(","))
|
|
39
|
+
out.puts(" Completed: %s" % (completed > 0 ? Util.colorize(:green, completed) : Util.colorize(:yellow, completed)))
|
|
40
|
+
out.puts(" Running: %s" % (running > 0 ? Util.colorize(:yellow, running) : Util.colorize(:green, running)))
|
|
41
|
+
out.puts(" Unknown Task: %s" % Util.colorize(:red, task_not_known)) if task_not_known > 0
|
|
42
|
+
out.puts(" Wrapper Failure: %s" % Util.colorize(:red, wrapper_failure)) if wrapper_failure > 0
|
|
43
|
+
out.puts
|
|
44
|
+
out.puts(" Successful: %s" % (success > 0 ? Util.colorize(:green, success) : Util.colorize(:red, success)))
|
|
45
|
+
out.puts(" Failed: %s" % (fails > 0 ? Util.colorize(:red, fails) : fails))
|
|
46
|
+
out.puts
|
|
47
|
+
out.puts(" Average Run Time: %.2fs" % [runtime / (running + completed)])
|
|
48
|
+
|
|
49
|
+
if rpcstats.noresponsefrom.empty?
|
|
50
|
+
out.puts
|
|
51
|
+
out.puts rpcstats.no_response_report
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if running > 0
|
|
55
|
+
out.puts
|
|
56
|
+
out.puts("%s nodes are still running, use 'mco tasks status %s' to check on them later" % [Util.colorize(:bold, running), taskid])
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Prints the RPC stats for a request
|
|
61
|
+
#
|
|
62
|
+
# @param stats [RPC::Stats] request stats
|
|
63
|
+
def print_rpc_stats(stats)
|
|
64
|
+
out.puts stats.report("Task Stats", false, @verbose)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Prints an individual result
|
|
68
|
+
#
|
|
69
|
+
# @param result [RPC::Result]
|
|
70
|
+
def print_result(result)
|
|
71
|
+
status = result[:data]
|
|
72
|
+
stdout_text = status[:stdout] || ""
|
|
73
|
+
|
|
74
|
+
unless @verbose
|
|
75
|
+
begin
|
|
76
|
+
stdout_text = JSON.parse(status[:stdout])
|
|
77
|
+
stdout_text.delete("_error")
|
|
78
|
+
stdout_text = stdout_text.to_json
|
|
79
|
+
stdout_text = nil if stdout_text == "{}"
|
|
80
|
+
rescue # rubocop:disable Lint/SuppressedException
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if result[:statuscode] != 0
|
|
85
|
+
out.puts("%-40s %s" % [
|
|
86
|
+
Util.colorize(:red, result[:sender]),
|
|
87
|
+
Util.colorize(:yellow, result[:statusmsg])
|
|
88
|
+
])
|
|
89
|
+
|
|
90
|
+
out.puts(" %s" % stdout_text) if stdout_text
|
|
91
|
+
out.puts(" %s" % status[:stderr]) unless ["", nil].include?(status[:stderr])
|
|
92
|
+
out.puts
|
|
93
|
+
elsif result[:statuscode] == 0 && @verbose
|
|
94
|
+
out.puts(result[:sender])
|
|
95
|
+
out.puts(" %s" % stdout_text) if stdout_text
|
|
96
|
+
out.puts(" %s" % status[:stderr]) unless ["", nil].include?(status[:stderr])
|
|
97
|
+
out.puts
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Prints metadata for an individual result
|
|
102
|
+
#
|
|
103
|
+
# @param status [RPC::Reply] the individual task status to print
|
|
104
|
+
def print_result_metadata(status)
|
|
105
|
+
result = status.results
|
|
106
|
+
|
|
107
|
+
if [0, 1].include?(result[:statuscode])
|
|
108
|
+
if result[:data][:exitcode] == 0
|
|
109
|
+
out.puts(" %-40s %s" % [result[:sender], Util.colorize(:green, result[:data][:exitcode])])
|
|
110
|
+
else
|
|
111
|
+
out.puts(" %-40s %s" % [result[:sender], Util.colorize(:red, result[:data][:exitcode])])
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
out.puts(" %s by %s at %s" % [
|
|
115
|
+
Util.colorize(:bold, result[:data][:task]),
|
|
116
|
+
result[:data][:callerid],
|
|
117
|
+
Time.at(result[:data][:start_time]).utc.strftime("%F %T")
|
|
118
|
+
])
|
|
119
|
+
|
|
120
|
+
out.puts(" completed: %s runtime: %s stdout: %s stderr: %s" % [
|
|
121
|
+
result[:data][:completed] ? Util.colorize(:bold, "yes") : Util.colorize(:yellow, "no"),
|
|
122
|
+
Util.colorize(:bold, "%.2f" % result[:data][:runtime]),
|
|
123
|
+
result[:data][:stdout].empty? ? Util.colorize(:yellow, "no") : Util.colorize(:bold, "yes"),
|
|
124
|
+
result[:data][:stderr].empty? ? Util.colorize(:bold, "no") : Util.colorize(:red, "yes")
|
|
125
|
+
])
|
|
126
|
+
elsif result[:statuscode] == 3
|
|
127
|
+
out.puts(" %-40s %s" % [result[:sender], Util.colorize(:yellow, "Unknown Task")])
|
|
128
|
+
else
|
|
129
|
+
out.puts(" %-40s %s" % [result[:sender], Util.colorize(:yellow, result[:statusmsg])])
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
out.puts
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Util
|
|
3
|
+
class TasksSupport
|
|
4
|
+
class CLI
|
|
5
|
+
class JSONFormatter
|
|
6
|
+
attr_reader :out
|
|
7
|
+
|
|
8
|
+
def initialize(cli, verbose=false, out=$stdout)
|
|
9
|
+
@cli = cli
|
|
10
|
+
@verbose = verbose
|
|
11
|
+
@out = out
|
|
12
|
+
|
|
13
|
+
@started = false
|
|
14
|
+
@in_results = false
|
|
15
|
+
@in_stats = false
|
|
16
|
+
@first_item = true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def start
|
|
20
|
+
return if @started
|
|
21
|
+
|
|
22
|
+
@started = true
|
|
23
|
+
@in_results = true
|
|
24
|
+
|
|
25
|
+
out.puts '{"items": ['
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def end_results
|
|
29
|
+
return unless @in_results
|
|
30
|
+
|
|
31
|
+
@in_results = false
|
|
32
|
+
out.puts "],"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# (see DefaultFormatter.print_task_summary)
|
|
36
|
+
def print_task_summary(taskid, names, callers, completed, running, task_not_known, wrapper_failure, success, fails, runtime, rpcstats)
|
|
37
|
+
end_results
|
|
38
|
+
|
|
39
|
+
stats = {
|
|
40
|
+
"names" => names,
|
|
41
|
+
"callers" => callers,
|
|
42
|
+
"completed" => completed,
|
|
43
|
+
"running" => running,
|
|
44
|
+
"task_not_known" => task_not_known,
|
|
45
|
+
"wrapper_failure" => wrapper_failure,
|
|
46
|
+
"success" => success,
|
|
47
|
+
"failed" => fails,
|
|
48
|
+
"average_runtime" => runtime / (running + completed),
|
|
49
|
+
"noresponses" => rpcstats.noresponsefrom
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
summary = {
|
|
53
|
+
"nodes" => rpcstats.discovered_nodes.size,
|
|
54
|
+
"taskid" => taskid,
|
|
55
|
+
"completed" => stats["completed"] == rpcstats.discovered_nodes.size,
|
|
56
|
+
"success" => success == rpcstats.discovered_nodes.size
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
out.puts '"stats":'
|
|
60
|
+
out.puts stats.to_json
|
|
61
|
+
out.puts ","
|
|
62
|
+
out.puts '"summary":'
|
|
63
|
+
|
|
64
|
+
out.puts summary.to_json
|
|
65
|
+
out.puts "}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# (see DefaultFormatter.print_rpc_stats)
|
|
69
|
+
def print_rpc_stats(stats)
|
|
70
|
+
end_results
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# (see DefaultFormatter.print_result)
|
|
74
|
+
def print_result(result)
|
|
75
|
+
start
|
|
76
|
+
|
|
77
|
+
result = result.results
|
|
78
|
+
|
|
79
|
+
item = {
|
|
80
|
+
"host" => result[:sender]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
result[:data].each do |k, v|
|
|
84
|
+
item[k.to_s] = v
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
begin
|
|
88
|
+
item["stdout"] = JSON.parse(item["stdout"])
|
|
89
|
+
item["stdout"] = item["stdout"].delete("_output") if item["stdout"]["_output"]
|
|
90
|
+
rescue # rubocop:disable Lint/SuppressedException
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
out.puts "," unless @first_item
|
|
94
|
+
|
|
95
|
+
out.puts item.to_json
|
|
96
|
+
|
|
97
|
+
@first_item = false
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# (see DefaultFormatter.print_result_metadata)
|
|
101
|
+
def print_result_metadata(status)
|
|
102
|
+
print_result(status)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|