choria-mcorpc-support 0.0.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 +7 -0
- data/bin/mco +64 -0
- data/lib/mcollective.rb +63 -0
- data/lib/mcollective/agent.rb +5 -0
- data/lib/mcollective/agents.rb +149 -0
- data/lib/mcollective/aggregate.rb +85 -0
- data/lib/mcollective/aggregate/average.ddl +33 -0
- data/lib/mcollective/aggregate/average.rb +29 -0
- data/lib/mcollective/aggregate/base.rb +40 -0
- data/lib/mcollective/aggregate/result.rb +9 -0
- data/lib/mcollective/aggregate/result/base.rb +25 -0
- data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
- data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
- data/lib/mcollective/aggregate/sum.ddl +33 -0
- data/lib/mcollective/aggregate/sum.rb +18 -0
- data/lib/mcollective/aggregate/summary.ddl +33 -0
- data/lib/mcollective/aggregate/summary.rb +53 -0
- data/lib/mcollective/application.rb +365 -0
- data/lib/mcollective/application/completion.rb +104 -0
- data/lib/mcollective/application/describe_filter.rb +87 -0
- data/lib/mcollective/application/facts.rb +62 -0
- data/lib/mcollective/application/find.rb +23 -0
- data/lib/mcollective/application/help.rb +28 -0
- data/lib/mcollective/application/inventory.rb +344 -0
- data/lib/mcollective/application/ping.rb +82 -0
- data/lib/mcollective/application/plugin.rb +369 -0
- data/lib/mcollective/application/rpc.rb +111 -0
- data/lib/mcollective/applications.rb +134 -0
- data/lib/mcollective/cache.rb +145 -0
- data/lib/mcollective/client.rb +353 -0
- data/lib/mcollective/config.rb +245 -0
- data/lib/mcollective/connector.rb +18 -0
- data/lib/mcollective/connector/base.rb +26 -0
- data/lib/mcollective/data.rb +91 -0
- data/lib/mcollective/data/agent_data.ddl +22 -0
- data/lib/mcollective/data/agent_data.rb +17 -0
- data/lib/mcollective/data/base.rb +67 -0
- data/lib/mcollective/data/collective_data.ddl +20 -0
- data/lib/mcollective/data/collective_data.rb +9 -0
- data/lib/mcollective/data/fact_data.ddl +28 -0
- data/lib/mcollective/data/fact_data.rb +55 -0
- data/lib/mcollective/data/fstat_data.ddl +89 -0
- data/lib/mcollective/data/fstat_data.rb +56 -0
- data/lib/mcollective/data/result.rb +45 -0
- data/lib/mcollective/ddl.rb +113 -0
- data/lib/mcollective/ddl/agentddl.rb +253 -0
- data/lib/mcollective/ddl/base.rb +217 -0
- data/lib/mcollective/ddl/dataddl.rb +56 -0
- data/lib/mcollective/ddl/discoveryddl.rb +52 -0
- data/lib/mcollective/ddl/validatorddl.rb +6 -0
- data/lib/mcollective/discovery.rb +143 -0
- data/lib/mcollective/discovery/flatfile.ddl +11 -0
- data/lib/mcollective/discovery/flatfile.rb +48 -0
- data/lib/mcollective/discovery/mc.ddl +11 -0
- data/lib/mcollective/discovery/mc.rb +30 -0
- data/lib/mcollective/discovery/stdin.ddl +11 -0
- data/lib/mcollective/discovery/stdin.rb +68 -0
- data/lib/mcollective/exceptions.rb +28 -0
- data/lib/mcollective/facts.rb +39 -0
- data/lib/mcollective/facts/base.rb +100 -0
- data/lib/mcollective/facts/yaml_facts.rb +65 -0
- data/lib/mcollective/generators.rb +7 -0
- data/lib/mcollective/generators/agent_generator.rb +51 -0
- data/lib/mcollective/generators/base.rb +46 -0
- data/lib/mcollective/generators/data_generator.rb +51 -0
- data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
- data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
- data/lib/mcollective/generators/templates/ddl.erb +8 -0
- data/lib/mcollective/generators/templates/plugin.erb +7 -0
- data/lib/mcollective/log.rb +118 -0
- data/lib/mcollective/logger.rb +5 -0
- data/lib/mcollective/logger/base.rb +77 -0
- data/lib/mcollective/logger/console_logger.rb +61 -0
- data/lib/mcollective/logger/file_logger.rb +53 -0
- data/lib/mcollective/logger/syslog_logger.rb +53 -0
- data/lib/mcollective/matcher.rb +224 -0
- data/lib/mcollective/matcher/parser.rb +128 -0
- data/lib/mcollective/matcher/scanner.rb +241 -0
- data/lib/mcollective/message.rb +248 -0
- data/lib/mcollective/monkey_patches.rb +152 -0
- data/lib/mcollective/optionparser.rb +197 -0
- data/lib/mcollective/pluginmanager.rb +180 -0
- data/lib/mcollective/pluginpackager.rb +98 -0
- data/lib/mcollective/pluginpackager/agent_definition.rb +94 -0
- data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
- data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
- data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
- data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
- data/lib/mcollective/pluginpackager/standard_definition.rb +69 -0
- data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
- data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
- data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
- data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
- data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
- data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
- data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
- data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
- data/lib/mcollective/registration/base.rb +91 -0
- data/lib/mcollective/rpc.rb +182 -0
- data/lib/mcollective/rpc/actionrunner.rb +158 -0
- data/lib/mcollective/rpc/agent.rb +374 -0
- data/lib/mcollective/rpc/audit.rb +38 -0
- data/lib/mcollective/rpc/client.rb +1066 -0
- data/lib/mcollective/rpc/helpers.rb +321 -0
- data/lib/mcollective/rpc/progress.rb +63 -0
- data/lib/mcollective/rpc/reply.rb +87 -0
- data/lib/mcollective/rpc/request.rb +86 -0
- data/lib/mcollective/rpc/result.rb +90 -0
- data/lib/mcollective/rpc/stats.rb +294 -0
- data/lib/mcollective/runnerstats.rb +90 -0
- data/lib/mcollective/security.rb +26 -0
- data/lib/mcollective/security/base.rb +244 -0
- data/lib/mcollective/shell.rb +126 -0
- data/lib/mcollective/ssl.rb +285 -0
- data/lib/mcollective/util.rb +579 -0
- data/lib/mcollective/validator.rb +85 -0
- data/lib/mcollective/validator/array_validator.ddl +7 -0
- data/lib/mcollective/validator/array_validator.rb +9 -0
- data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
- data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
- data/lib/mcollective/validator/length_validator.ddl +7 -0
- data/lib/mcollective/validator/length_validator.rb +11 -0
- data/lib/mcollective/validator/regex_validator.ddl +7 -0
- data/lib/mcollective/validator/regex_validator.rb +9 -0
- data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
- data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
- data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
- data/lib/mcollective/validator/typecheck_validator.rb +28 -0
- metadata +215 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module RPC
|
|
3
|
+
# Various utilities for the RPC system
|
|
4
|
+
class Helpers
|
|
5
|
+
# Parse JSON output as produced by printrpc or puppet query
|
|
6
|
+
# and extract the "sender" / "certname" of each entry
|
|
7
|
+
#
|
|
8
|
+
# The simplist valid JSON based data would be:
|
|
9
|
+
#
|
|
10
|
+
# [
|
|
11
|
+
# {"sender" => "example.com"},
|
|
12
|
+
# {"sender" => "another.com"}
|
|
13
|
+
# ]
|
|
14
|
+
#
|
|
15
|
+
# or
|
|
16
|
+
#
|
|
17
|
+
# [
|
|
18
|
+
# {"certname" => "example.com"},
|
|
19
|
+
# {"certname" => "another.com"}
|
|
20
|
+
# ]
|
|
21
|
+
def self.extract_hosts_from_json(json)
|
|
22
|
+
hosts = JSON.parse(json)
|
|
23
|
+
|
|
24
|
+
raise "JSON hosts list is not an array" unless hosts.is_a?(Array)
|
|
25
|
+
|
|
26
|
+
hosts.map do |host|
|
|
27
|
+
raise "JSON host list is not an array of Hashes" unless host.is_a?(Hash)
|
|
28
|
+
|
|
29
|
+
unless host.include?("sender") || host.include?("certname")
|
|
30
|
+
raise "JSON host list does not have senders in it"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
host["sender"] || host["certname"]
|
|
34
|
+
end.uniq
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Given an array of something, make sure each is a string
|
|
38
|
+
# chomp off any new lines and return just the array of hosts
|
|
39
|
+
def self.extract_hosts_from_array(hosts)
|
|
40
|
+
[hosts].flatten.map do |host|
|
|
41
|
+
raise "#{host} should be a string" unless host.is_a?(String)
|
|
42
|
+
host.chomp
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns a blob of text representing the results in a standard way
|
|
47
|
+
#
|
|
48
|
+
# It tries hard to do sane things so you often
|
|
49
|
+
# should not need to write your own display functions
|
|
50
|
+
#
|
|
51
|
+
# If the agent you are getting results for has a DDL
|
|
52
|
+
# it will use the hints in there to do the right thing specifically
|
|
53
|
+
# it will look at the values of display in the DDL to choose
|
|
54
|
+
# when to show results
|
|
55
|
+
#
|
|
56
|
+
# If you do not have a DDL you can pass these flags:
|
|
57
|
+
#
|
|
58
|
+
# printrpc exim.mailq, :flatten => true
|
|
59
|
+
# printrpc exim.mailq, :verbose => true
|
|
60
|
+
#
|
|
61
|
+
# If you've asked it to flatten the result it will not print sender
|
|
62
|
+
# hostnames, it will just print the result as if it's one huge result,
|
|
63
|
+
# handy for things like showing a combined mailq.
|
|
64
|
+
def self.rpcresults(result, flags = {})
|
|
65
|
+
flags = {:verbose => false, :flatten => false, :format => :console, :force_display_mode => false}.merge(flags)
|
|
66
|
+
|
|
67
|
+
result_text = ""
|
|
68
|
+
ddl = nil
|
|
69
|
+
|
|
70
|
+
# if running in verbose mode, just use the old style print
|
|
71
|
+
# no need for all the DDL helpers obfuscating the result
|
|
72
|
+
if flags[:format] == :json
|
|
73
|
+
if STDOUT.tty?
|
|
74
|
+
result_text = JSON.pretty_generate(result)
|
|
75
|
+
else
|
|
76
|
+
result_text = result.to_json
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
if flags[:verbose]
|
|
80
|
+
result_text = old_rpcresults(result, flags)
|
|
81
|
+
else
|
|
82
|
+
[result].flatten.each do |r|
|
|
83
|
+
begin
|
|
84
|
+
ddl ||= DDL.new(r.agent).action_interface(r.action.to_s)
|
|
85
|
+
|
|
86
|
+
sender = r[:sender]
|
|
87
|
+
status = r[:statuscode]
|
|
88
|
+
message = r[:statusmsg]
|
|
89
|
+
result = r[:data]
|
|
90
|
+
|
|
91
|
+
if flags[:force_display_mode]
|
|
92
|
+
display = flags[:force_display_mode]
|
|
93
|
+
else
|
|
94
|
+
display = ddl[:display]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# appand the results only according to what the DDL says
|
|
98
|
+
case display
|
|
99
|
+
when :ok
|
|
100
|
+
if status == 0
|
|
101
|
+
result_text << text_for_result(sender, status, message, result, ddl)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
when :failed
|
|
105
|
+
if status > 0
|
|
106
|
+
result_text << text_for_result(sender, status, message, result, ddl)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
when :always
|
|
110
|
+
result_text << text_for_result(sender, status, message, result, ddl)
|
|
111
|
+
|
|
112
|
+
when :flatten
|
|
113
|
+
Log.warn("The display option :flatten is being deprecated and will be removed in the next minor release")
|
|
114
|
+
result_text << text_for_flattened_result(status, result)
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
rescue Exception => e
|
|
118
|
+
# no DDL so just do the old style print unchanged for
|
|
119
|
+
# backward compat
|
|
120
|
+
result_text = old_rpcresults(result, flags)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
result_text
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Return text representing a result
|
|
130
|
+
def self.text_for_result(sender, status, msg, result, ddl)
|
|
131
|
+
statusses = ["",
|
|
132
|
+
Util.colorize(:red, "Request Aborted"),
|
|
133
|
+
Util.colorize(:yellow, "Unknown Action"),
|
|
134
|
+
Util.colorize(:yellow, "Missing Request Data"),
|
|
135
|
+
Util.colorize(:yellow, "Invalid Request Data"),
|
|
136
|
+
Util.colorize(:red, "Unknown Request Status")]
|
|
137
|
+
|
|
138
|
+
result_text = "%-40s %s\n" % [sender, statusses[status]]
|
|
139
|
+
result_text << " %s\n" % [Util.colorize(:yellow, msg)] unless msg == "OK"
|
|
140
|
+
|
|
141
|
+
# only print good data, ignore data that results from failure
|
|
142
|
+
if status == 0
|
|
143
|
+
if result.is_a?(Hash)
|
|
144
|
+
# figure out the lengths of the display as strings, we'll use
|
|
145
|
+
# it later to correctly justify the output
|
|
146
|
+
lengths = result.keys.map do |k|
|
|
147
|
+
begin
|
|
148
|
+
ddl[:output][k][:display_as].size
|
|
149
|
+
rescue
|
|
150
|
+
k.to_s.size
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
result.keys.sort_by{|k| k}.each do |k|
|
|
155
|
+
# get all the output fields nicely lined up with a
|
|
156
|
+
# 3 space front padding
|
|
157
|
+
begin
|
|
158
|
+
display_as = ddl[:output][k][:display_as]
|
|
159
|
+
rescue
|
|
160
|
+
display_as = k.to_s
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
display_length = display_as.size
|
|
164
|
+
padding = lengths.max - display_length + 3
|
|
165
|
+
result_text << " " * padding
|
|
166
|
+
|
|
167
|
+
result_text << "#{display_as}:"
|
|
168
|
+
|
|
169
|
+
if [String, Numeric].include?(result[k].class)
|
|
170
|
+
lines = result[k].to_s.split("\n")
|
|
171
|
+
|
|
172
|
+
if lines.empty?
|
|
173
|
+
result_text << "\n"
|
|
174
|
+
else
|
|
175
|
+
lines.each_with_index do |line, i|
|
|
176
|
+
i == 0 ? padtxt = " " : padtxt = " " * (padding + display_length + 2)
|
|
177
|
+
|
|
178
|
+
result_text << "#{padtxt}#{line}\n"
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
else
|
|
182
|
+
padding = " " * (lengths.max + 5)
|
|
183
|
+
result_text << " " << result[k].pretty_inspect.split("\n").join("\n" << padding) << "\n"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
elsif status == 1
|
|
187
|
+
# for status 1 we dont want to show half baked
|
|
188
|
+
# data by default since the DDL will supply all the defaults
|
|
189
|
+
# it just doesnt look right
|
|
190
|
+
else
|
|
191
|
+
result_text << "\n\t" + result.pretty_inspect.split("\n").join("\n\t")
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
result_text << "\n"
|
|
196
|
+
result_text
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Returns text representing a flattened result of only good data
|
|
200
|
+
def self.text_for_flattened_result(status, result)
|
|
201
|
+
result_text = ""
|
|
202
|
+
|
|
203
|
+
if status <= 1
|
|
204
|
+
unless result.is_a?(String)
|
|
205
|
+
result_text << result.pretty_inspect
|
|
206
|
+
else
|
|
207
|
+
result_text << result
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Backward compatible display block for results without a DDL
|
|
213
|
+
def self.old_rpcresults(result, flags = {})
|
|
214
|
+
result_text = ""
|
|
215
|
+
|
|
216
|
+
if flags[:flatten]
|
|
217
|
+
result.each do |r|
|
|
218
|
+
if r[:statuscode] <= 1
|
|
219
|
+
data = r[:data]
|
|
220
|
+
|
|
221
|
+
unless data.is_a?(String)
|
|
222
|
+
result_text << data.pretty_inspect
|
|
223
|
+
else
|
|
224
|
+
result_text << data
|
|
225
|
+
end
|
|
226
|
+
else
|
|
227
|
+
result_text << r.pretty_inspect
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
result_text << ""
|
|
232
|
+
else
|
|
233
|
+
[result].flatten.each do |r|
|
|
234
|
+
if flags[:verbose]
|
|
235
|
+
result_text << "%-40s: %s\n" % [r[:sender], r[:statusmsg]]
|
|
236
|
+
|
|
237
|
+
if r[:statuscode] <= 1
|
|
238
|
+
r[:data].pretty_inspect.split("\n").each {|m| result_text += " #{m}"}
|
|
239
|
+
result_text << "\n\n"
|
|
240
|
+
elsif r[:statuscode] == 2
|
|
241
|
+
# dont print anything, no useful data to display
|
|
242
|
+
# past what was already shown
|
|
243
|
+
elsif r[:statuscode] == 3
|
|
244
|
+
# dont print anything, no useful data to display
|
|
245
|
+
# past what was already shown
|
|
246
|
+
elsif r[:statuscode] == 4
|
|
247
|
+
# dont print anything, no useful data to display
|
|
248
|
+
# past what was already shown
|
|
249
|
+
else
|
|
250
|
+
result_text << " #{r[:statusmsg]}"
|
|
251
|
+
end
|
|
252
|
+
else
|
|
253
|
+
unless r[:statuscode] == 0
|
|
254
|
+
result_text << "%-40s %s\n" % [r[:sender], Util.colorize(:red, r[:statusmsg])]
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
result_text << ""
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Add SimpleRPC common options
|
|
264
|
+
def self.add_simplerpc_options(parser, options)
|
|
265
|
+
parser.separator ""
|
|
266
|
+
parser.separator "RPC Options"
|
|
267
|
+
|
|
268
|
+
# add SimpleRPC specific options to all clients that use our library
|
|
269
|
+
parser.on('--np', '--no-progress', 'Do not show the progress bar') do |v|
|
|
270
|
+
options[:progress_bar] = false
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
parser.on('--one', '-1', 'Send request to only one discovered nodes') do |v|
|
|
274
|
+
options[:mcollective_limit_targets] = 1
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
parser.on('--batch SIZE', 'Do requests in batches') do |v|
|
|
278
|
+
# validate batch string. Is it x% where x > 0 or is it an integer
|
|
279
|
+
if ((v =~ /^(\d+)%$/ && Integer($1) != 0) || v =~ /^(\d+)$/)
|
|
280
|
+
options[:batch_size] = v
|
|
281
|
+
else
|
|
282
|
+
raise(::OptionParser::InvalidArgument.new(v))
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
parser.on('--batch-sleep SECONDS', Float, 'Sleep time between batches') do |v|
|
|
287
|
+
options[:batch_sleep_time] = v
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
parser.on('--limit-seed NUMBER', Integer, 'Seed value for deterministic random batching') do |v|
|
|
291
|
+
options[:limit_seed] = v
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
parser.on('--limit-nodes COUNT', '--ln', '--limit', 'Send request to only a subset of nodes, can be a percentage') do |v|
|
|
295
|
+
raise "Invalid limit specified: #{v} valid limits are /^\d+%*$/" unless v =~ /^\d+%*$/
|
|
296
|
+
|
|
297
|
+
if v =~ /^\d+$/
|
|
298
|
+
options[:mcollective_limit_targets] = v.to_i
|
|
299
|
+
else
|
|
300
|
+
options[:mcollective_limit_targets] = v
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
parser.on('--json', '-j', 'Produce JSON output') do |v|
|
|
305
|
+
options[:progress_bar] = false
|
|
306
|
+
options[:output_format] = :json
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
parser.on('--display MODE', 'Influence how results are displayed. One of ok, all or failed') do |v|
|
|
310
|
+
if v == "all"
|
|
311
|
+
options[:force_display_mode] = :always
|
|
312
|
+
else
|
|
313
|
+
options[:force_display_mode] = v.intern
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
raise "--display has to be one of 'ok', 'all' or 'failed'" unless [:ok, :failed, :always].include?(options[:force_display_mode])
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module RPC
|
|
3
|
+
# Class that shows a progress bar, currently only supports a twirling
|
|
4
|
+
# progress bar.
|
|
5
|
+
#
|
|
6
|
+
# You can specify a size for the progress bar if you want if you dont
|
|
7
|
+
# it will use the helper functions to figure out terminal dimensions
|
|
8
|
+
# and draw an appropriately sized bar
|
|
9
|
+
#
|
|
10
|
+
# p = Progress.new
|
|
11
|
+
# 100.times {|i| print p.twirl(i+1, 100) + "\r"};puts
|
|
12
|
+
#
|
|
13
|
+
# * [ ==================================================> ] 100 / 100
|
|
14
|
+
class Progress
|
|
15
|
+
def initialize(size=nil)
|
|
16
|
+
@twirl = ['|', '/', '-', "\\", '|', '/', '-', "\\"]
|
|
17
|
+
@twirldex = 0
|
|
18
|
+
|
|
19
|
+
if size
|
|
20
|
+
@size = size
|
|
21
|
+
else
|
|
22
|
+
cols = Util.terminal_dimensions[0] - 22
|
|
23
|
+
|
|
24
|
+
# Defaults back to old behavior if it
|
|
25
|
+
# couldn't figure out the size or if
|
|
26
|
+
# its more than 60 wide
|
|
27
|
+
if cols <= 0
|
|
28
|
+
@size = 0
|
|
29
|
+
elsif cols > 60
|
|
30
|
+
@size = 60
|
|
31
|
+
else
|
|
32
|
+
@size = cols
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def twirl(current, total)
|
|
38
|
+
# if the size is negative there is just not enough
|
|
39
|
+
# space on the terminal, return a simpler version
|
|
40
|
+
return "\r#{current} / #{total}" if @size == 0
|
|
41
|
+
|
|
42
|
+
if current == total
|
|
43
|
+
txt = "\r %s [ " % Util.colorize(:green, "*")
|
|
44
|
+
else
|
|
45
|
+
txt = "\r %s [ " % Util.colorize(:red, @twirl[@twirldex])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
dashes = ((current.to_f / total) * @size).round
|
|
49
|
+
|
|
50
|
+
dashes.times { txt << "=" }
|
|
51
|
+
txt << ">"
|
|
52
|
+
|
|
53
|
+
(@size - dashes).times { txt << " " }
|
|
54
|
+
|
|
55
|
+
txt << " ] #{current} / #{total}"
|
|
56
|
+
|
|
57
|
+
@twirldex == 7 ? @twirldex = 0 : @twirldex += 1
|
|
58
|
+
|
|
59
|
+
return txt
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module RPC
|
|
3
|
+
# Simple class to manage compliant replies to MCollective::RPC
|
|
4
|
+
class Reply
|
|
5
|
+
attr_accessor :statuscode, :statusmsg, :data
|
|
6
|
+
|
|
7
|
+
def initialize(action, ddl)
|
|
8
|
+
@data = {}
|
|
9
|
+
@statuscode = 0
|
|
10
|
+
@statusmsg = "OK"
|
|
11
|
+
@ddl = ddl
|
|
12
|
+
@action = action
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
initialize_data
|
|
16
|
+
rescue Exception => e
|
|
17
|
+
Log.warn("Could not pre-populate reply data from the DDL: %s: %s" % [e.class, e.to_s ])
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize_data
|
|
22
|
+
unless @ddl.actions.include?(@action)
|
|
23
|
+
raise "No action '%s' defined for agent '%s' in the DDL" % [@action, @ddl.pluginname]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
interface = @ddl.action_interface(@action)
|
|
27
|
+
|
|
28
|
+
interface[:output].keys.each do |output|
|
|
29
|
+
# must deep clone this data to avoid accidental updates of the DDL in cases where the
|
|
30
|
+
# default is for example a string and someone does << on it
|
|
31
|
+
@data[output] = Marshal.load(Marshal.dump(interface[:output][output].fetch(:default, nil)))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Helper to fill in statusmsg and code on failure
|
|
36
|
+
def fail(msg, code=1)
|
|
37
|
+
@statusmsg = msg
|
|
38
|
+
@statuscode = code
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Helper that fills in statusmsg and code but also raises an appropriate error
|
|
42
|
+
def fail!(msg, code=1)
|
|
43
|
+
@statusmsg = msg
|
|
44
|
+
@statuscode = code
|
|
45
|
+
|
|
46
|
+
case code
|
|
47
|
+
when 1
|
|
48
|
+
raise RPCAborted, msg
|
|
49
|
+
|
|
50
|
+
when 2
|
|
51
|
+
raise UnknownRPCAction, msg
|
|
52
|
+
|
|
53
|
+
when 3
|
|
54
|
+
raise MissingRPCData, msg
|
|
55
|
+
|
|
56
|
+
when 4
|
|
57
|
+
raise InvalidRPCData, msg
|
|
58
|
+
|
|
59
|
+
else
|
|
60
|
+
raise UnknownRPCError, msg
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Write to the data hash
|
|
65
|
+
def []=(key, val)
|
|
66
|
+
@data[key] = val
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Read from the data hash
|
|
70
|
+
def [](key)
|
|
71
|
+
@data[key]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def fetch(key, default)
|
|
75
|
+
@data.fetch(key, default)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns a compliant Hash of the reply that should be sent
|
|
79
|
+
# over the middleware
|
|
80
|
+
def to_hash
|
|
81
|
+
return {:statuscode => @statuscode,
|
|
82
|
+
:statusmsg => @statusmsg,
|
|
83
|
+
:data => @data}
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|