mu 5.7.2.7 → 5.7.8
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.
- data/lib/mu.rb +1 -0
- data/lib/mu/command/cmd_appid.rb +520 -512
- data/lib/mu/command/cmd_runscale.rb +604 -578
- data/rdoc/Mu/Command/Cmd_appid.html +271 -272
- data/rdoc/VERSION.html +1 -1
- data/rdoc/created.rid +4 -4
- data/rdoc/lib/mu/api/scale_rb.html +1 -1
- data/rdoc/lib/mu/command/cmd_appid_rb.html +1 -1
- data/test/data/app_id_stats.csv +1 -1
- data/test/data/app_id_status.json +50 -50
- data/test/data/scale.json +3 -3
- metadata +5 -41
@@ -4,604 +4,630 @@
|
|
4
4
|
# to specify the Mu parameters, the interfaces to use, and the pattern in which to run
|
5
5
|
require 'mu/api/scale'
|
6
6
|
class Mu
|
7
|
-
class Command
|
8
|
-
class Cmd_runscale < Command
|
9
|
-
|
10
|
-
attr_accessor :api, :params, :hosts, :addr_indexes, :offset_indexes, :peak_concurrency, :peak_throughput
|
11
|
-
|
12
|
-
# displays command-line help
|
13
|
-
# * argv = command-line arguments
|
14
|
-
def cmd_help argv
|
15
|
-
help
|
16
|
-
end
|
17
|
-
|
18
|
-
# sets up, executes, and closes a Studio Scale test
|
19
|
-
# * argv = command-line arguments , requires a scenario (-s) argument
|
20
|
-
def cmd_run_file argv
|
21
|
-
setup argv
|
22
|
-
|
23
|
-
if not @hash['scenario']
|
24
|
-
msg "scenario required"
|
25
|
-
return help
|
26
|
-
else
|
27
|
-
if @hash['scenario'].include?(".msl")
|
28
|
-
scenario = @hash['scenario']
|
29
|
-
else # TODO: eventually, xml and mus file may be supported by scale api
|
30
|
-
msg "only .msl files are currently supported"
|
31
|
-
return help
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
if not @hash['dir']
|
36
|
-
@dir = ""
|
37
|
-
path = scenario
|
38
|
-
else
|
39
|
-
@dir = @hash['dir']
|
40
|
-
path = @dir + "/" + scenario
|
41
|
-
end
|
42
|
-
|
43
|
-
if !File.exists?(path)
|
44
|
-
raise "*** Error: File #{path} does not exist"
|
45
|
-
end
|
46
|
-
|
47
|
-
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
48
|
-
@api.configure("pattern", @cmd_line_pattern)
|
49
|
-
@params = {}
|
50
|
-
@params["dir"] = @dir
|
51
|
-
@params["msl"] = scenario
|
52
|
-
@params["hosts"] = @cmd_line_hosts
|
53
|
-
run(scenario)
|
54
|
-
@api.release
|
55
|
-
end
|
56
|
-
|
57
|
-
# sets up, executes, and closes a Studio Scale test for each scenario (.msl file) found in the specified directory
|
58
|
-
# * argv = command-line arguments, requires a directory (-d) argument
|
59
|
-
# * optional -r argument for recursive directory search (default is a flat directory)
|
60
|
-
def cmd_run_dir argv
|
61
|
-
setup argv
|
62
|
-
|
63
|
-
if not @hash['dir']
|
64
|
-
return help
|
65
|
-
else
|
66
|
-
@dir = @hash['dir']
|
67
|
-
end
|
68
|
-
|
69
|
-
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
70
|
-
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
71
|
-
|
72
|
-
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
73
|
-
@api.configure("pattern", @cmd_line_pattern)
|
74
|
-
@params = {}
|
75
|
-
@params["dir"] = @dir
|
76
|
-
@params["hosts"] = @cmd_line_hosts
|
77
|
-
Dir.chdir(@params["dir"])
|
78
|
-
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
79
|
-
if @hash['recursive'].nil?
|
80
|
-
files = Dir.glob("*.msl")
|
81
|
-
else
|
82
|
-
files = Dir.glob("**/*.msl")
|
83
|
-
end
|
84
|
-
if !files.empty?
|
85
|
-
files.sort.each do | f |
|
86
|
-
run(f)
|
87
|
-
output_csv(f)
|
88
|
-
sleep 2
|
89
|
-
end
|
90
|
-
else
|
91
|
-
msg "no msl files found in #{@dir}"
|
92
|
-
end
|
93
|
-
@api.release
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
def setup argv
|
99
|
-
parse_cli argv
|
100
|
-
@params = {}
|
101
|
-
@peak_concurrency = 0
|
102
|
-
@peak_throughput = 0.0
|
103
|
-
|
104
|
-
if @hash['test']
|
105
|
-
@verify_only = true
|
106
|
-
else
|
107
|
-
@verify_only = false
|
108
|
-
end
|
109
|
-
|
110
|
-
if not @hash['testset']
|
111
|
-
@testset = ""
|
112
|
-
else
|
113
|
-
@testset = @hash['testset']
|
114
|
-
end
|
115
|
-
|
116
|
-
if not @hash['pattern']
|
117
|
-
@cmd_line_pattern = "{ \"iterations\": 1, \"intervals\": [ {\"iterations\":1, \"end\":100, \"start\":1, \"duration\":20 } ] }"
|
118
|
-
else
|
119
|
-
@cmd_line_pattern = @hash['pattern']
|
120
|
-
end
|
121
|
-
|
122
|
-
if not @hash['interfaces']
|
123
|
-
@cmd_line_hosts = "b1,b2"
|
124
|
-
else
|
125
|
-
@cmd_line_hosts = @hash['interfaces']
|
126
|
-
end
|
127
|
-
|
128
|
-
if not @hash['delay']
|
129
|
-
@delay = 0
|
130
|
-
else
|
131
|
-
@delay = @hash['delay'].to_i
|
132
|
-
end
|
133
|
-
|
134
|
-
if not @hash['no_verify']
|
135
|
-
@no_verify = false
|
136
|
-
else
|
137
|
-
@no_verify = true
|
138
|
-
end
|
139
|
-
|
140
|
-
if not @hash['vector_address_pairing']
|
141
|
-
@vector_address_pairing = false
|
142
|
-
@limit_concurrency = false
|
143
|
-
else
|
144
|
-
@vector_address_pairing = true
|
145
|
-
@limit_concurrency = true
|
146
|
-
end
|
7
|
+
class Command
|
8
|
+
class Cmd_runscale < Command
|
147
9
|
|
148
|
-
|
149
|
-
if not @hash['hold_concurrency']
|
150
|
-
@hold_concurrency = false
|
151
|
-
else
|
152
|
-
@hold_concurrency = true
|
153
|
-
end
|
154
|
-
=end
|
155
|
-
|
156
|
-
end
|
157
|
-
|
158
|
-
def run(scenario)
|
159
|
-
# assume the scenario and testset files are in dir unless they contain '/'
|
160
|
-
# in which case they are assumed to be absolute paths
|
161
|
-
if scenario.include?("/")
|
162
|
-
musl_file = scenario
|
163
|
-
else
|
164
|
-
musl_file = @params["dir"] + "/" + scenario
|
165
|
-
end
|
166
|
-
# msg musl_file, Logger::DEBUG
|
167
|
-
@api.configure("musl", File.read(musl_file))
|
168
|
-
|
169
|
-
unless @testset.empty?
|
170
|
-
if @testset.include?("/")
|
171
|
-
csv_file = @testset
|
172
|
-
else
|
173
|
-
csv_file = @params["dir"] + "/" + @testset
|
174
|
-
end
|
175
|
-
@api.configure("csv", File.read(csv_file))
|
176
|
-
end
|
177
|
-
|
178
|
-
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
179
|
-
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
180
|
-
|
181
|
-
configure_hosts
|
182
|
-
@api.configure("delay", @delay)
|
183
|
-
@api.configure("vectorAddressPairing", @vector_address_pairing)
|
184
|
-
@api.configure("limitConcurrency", @limit_concurrency)
|
185
|
-
# @api.configure("holdConcurrency", @hold_concurrency)
|
186
|
-
|
187
|
-
if @no_verify == false # don't do verify if no_verify==true
|
188
|
-
msg "verifying #{scenario} ..."
|
189
|
-
response = @api.verify
|
190
|
-
msg response, Logger::DEBUG
|
191
|
-
# sleep 3
|
192
|
-
v = parse_verify_response(response)
|
193
|
-
msg "#{v}", Logger::DEBUG
|
194
|
-
if v.nil?
|
195
|
-
msg "error in verify"
|
196
|
-
return
|
197
|
-
end
|
198
|
-
if @verify_only
|
199
|
-
msg v
|
200
|
-
return
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
msg "starting #{scenario} ..."
|
205
|
-
@api.start
|
206
|
-
start_time = Time.now.to_i
|
207
|
-
while true
|
208
|
-
sleep 5
|
209
|
-
status = @api.status
|
210
|
-
if !status.nil?
|
211
|
-
if !status["status"].nil?
|
212
|
-
if status["status"]["running"] == false
|
213
|
-
msg "running = #{status["status"]["running"]}", Logger::DEBUG
|
214
|
-
r = parse_status(status)
|
215
|
-
dump_status(status, musl_file)
|
216
|
-
return
|
217
|
-
else
|
218
|
-
r = parse_status(status)
|
219
|
-
end
|
220
|
-
else # status['status'].nil? ... no bonafide status was returned
|
221
|
-
time_now = Time.now.to_i
|
222
|
-
if time_now - start_time > 20
|
223
|
-
# puts "\nError: timing out after 20 seconds. Test had failed to start or verify"
|
224
|
-
break
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
ensure
|
230
|
-
msg "stopping #{scenario} ..."
|
231
|
-
end
|
232
|
-
|
233
|
-
def cmd_running?
|
234
|
-
if @api.nil?
|
235
|
-
msg "false"
|
236
|
-
return
|
237
|
-
end
|
238
|
-
|
239
|
-
status = @api.status
|
240
|
-
if !status.nil?
|
241
|
-
if !status["status"].nil?
|
242
|
-
msg status["status"]["running"]
|
243
|
-
end
|
244
|
-
else
|
245
|
-
msg "false"
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
def configure_hosts
|
250
|
-
@hosts = Array.new
|
251
|
-
@addr_indexes = Array.new
|
252
|
-
@offset_indexes = Array.new
|
253
|
-
hosts = @params["hosts"]
|
254
|
-
if !hosts.nil?
|
255
|
-
p = hosts.split(",")
|
256
|
-
p.each do | h |
|
257
|
-
if h.include?("-") # b1-1000,b2-1 to indicate addr_count
|
258
|
-
q = h.split("-")
|
259
|
-
@hosts << q[0]
|
260
|
-
if q[1].include?(":") # -1000:20 to indicate offset within range
|
261
|
-
r = q[1].split(":")
|
262
|
-
@addr_indexes << r[0]
|
263
|
-
@offset_indexes << r[1]
|
264
|
-
else
|
265
|
-
@addr_indexes << q[1]
|
266
|
-
@offset_indexes << 1
|
267
|
-
end
|
268
|
-
else # default to the 1st addr index
|
269
|
-
@hosts << h
|
270
|
-
@addr_indexes << 1
|
271
|
-
@offset_indexes << 1
|
272
|
-
end
|
273
|
-
end
|
274
|
-
else
|
275
|
-
@hosts = ['b1','b2']
|
276
|
-
@addr_indexes = [1,1]
|
277
|
-
@offset_indexes = [1,1]
|
278
|
-
end
|
279
|
-
|
280
|
-
set_hosts_byname(@hosts, @addr_indexes, @offset_indexes)
|
281
|
-
end
|
282
|
-
|
283
|
-
def set_hosts_byname(hosts=@hosts, count=[1,1], offset=[1,1], v4=true)
|
284
|
-
new_hosts = Array.new
|
285
|
-
str = ""
|
286
|
-
hosts.each_with_index do |n, i|
|
287
|
-
if n.match(/^[ab][1-4]$/) or n.include?(".") # possible vlan
|
288
|
-
if count[i] == 1 or count[i].nil?
|
289
|
-
str = "#{n}/*"
|
290
|
-
else
|
291
|
-
str = "#{n}/*,#{count[i]},#{offset[i]}"
|
292
|
-
end
|
293
|
-
msg "using host #{str}", Logger::DEBUG
|
294
|
-
else
|
295
|
-
@net = Netconfig.new
|
296
|
-
@net.setup(@hosts, @username, @password)
|
297
|
-
if v4
|
298
|
-
addr = @net.get("hosts/#{n}")['v4_addr']
|
299
|
-
else
|
300
|
-
addr = @net.get("hosts/#{n}")['v6_addr']
|
301
|
-
end
|
302
|
-
str = "#{addr}"
|
303
|
-
msg "using host #{str}", Logger::DEBUG
|
304
|
-
end
|
305
|
-
new_hosts << str
|
306
|
-
end
|
307
|
-
set_hosts(new_hosts)
|
308
|
-
end
|
309
|
-
|
310
|
-
# expects full strings: e.g. b1/12.89.0.1 ...
|
311
|
-
def set_hosts(hosts=["b1","b2"])
|
312
|
-
host_params = {}
|
313
|
-
|
314
|
-
# assign hosts to consecutive string keys, host_0, host_1, etc ...
|
315
|
-
hosts.each_with_index do | h, i |
|
316
|
-
host_params["host_#{i}"] = hosts[i]
|
317
|
-
end
|
318
|
-
|
319
|
-
# convert keys to symbols
|
320
|
-
# host_params.each_key { |k| host_params[k.to_sym] = host_params[k] }
|
321
|
-
new_host_params = {}
|
322
|
-
host_params.each_key { |k| new_host_params[k.to_sym] = host_params[k] }
|
10
|
+
attr_accessor :api, :params, :hosts, :addr_indexes, :offset_indexes, :peak_concurrency, :peak_throughput
|
323
11
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
new_host_params[:default_host] = @hash['default_host']
|
330
|
-
end
|
331
|
-
=end
|
332
|
-
|
333
|
-
@api.configure("hosts", new_host_params)
|
334
|
-
|
335
|
-
end
|
336
|
-
|
337
|
-
def dump_status(status, msl)
|
338
|
-
filename = "app_id_status.json"
|
339
|
-
f = File.open(filename, "a")
|
340
|
-
status["filename"] = msl
|
341
|
-
str = JSON.pretty_generate(status)
|
342
|
-
f.write(",") if !File.zero?(f) # if appending, we need to insert a comma
|
343
|
-
f.write(str)
|
344
|
-
f.close
|
345
|
-
end
|
346
|
-
|
347
|
-
def output_csv(msl_file)
|
348
|
-
filename = "app_id_stats.csv"
|
349
|
-
f = File.open(filename, "a")
|
350
|
-
doc = "#{msl_file},#{@executed},#{@errors.to_i},#{@timeouts.to_i},#{@client_tx_bytes},#{@client_tx_msgs},#{@client_rx_bytes},#{@client_rx_msgs},#{@server_tx_bytes},#{@server_tx_msgs},#{@server_rx_bytes},#{@server_rx_msgs}\n"
|
351
|
-
File.open(filename, 'a') {|f| f.write(doc) }
|
352
|
-
end
|
353
|
-
|
354
|
-
def parse_verify_response(response)
|
355
|
-
if response.nil? # || response.empty?
|
356
|
-
msg "*** error = no response received from /verify ***\n\n"
|
357
|
-
return nil
|
358
|
-
end
|
359
|
-
begin
|
360
|
-
msg JSON.pretty_generate(response), Logger::DEBUG
|
361
|
-
if !response["status"].nil?
|
362
|
-
if response["status"]["error"] == true
|
363
|
-
@error = response["status"]["error"]
|
364
|
-
@reason = response["status"]["reason"]
|
365
|
-
dump_status(response)
|
366
|
-
msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
|
367
|
-
return nil
|
368
|
-
end
|
369
|
-
end
|
370
|
-
msg "*** verify: okay ***", Logger::DEBUG
|
371
|
-
return "*** verify: okay ***"
|
372
|
-
rescue => e
|
373
|
-
msg e, Logger::DEBUG
|
374
|
-
return nil
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
|
-
def parse_status(status)
|
379
|
-
return nil if status.nil?
|
380
|
-
@reported_volume = 0
|
381
|
-
if !status["status"]["error"].nil?
|
382
|
-
if status["status"]["error"] == true
|
383
|
-
@error = status["status"]["error"]
|
384
|
-
@reason = status["status"]["reason"]
|
385
|
-
msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
|
386
|
-
return nil
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
@stats_summary = status["status"]["statistics"]["summary"]
|
391
|
-
@duration = @stats_summary["duration"]
|
392
|
-
@instances = @stats_summary["instances"]
|
393
|
-
@total_instances = @instances["total"]
|
394
|
-
@executed = @instances["executed"]
|
395
|
-
@timeouts = @instances["timeouts"]
|
396
|
-
@errors = @instances["errors"]
|
397
|
-
@asserts_failed = @stats_summary["asserts"]["failed"]
|
398
|
-
@server = @stats_summary["server"]
|
399
|
-
@server_tx_bytes = @server["tx"]["bytes"]
|
400
|
-
@server_tx_msgs = @server["tx"]["msgs"]
|
401
|
-
@server_rx_bytes = @server["rx"]["bytes"]
|
402
|
-
@server_rx_msgs = @server["rx"]["msgs"]
|
403
|
-
@client = @stats_summary["client"]
|
404
|
-
@client_tx_bytes = @client["tx"]["bytes"]
|
405
|
-
@client_tx_msgs = @client["tx"]["msgs"]
|
406
|
-
@client_rx_bytes = @client["rx"]["bytes"]
|
407
|
-
@client_rx_msgs = @client["rx"]["msgs"]
|
408
|
-
@scenarios = status["status"]["statistics"]["scenarios"]
|
409
|
-
@scenarios.each do | scenario |
|
410
|
-
@reported_volume = @reported_volume + scenario["volume"]
|
411
|
-
end
|
412
|
-
|
413
|
-
if @reported_volume.to_i > @peak_concurrency
|
414
|
-
@peak_concurrency = @reported_volume.to_i
|
415
|
-
end
|
416
|
-
|
417
|
-
bits1 = (@client_tx_bytes.to_i + @client_rx_bytes.to_i) * 8
|
418
|
-
dur1 = @duration.to_f
|
419
|
-
thruput = format_float(2, bits1.to_f / dur1)
|
420
|
-
|
421
|
-
if thruput.to_f > @peak_throughput
|
422
|
-
@peak_throughput = thruput.to_f
|
423
|
-
end
|
424
|
-
|
425
|
-
msg ""
|
426
|
-
msg "duration: #{format_float(2, @duration)}"
|
427
|
-
msg "concurrency: #{@reported_volume}"
|
428
|
-
msg "tests/sec: #{format_float(2, @executed.to_f / @duration)}" if @duration.to_i > 0
|
429
|
-
msg "bits/sec: #{thruput}" if @duration.to_i > 0
|
430
|
-
msg "passed: #{@executed}"
|
431
|
-
msg "errors: #{@errors}"
|
432
|
-
msg "timeouts: #{@timeouts}"
|
433
|
-
msg "client tx bytes/sec #{format_float(2, @client_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
434
|
-
msg "client tx msgs/sec #{format_float(2, @client_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
435
|
-
msg "client rx bytes/sec #{format_float(2, @client_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
436
|
-
msg "client rx msgs/sec #{format_float(2, @client_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
437
|
-
msg "server tx bytes/sec #{format_float(2, @server_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
438
|
-
msg "server tx msgs/sec #{format_float(2, @server_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
439
|
-
msg "server rx bytes/sec #{format_float(2, @server_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
440
|
-
msg "server rx msgs/sec #{format_float(2, @server_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
441
|
-
msg ""
|
442
|
-
end
|
443
|
-
|
444
|
-
def parse_cli argv
|
445
|
-
@hash = Hash.new
|
446
|
-
while not argv.empty?
|
447
|
-
break if argv.first[0,1] != '-'
|
448
|
-
|
449
|
-
k = argv.shift
|
450
|
-
|
451
|
-
if [ '-a', '--vector_address_pairing' ].member? k
|
452
|
-
@hash['vector_address_pairing'] = true
|
453
|
-
next
|
454
|
-
end
|
12
|
+
# displays command-line help
|
13
|
+
# * argv = command-line arguments
|
14
|
+
def cmd_help argv
|
15
|
+
help
|
16
|
+
end
|
455
17
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
18
|
+
# sets up, executes, and closes a Studio Scale test
|
19
|
+
# * argv = command-line arguments , requires a scenario (-s) argument
|
20
|
+
def cmd_run_file argv
|
21
|
+
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
22
|
+
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
23
|
+
puts "Please use 'cmd_runscale:run_files'"
|
24
|
+
setup argv
|
25
|
+
|
26
|
+
if not @hash['scenario']
|
27
|
+
msg "scenario required", Logger::ERROR
|
28
|
+
return help
|
29
|
+
else
|
30
|
+
if @hash['scenario'].include?(".msl")
|
31
|
+
scenario = @hash['scenario']
|
32
|
+
else # TODO: eventually, xml and mus file may be supported by scale api
|
33
|
+
msg "only .msl files are currently supported", Logger::ERROR
|
34
|
+
return help
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if not File.readable?(scenario)
|
39
|
+
msg "*** Error: can't read scenario file #{scenario}", Logger::ERROR
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
44
|
+
@api.configure("pattern", @cmd_line_pattern)
|
45
|
+
@params = {}
|
46
|
+
@params["dir"] = @dir
|
47
|
+
@params["msl"] = scenario
|
48
|
+
@params["hosts"] = @cmd_line_hosts
|
49
|
+
run(scenario)
|
50
|
+
@api.release
|
51
|
+
end
|
460
52
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
53
|
+
# sets up, executes, and closes a Studio Scale test for each scenario (.msl file) found in the specified directory
|
54
|
+
# * argv = command-line arguments, requires a directory (-d) argument
|
55
|
+
# * optional -r argument for recursive directory search (default is a flat directory)
|
56
|
+
def cmd_run_dir argv
|
57
|
+
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
58
|
+
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
59
|
+
puts "Please use 'cmd_runscale:run_files'"
|
60
|
+
setup argv
|
61
|
+
|
62
|
+
if not @hash['dir']
|
63
|
+
return help
|
64
|
+
else
|
65
|
+
@dir = @hash['dir']
|
66
|
+
end
|
67
|
+
|
68
|
+
msg "Clean up existing stats files: app_id_status.json, app_id_stats.csv", Logger::INFO
|
69
|
+
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
70
|
+
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
71
|
+
|
72
|
+
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
73
|
+
@api.configure("pattern", @cmd_line_pattern)
|
74
|
+
@params = {}
|
75
|
+
@params["dir"] = @dir
|
76
|
+
@params["hosts"] = @cmd_line_hosts
|
77
|
+
recursive = (@hash['recursive'].nil?) ? "": "**"
|
78
|
+
files = Dir.glob(File.join(@dir,recursive,"*.msl"))
|
79
|
+
if !files.empty?
|
80
|
+
files.sort.each do | f |
|
81
|
+
run(f)
|
82
|
+
output_csv(f)
|
83
|
+
sleep 2
|
84
|
+
end
|
85
|
+
else
|
86
|
+
msg "no msl files found in #{@dir}", Logger::ERROR
|
87
|
+
end
|
88
|
+
@api.release
|
89
|
+
end
|
465
90
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
91
|
+
# sets up, executes, and closes a Studio Scale test for one scenario or each scenario (.msl file) found in the specified directory
|
92
|
+
# * argv = command-line arguments
|
93
|
+
# * optional -s scenario file
|
94
|
+
# * optional -d directory containing one or more scenario files
|
95
|
+
# * optional -r argument for recursive directory search (default is a flat directory)
|
96
|
+
def cmd_run_files argv
|
97
|
+
setup argv
|
98
|
+
|
99
|
+
msg "Clean up existing stats files: app_id_status.json, app_id_stats.csv", Logger::INFO
|
100
|
+
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
101
|
+
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
102
|
+
|
103
|
+
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
104
|
+
@api.configure("pattern", @cmd_line_pattern)
|
105
|
+
@params = {}
|
106
|
+
@params["hosts"] = @cmd_line_hosts
|
107
|
+
if @hash["dir"].nil?
|
108
|
+
files = [@hash["scenario"]]
|
109
|
+
else
|
110
|
+
recursive = (@hash['recursive'].nil?) ? "": "**"
|
111
|
+
files = Dir.glob(File.join(@hash["dir"],recursive,"*.msl"))
|
112
|
+
end
|
113
|
+
if files.nil? or files.empty?
|
114
|
+
msg "no msl files found", Logger::ERROR
|
115
|
+
else
|
116
|
+
files.each do | scenario |
|
117
|
+
run scenario
|
118
|
+
if @verify_only
|
119
|
+
output_verify_results scenario
|
120
|
+
else
|
121
|
+
output_csv scenario
|
122
|
+
end
|
123
|
+
sleep 2
|
124
|
+
end
|
125
|
+
end
|
126
|
+
@api.release
|
127
|
+
end
|
470
128
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
129
|
+
private
|
130
|
+
|
131
|
+
def setup argv
|
132
|
+
parse_cli argv
|
133
|
+
@params = {}
|
134
|
+
@peak_concurrency = 0
|
135
|
+
@peak_throughput = 0.0
|
136
|
+
|
137
|
+
if @hash['test']
|
138
|
+
@verify_only = true
|
139
|
+
else
|
140
|
+
@verify_only = false
|
141
|
+
end
|
142
|
+
|
143
|
+
if not @hash['testset']
|
144
|
+
@testset = ""
|
145
|
+
else
|
146
|
+
@testset = @hash['testset']
|
147
|
+
end
|
148
|
+
|
149
|
+
if not @hash['pattern']
|
150
|
+
@cmd_line_pattern = "{ \"iterations\": 1, \"intervals\": [ {\"iterations\":1, \"end\":100, \"start\":1, \"duration\":20 } ] }"
|
151
|
+
else
|
152
|
+
@cmd_line_pattern = @hash['pattern']
|
153
|
+
end
|
154
|
+
|
155
|
+
if not @hash['interfaces']
|
156
|
+
@cmd_line_hosts = "b1,b2"
|
157
|
+
else
|
158
|
+
@cmd_line_hosts = @hash['interfaces']
|
159
|
+
end
|
160
|
+
|
161
|
+
if not @hash['delay']
|
162
|
+
@delay = 0
|
163
|
+
else
|
164
|
+
@delay = @hash['delay'].to_i
|
165
|
+
end
|
166
|
+
|
167
|
+
if not @hash['no_verify']
|
168
|
+
@no_verify = false
|
169
|
+
else
|
170
|
+
@no_verify = true
|
171
|
+
end
|
172
|
+
|
173
|
+
if not @hash['vector_address_pairing']
|
174
|
+
@vector_address_pairing = false
|
175
|
+
@limit_concurrency = false
|
176
|
+
else
|
177
|
+
@vector_address_pairing = true
|
178
|
+
@limit_concurrency = true
|
179
|
+
end
|
475
180
|
|
476
|
-
|
477
|
-
help
|
478
|
-
exit
|
479
|
-
end
|
480
|
-
=begin
|
481
|
-
if [ '-hold', '--hold_concurrency' ].member? k
|
482
|
-
@hash['hold_concurrency'] = true
|
483
|
-
next
|
484
|
-
end
|
485
|
-
=end
|
486
|
-
if [ '-l', '--delay' ].member? k
|
487
|
-
@hash['delay'] = shift(k, argv)
|
488
|
-
next
|
489
|
-
end
|
181
|
+
end
|
490
182
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
183
|
+
def run(scenario)
|
184
|
+
begin
|
185
|
+
@api.configure("musl", File.read(scenario))
|
186
|
+
rescue
|
187
|
+
raise "Failed to read in scenario #{scenario}"
|
188
|
+
end
|
189
|
+
|
190
|
+
unless @testset.empty?
|
191
|
+
@api.configure("csv", File.read(@testset))
|
192
|
+
end
|
193
|
+
|
194
|
+
configure_hosts
|
195
|
+
@api.configure("delay", @delay)
|
196
|
+
@api.configure("vectorAddressPairing", @vector_address_pairing)
|
197
|
+
@api.configure("limitConcurrency", @limit_concurrency)
|
198
|
+
|
199
|
+
if @no_verify == false # don't do verify if no_verify==true
|
200
|
+
msg "verifying #{scenario} ...", Logger::INFO
|
201
|
+
response = @api.verify
|
202
|
+
msg response, Logger::DEBUG
|
203
|
+
# sleep 3
|
204
|
+
v = parse_verify_response(response)
|
205
|
+
msg "#{v}", Logger::DEBUG
|
206
|
+
if v.nil? or v.include? "Error"
|
207
|
+
msg "error in verify", Logger::ERROR
|
208
|
+
return
|
209
|
+
end
|
210
|
+
if @verify_only
|
211
|
+
msg v, Logger::DEBUG
|
212
|
+
return v
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
msg "starting #{scenario} ...", Logger::INFO
|
217
|
+
@api.start
|
218
|
+
start_time = Time.now.to_i
|
219
|
+
while true
|
220
|
+
sleep 5
|
221
|
+
status = @api.status
|
222
|
+
if !status.nil?
|
223
|
+
if !status["status"].nil?
|
224
|
+
if status["status"]["running"] == false
|
225
|
+
msg "running = #{status["status"]["running"]}", Logger::DEBUG
|
226
|
+
r = parse_status(status)
|
227
|
+
dump_status(status, scenario)
|
228
|
+
return
|
229
|
+
else
|
230
|
+
r = parse_status(status)
|
231
|
+
end
|
232
|
+
else # status['status'].nil? ... no bonafide status was returned
|
233
|
+
time_now = Time.now.to_i
|
234
|
+
if time_now - start_time > 60
|
235
|
+
msg "Error: timing out after 60 seconds. Test had failed to start or verify", Logger::ERROR
|
236
|
+
break
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
ensure
|
242
|
+
msg "stopping #{scenario} ...", Logger::DEBUG
|
243
|
+
end
|
500
244
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
245
|
+
def cmd_running?
|
246
|
+
if @api.nil?
|
247
|
+
msg "false"
|
248
|
+
return
|
249
|
+
end
|
250
|
+
|
251
|
+
status = @api.status
|
252
|
+
if !status.nil?
|
253
|
+
if !status["status"].nil?
|
254
|
+
msg status["status"]["running"]
|
255
|
+
end
|
256
|
+
else
|
257
|
+
msg "false"
|
258
|
+
end
|
259
|
+
end
|
505
260
|
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
261
|
+
def configure_hosts
|
262
|
+
@hosts = Array.new
|
263
|
+
@addr_indexes = Array.new
|
264
|
+
@offset_indexes = Array.new
|
265
|
+
hosts = @params["hosts"]
|
266
|
+
if !hosts.nil?
|
267
|
+
p = hosts.split(",")
|
268
|
+
p.each do | h |
|
269
|
+
if h.include?("-") # b1-1000,b2-1 to indicate addr_count
|
270
|
+
q = h.split("-")
|
271
|
+
@hosts << q[0]
|
272
|
+
if q[1].include?(":") # -1000:20 to indicate offset within range
|
273
|
+
r = q[1].split(":")
|
274
|
+
@addr_indexes << r[0]
|
275
|
+
@offset_indexes << r[1]
|
276
|
+
else
|
277
|
+
@addr_indexes << q[1]
|
278
|
+
@offset_indexes << 1
|
279
|
+
end
|
280
|
+
else # default to the 1st addr index
|
281
|
+
@hosts << h
|
282
|
+
@addr_indexes << 1
|
283
|
+
@offset_indexes << 1
|
284
|
+
end
|
285
|
+
end
|
286
|
+
else
|
287
|
+
@hosts = ['b1','b2']
|
288
|
+
@addr_indexes = [1,1]
|
289
|
+
@offset_indexes = [1,1]
|
290
|
+
end
|
291
|
+
|
292
|
+
set_hosts_byname(@hosts, @addr_indexes, @offset_indexes)
|
293
|
+
end
|
510
294
|
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
295
|
+
def set_hosts_byname(hosts=@hosts, count=[1,1], offset=[1,1], v4=true)
|
296
|
+
new_hosts = Array.new
|
297
|
+
str = ""
|
298
|
+
hosts.each_with_index do |n, i|
|
299
|
+
if n.match(/^[ab][1-4]$/) or n.include?(".") # possible vlan
|
300
|
+
if count[i] == 1 or count[i].nil?
|
301
|
+
str = "#{n}/*"
|
302
|
+
else
|
303
|
+
str = "#{n}/*,#{count[i]},#{offset[i]}"
|
304
|
+
end
|
305
|
+
msg "using host #{str}", Logger::DEBUG
|
306
|
+
else
|
307
|
+
@net = Netconfig.new
|
308
|
+
@net.setup(@hosts, @username, @password)
|
309
|
+
if v4
|
310
|
+
addr = @net.get("hosts/#{n}")['v4_addr']
|
311
|
+
else
|
312
|
+
addr = @net.get("hosts/#{n}")['v6_addr']
|
313
|
+
end
|
314
|
+
str = "#{addr}"
|
315
|
+
msg "using host #{str}", Logger::DEBUG
|
316
|
+
end
|
317
|
+
new_hosts << str
|
318
|
+
end
|
319
|
+
set_hosts(new_hosts)
|
522
320
|
end
|
523
|
-
|
524
|
-
|
525
|
-
|
321
|
+
|
322
|
+
# expects full strings: e.g. b1/12.89.0.1 ...
|
323
|
+
def set_hosts(hosts=["b1","b2"])
|
324
|
+
host_params = {}
|
325
|
+
|
326
|
+
# assign hosts to consecutive string keys, host_0, host_1, etc ...
|
327
|
+
hosts.each_with_index do | h, i |
|
328
|
+
host_params["host_#{i}"] = hosts[i]
|
329
|
+
end
|
330
|
+
|
331
|
+
# convert keys to symbols
|
332
|
+
# host_params.each_key { |k| host_params[k.to_sym] = host_params[k] }
|
333
|
+
new_host_params = {}
|
334
|
+
host_params.each_key { |k| new_host_params[k.to_sym] = host_params[k] }
|
335
|
+
|
336
|
+
@api.configure("hosts", new_host_params)
|
337
|
+
|
526
338
|
end
|
527
|
-
ps = ps[0..ps.length-2] # remove final comma
|
528
|
-
ps = ps + "] }"
|
529
|
-
@hash['pattern'] = ps
|
530
|
-
next
|
531
|
-
end
|
532
339
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
340
|
+
def dump_status(status, msl)
|
341
|
+
filename = "app_id_status.json"
|
342
|
+
msg "Update status to: #{File.absolute_path(filename)}", Logger::INFO
|
343
|
+
f = File.open(filename, "a")
|
344
|
+
status["filename"] = msl
|
345
|
+
str = JSON.pretty_generate(status)
|
346
|
+
File.zero?(filename) or f.puts(",")
|
347
|
+
f.write(str)
|
348
|
+
f.close
|
349
|
+
end
|
537
350
|
|
351
|
+
def output_csv(msl_file)
|
352
|
+
filename = "app_id_stats.csv"
|
353
|
+
msg "Update stats to: #{File.absolute_path(filename)}", Logger::INFO
|
354
|
+
unless File.exists?(filename)
|
355
|
+
heading = "scenario,executed,errors,timeouts,client_tx_bytes,client_tx_msgs,client_rx_bytes,client_rx_msgs,server_tx_bytes,server_tx_msgs,server_rx_bytes,server_rx_msgs"
|
356
|
+
File.open(filename, 'a'){|f| f.puts(heading)}
|
357
|
+
end
|
358
|
+
@row = "#{msl_file},#{@executed},#{@errors},#{@timeouts},#{@client_tx_bytes},#{@client_tx_msgs},#{@client_rx_bytes},#{@client_rx_msgs},#{@server_tx_bytes},#{@server_tx_msgs},#{@server_rx_bytes},#{@server_rx_msgs}"
|
359
|
+
File.open(filename, 'a'){|f| f.puts(@row)}
|
360
|
+
end
|
538
361
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
362
|
+
def output_verify_results(msl_file)
|
363
|
+
filename = "app_id_stats.csv"
|
364
|
+
msg "Update verify results to: #{File.absolute_path(filename)}", Logger::DEBUG
|
365
|
+
unless File.exists?(filename)
|
366
|
+
msg "Writting verify results to: #{File.absolute_path(filename)}", Logger::INFO
|
367
|
+
heading = "scenario, status"
|
368
|
+
File.open(filename, 'a'){|f| f.puts(heading)}
|
369
|
+
end
|
370
|
+
File.open(filename, 'a'){|f| f.puts("#{msl_file},#{@verify_response}")}
|
371
|
+
end
|
543
372
|
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
373
|
+
def parse_verify_response(response)
|
374
|
+
if response.nil? # || response.empty?
|
375
|
+
msg "*** error = no response received from /verify ***\n\n", Logger::ERROR
|
376
|
+
@verify_response = "Error = No response from verify"
|
377
|
+
return @verify_response
|
378
|
+
end
|
379
|
+
begin
|
380
|
+
msg JSON.pretty_generate(response), Logger::DEBUG
|
381
|
+
if !response["status"].nil?
|
382
|
+
if response["status"]["error"] == true
|
383
|
+
@error = response["status"]["error"]
|
384
|
+
@reason = response["status"]["reason"]
|
385
|
+
msg "*** Error = #{@error}, reason = #{@reason} ***\n\n", Logger::ERROR
|
386
|
+
@verify_response = "Error = #{@error}, reason = #{@reason}"
|
387
|
+
return @verify_response
|
388
|
+
end
|
389
|
+
end
|
390
|
+
msg "*** verify: okay ***", Logger::INFO
|
391
|
+
@verify_response = "okay"
|
392
|
+
return @verify_response
|
393
|
+
rescue => e
|
394
|
+
msg e, Logger::ERROR
|
395
|
+
raise
|
396
|
+
return nil
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def parse_status(status)
|
401
|
+
return nil if status.nil?
|
402
|
+
@reported_volume = 0
|
403
|
+
if !status["status"]["error"].nil?
|
404
|
+
if status["status"]["error"] == true
|
405
|
+
@error = status["status"]["error"]
|
406
|
+
@reason = status["status"]["reason"]
|
407
|
+
msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
|
408
|
+
return nil
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
@stats_summary = status["status"]["statistics"]["summary"]
|
413
|
+
@duration = @stats_summary["duration"]
|
414
|
+
@instances = @stats_summary["instances"]
|
415
|
+
@total_instances = @instances["total"]
|
416
|
+
@executed = @instances["executed"]
|
417
|
+
@timeouts = @instances["timeouts"]
|
418
|
+
@errors = @instances["errors"]
|
419
|
+
@asserts_failed = @stats_summary["asserts"]["failed"]
|
420
|
+
@server = @stats_summary["server"]
|
421
|
+
@server_tx_bytes = @server["tx"]["bytes"]
|
422
|
+
@server_tx_msgs = @server["tx"]["msgs"]
|
423
|
+
@server_rx_bytes = @server["rx"]["bytes"]
|
424
|
+
@server_rx_msgs = @server["rx"]["msgs"]
|
425
|
+
@client = @stats_summary["client"]
|
426
|
+
@client_tx_bytes = @client["tx"]["bytes"]
|
427
|
+
@client_tx_msgs = @client["tx"]["msgs"]
|
428
|
+
@client_rx_bytes = @client["rx"]["bytes"]
|
429
|
+
@client_rx_msgs = @client["rx"]["msgs"]
|
430
|
+
@scenarios = status["status"]["statistics"]["scenarios"]
|
431
|
+
@scenarios.each do | scenario |
|
432
|
+
@reported_volume = @reported_volume + scenario["volume"]
|
433
|
+
end
|
434
|
+
|
435
|
+
if @reported_volume.to_i > @peak_concurrency
|
436
|
+
@peak_concurrency = @reported_volume.to_i
|
437
|
+
end
|
438
|
+
|
439
|
+
bits1 = (@client_tx_bytes.to_i + @client_rx_bytes.to_i) * 8
|
440
|
+
dur1 = @duration.to_f
|
441
|
+
thruput = format_float(2, bits1.to_f / dur1)
|
442
|
+
|
443
|
+
if thruput.to_f > @peak_throughput
|
444
|
+
@peak_throughput = thruput.to_f
|
445
|
+
end
|
446
|
+
|
447
|
+
msg ""
|
448
|
+
msg "duration: #{format_float(2, @duration)}"
|
449
|
+
msg "concurrency: #{@reported_volume}"
|
450
|
+
msg "tests/sec: #{format_float(2, @executed.to_f / @duration)}" if @duration.to_i > 0
|
451
|
+
msg "bits/sec: #{thruput}" if @duration.to_i > 0
|
452
|
+
msg "passed: #{@executed}"
|
453
|
+
msg "errors: #{@errors}"
|
454
|
+
msg "timeouts: #{@timeouts}"
|
455
|
+
msg "client tx bytes/sec #{format_float(2, @client_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
456
|
+
msg "client tx msgs/sec #{format_float(2, @client_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
457
|
+
msg "client rx bytes/sec #{format_float(2, @client_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
458
|
+
msg "client rx msgs/sec #{format_float(2, @client_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
459
|
+
msg "server tx bytes/sec #{format_float(2, @server_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
460
|
+
msg "server tx msgs/sec #{format_float(2, @server_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
461
|
+
msg "server rx bytes/sec #{format_float(2, @server_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
462
|
+
msg "server rx msgs/sec #{format_float(2, @server_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
463
|
+
msg ""
|
464
|
+
end
|
465
|
+
|
466
|
+
def parse_cli argv
|
467
|
+
@hash = Hash.new
|
468
|
+
while not argv.empty?
|
469
|
+
break if argv.first[0,1] != '-'
|
470
|
+
|
471
|
+
k = argv.shift
|
472
|
+
|
473
|
+
if [ '-a', '--vector_address_pairing' ].member? k
|
474
|
+
@hash['vector_address_pairing'] = true
|
475
|
+
next
|
476
|
+
end
|
477
|
+
|
478
|
+
if [ '-c', '--csv' ].member? k
|
479
|
+
@hash['testset'] = shift(k, argv)
|
480
|
+
next
|
481
|
+
end
|
482
|
+
|
483
|
+
if [ '-d', '--dir' ].member? k
|
484
|
+
@hash['dir'] = shift(k, argv)
|
485
|
+
next
|
486
|
+
end
|
487
|
+
|
488
|
+
if [ '-f', '--default_host' ].member? k
|
489
|
+
@hash['default_host'] = shift(k, argv)
|
490
|
+
next
|
491
|
+
end
|
492
|
+
|
493
|
+
if [ '-i', '--interfaces' ].member? k
|
494
|
+
@hash['interfaces'] = shift(k, argv)
|
495
|
+
next
|
496
|
+
end
|
497
|
+
|
498
|
+
if [ '-h', '--help' ].member? k
|
499
|
+
help
|
500
|
+
exit
|
501
|
+
end
|
502
|
+
=begin
|
503
|
+
if [ '-hold', '--hold_concurrency' ].member? k
|
504
|
+
@hash['hold_concurrency'] = true
|
551
505
|
next
|
552
506
|
end
|
507
|
+
=end
|
508
|
+
if [ '-l', '--delay' ].member? k
|
509
|
+
@hash['delay'] = shift(k, argv)
|
510
|
+
next
|
511
|
+
end
|
512
|
+
|
513
|
+
if [ '-m', '--mu_string' ].member? k
|
514
|
+
mu_string = shift(k, argv)
|
515
|
+
if mu_string =~ /(.+?):(.+?)@(.*)/
|
516
|
+
@@mu_admin_user = $1
|
517
|
+
@@mu_admin_pass = $2
|
518
|
+
@@mu_ip = $3
|
519
|
+
end
|
520
|
+
next
|
521
|
+
end
|
522
|
+
|
523
|
+
if [ '-n', '--no_verify' ].member? k
|
524
|
+
@hash['no_verify'] = true
|
525
|
+
next
|
526
|
+
end
|
527
|
+
|
528
|
+
if [ '-o', '--output' ].member? k
|
529
|
+
$stdout.reopen(shift(k, argv), "w")
|
530
|
+
next
|
531
|
+
end
|
532
|
+
|
533
|
+
if [ '-p', '--pattern' ].member? k
|
534
|
+
patterns = Array.new
|
535
|
+
pattern_string = shift(k, argv)
|
536
|
+
pstrings = pattern_string.split(",")
|
537
|
+
pstrings.each do | p |
|
538
|
+
if p =~ /(.+?)-(.+?):(.*)/ # e.g. 1-10000:60
|
539
|
+
start_vol = $1
|
540
|
+
end_vol = $2
|
541
|
+
duration = $3
|
542
|
+
patterns << "{\"iterations\":1, \"end\":#{end_vol}, \"start\":#{start_vol}, \"duration\":#{duration} }"
|
543
|
+
end
|
544
|
+
end
|
545
|
+
ps = "{ \"iterations\": 1, \"intervals\": ["
|
546
|
+
patterns.each do | p |
|
547
|
+
ps = ps + p + ","
|
548
|
+
end
|
549
|
+
ps = ps[0..ps.length-2] # remove final comma
|
550
|
+
ps = ps + "] }"
|
551
|
+
@hash['pattern'] = ps
|
552
|
+
next
|
553
|
+
end
|
554
|
+
|
555
|
+
if [ '-r', '--recursive'].member? k
|
556
|
+
@hash['recursive'] = true
|
557
|
+
next
|
558
|
+
end
|
559
|
+
|
560
|
+
|
561
|
+
if [ '-s', '--scenario' ].member? k
|
562
|
+
@hash['scenario'] = shift(k, argv)
|
563
|
+
next
|
564
|
+
end
|
565
|
+
|
566
|
+
if [ '-t', '--test' ].member? k
|
567
|
+
@hash['test'] = true
|
568
|
+
next
|
569
|
+
end
|
570
|
+
|
571
|
+
if [ '-v', '--verbose' ].member? k
|
572
|
+
$log.level = Logger::DEBUG
|
573
|
+
next
|
574
|
+
end
|
575
|
+
|
576
|
+
raise ArgumentError, "Unknown option #{k}"
|
577
|
+
end
|
578
|
+
|
579
|
+
@hash
|
580
|
+
end
|
553
581
|
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
puts
|
602
|
-
end
|
582
|
+
def help
|
583
|
+
helps = [
|
584
|
+
{ :short => '-a', :long => '--vector_address_pairing', :value => '', :help => 'sets vectorAddressPairing to true (limits and maps concurrency to the rows in the testset)' },
|
585
|
+
{ :short => '-c', :long => '--csv', :value => '<string>', :help => 'name of the csv testset to run' },
|
586
|
+
{ :short => '-d', :long => '--dir', :value => '<string>', :help => 'directory containing the scenario file' },
|
587
|
+
{ :short => '-f', :long => '--default_host', :value => '<string>', :help => 'default_host setting' },
|
588
|
+
{ :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
|
589
|
+
# { :short => '-hold', :long => '--hold_concurrency', :value => '', :help => 'sets holdConcurrency to tru' },
|
590
|
+
{ :short => '-i', :long => '--interfaces', :value => '<string>', :help => 'comma-separated list of interfaces, e.g. b1,b2 or b1-1000,b2 for ip range' },
|
591
|
+
{ :short => '-l', :long => '--delay', :value => '<string>', :help => 'intra-scenario delay value' },
|
592
|
+
{ :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
|
593
|
+
{ :short => '-n', :long => '--no_verify', :value => '', :help => 'do not do verify before start' },
|
594
|
+
{ :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
|
595
|
+
{ :short => '-p', :long => '--pattern', :value => '<string>', :help => 'pattern in the form of comma-separated concurrency_start-end:duration patterns, e.g. 1-100:60,100-100:60,100-1:60' },
|
596
|
+
{ :short => '-r', :long => '--recursive', :value => '', :help => 'for run_dir, recurse through sub-directories' },
|
597
|
+
{ :short => '-s', :long => '--scenario', :value => '<string>', :help => 'scenario file to run' },
|
598
|
+
{ :short => '-t', :long => '--test', :value => '', :help => 'do verify only' },
|
599
|
+
{ :short => '-v', :long => '--verbose', :value => '', :help => 'set Logger::DEBUG level' }
|
600
|
+
]
|
601
|
+
|
602
|
+
cmds = [
|
603
|
+
"mu cmd_runscale:help",
|
604
|
+
"mu cmd_runscale:run_files -s <scenario>|-d <scenario_directory> --recursive -i <hosts, e.g. a1,dell-9> -p <pattern, e.g. 1-1000:30>",
|
605
|
+
"mu cmd_runscale:run_file -s <scenario> -i <hosts, e.g. a1,dell-9> -p <pattern, e.g. 1-1000:30>",
|
606
|
+
"mu cmd_runscale:run_dir -d <scenario_directory>",
|
607
|
+
"mu cmd_runscale:running?"
|
608
|
+
]
|
609
|
+
|
610
|
+
max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
|
611
|
+
max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
|
612
|
+
puts
|
613
|
+
puts "Usage: mu cmd_runscale:<command> <options>"
|
614
|
+
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
615
|
+
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
616
|
+
puts "Please use 'cmd_runscale:run_files'"
|
617
|
+
puts
|
618
|
+
helps.each do |h|
|
619
|
+
puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
|
620
|
+
end
|
621
|
+
puts
|
622
|
+
puts "Available Commands"
|
623
|
+
puts
|
624
|
+
cmds.each do | c |
|
625
|
+
puts c
|
626
|
+
end
|
627
|
+
puts
|
628
|
+
end
|
603
629
|
|
604
|
-
end
|
605
|
-
end # Command
|
630
|
+
end
|
631
|
+
end # Command
|
606
632
|
end # Mu
|
607
633
|
|