mu 5.7.2.3
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/Mu_Gem.html +1591 -0
- data/bin/mu +11 -0
- data/lib/mu.rb +65 -0
- data/lib/mu/api/ddt.rb +233 -0
- data/lib/mu/api/homepage.rb +54 -0
- data/lib/mu/api/muapi.rb +231 -0
- data/lib/mu/api/netconfig.rb +233 -0
- data/lib/mu/api/scale.rb +199 -0
- data/lib/mu/api/system.rb +40 -0
- data/lib/mu/client.rb +31 -0
- data/lib/mu/command.rb +28 -0
- data/lib/mu/command/api.rb +95 -0
- data/lib/mu/command/cmd_appid.rb +486 -0
- data/lib/mu/command/cmd_cli.rb +151 -0
- data/lib/mu/command/cmd_ddt.rb +449 -0
- data/lib/mu/command/cmd_homepage.rb +146 -0
- data/lib/mu/command/cmd_muapi.rb +361 -0
- data/lib/mu/command/cmd_netconfig.rb +262 -0
- data/lib/mu/command/cmd_runscale.rb +533 -0
- data/lib/mu/command/cmd_runscenario.rb +258 -0
- data/lib/mu/command/cmd_runverify.rb +336 -0
- data/lib/mu/command/cmd_scale.rb +333 -0
- data/lib/mu/command/cmd_system.rb +127 -0
- data/lib/mu/command/curl.rb +246 -0
- data/lib/mu/command/help.rb +29 -0
- data/lib/mu/curl/error.rb +54 -0
- data/lib/mu/curl/verify.rb +137 -0
- data/lib/mu/helper.rb +55 -0
- data/lib/mu/http_helper.rb +232 -0
- data/rdoc/classes/Mu.html +305 -0
- data/rdoc/classes/Mu/Client.html +265 -0
- data/rdoc/classes/Mu/Command.html +208 -0
- data/rdoc/classes/Mu/Command/API.html +524 -0
- data/rdoc/classes/Mu/Command/Cmd_appid.html +934 -0
- data/rdoc/classes/Mu/Command/Cmd_cli.html +515 -0
- data/rdoc/classes/Mu/Command/Cmd_ddt.html +1169 -0
- data/rdoc/classes/Mu/Command/Cmd_homepage.html +489 -0
- data/rdoc/classes/Mu/Command/Cmd_muapi.html +968 -0
- data/rdoc/classes/Mu/Command/Cmd_netconfig.html +743 -0
- data/rdoc/classes/Mu/Command/Cmd_runscale.html +970 -0
- data/rdoc/classes/Mu/Command/Cmd_runscenario.html +530 -0
- data/rdoc/classes/Mu/Command/Cmd_runverify.html +621 -0
- data/rdoc/classes/Mu/Command/Cmd_scale.html +939 -0
- data/rdoc/classes/Mu/Command/Cmd_system.html +426 -0
- data/rdoc/classes/Mu/Command/Curl.html +524 -0
- data/rdoc/classes/Mu/Command/Help.html +166 -0
- data/rdoc/classes/Mu/Curl.html +116 -0
- data/rdoc/classes/Mu/Curl/Error.html +157 -0
- data/rdoc/classes/Mu/Curl/Error/Authorize.html +178 -0
- data/rdoc/classes/Mu/Curl/Error/Connect.html +149 -0
- data/rdoc/classes/Mu/Curl/Error/DNS.html +113 -0
- data/rdoc/classes/Mu/Curl/Error/Region.html +160 -0
- data/rdoc/classes/Mu/Curl/Error/Status.html +149 -0
- data/rdoc/classes/Mu/Curl/Error/Timeout.html +149 -0
- data/rdoc/classes/Mu/Curl/Verify.html +282 -0
- data/rdoc/classes/Mu/Curl/Verify/Request.html +227 -0
- data/rdoc/classes/Mu/Curl/Verify/Response.html +187 -0
- data/rdoc/classes/Mu/Curl/Verify/Result.html +188 -0
- data/rdoc/classes/Mu/Ddt.html +914 -0
- data/rdoc/classes/Mu/Helper.html +308 -0
- data/rdoc/classes/Mu/Homepage.html +377 -0
- data/rdoc/classes/Mu/HttpHelper.html +639 -0
- data/rdoc/classes/Mu/Muapi.html +816 -0
- data/rdoc/classes/Mu/Netconfig.html +781 -0
- data/rdoc/classes/Mu/Scale.html +832 -0
- data/rdoc/classes/Mu/System.html +281 -0
- data/rdoc/classes/Object.html +148 -0
- data/rdoc/classes/TCTestMu.html +1793 -0
- data/rdoc/classes/Test.html +107 -0
- data/rdoc/classes/Test/Unit.html +107 -0
- data/rdoc/classes/Test/Unit/TestCase.html +113 -0
- data/rdoc/created.rid +1 -0
- data/rdoc/files/lib/mu/api/ddt_rb.html +101 -0
- data/rdoc/files/lib/mu/api/homepage_rb.html +101 -0
- data/rdoc/files/lib/mu/api/muapi_rb.html +101 -0
- data/rdoc/files/lib/mu/api/netconfig_rb.html +101 -0
- data/rdoc/files/lib/mu/api/scale_rb.html +101 -0
- data/rdoc/files/lib/mu/api/system_rb.html +101 -0
- data/rdoc/files/lib/mu/client_rb.html +101 -0
- data/rdoc/files/lib/mu/command/api_rb.html +101 -0
- data/rdoc/files/lib/mu/command/cmd_appid_rb.html +119 -0
- data/rdoc/files/lib/mu/command/cmd_cli_rb.html +108 -0
- data/rdoc/files/lib/mu/command/cmd_ddt_rb.html +117 -0
- data/rdoc/files/lib/mu/command/cmd_homepage_rb.html +115 -0
- data/rdoc/files/lib/mu/command/cmd_muapi_rb.html +116 -0
- data/rdoc/files/lib/mu/command/cmd_netconfig_rb.html +116 -0
- data/rdoc/files/lib/mu/command/cmd_runscale_rb.html +119 -0
- data/rdoc/files/lib/mu/command/cmd_runscenario_rb.html +115 -0
- data/rdoc/files/lib/mu/command/cmd_runverify_rb.html +117 -0
- data/rdoc/files/lib/mu/command/cmd_scale_rb.html +115 -0
- data/rdoc/files/lib/mu/command/cmd_system_rb.html +116 -0
- data/rdoc/files/lib/mu/command/curl_rb.html +101 -0
- data/rdoc/files/lib/mu/command/help_rb.html +101 -0
- data/rdoc/files/lib/mu/command_rb.html +107 -0
- data/rdoc/files/lib/mu/curl/error_rb.html +101 -0
- data/rdoc/files/lib/mu/curl/verify_rb.html +101 -0
- data/rdoc/files/lib/mu/helper_rb.html +101 -0
- data/rdoc/files/lib/mu/http_helper_rb.html +101 -0
- data/rdoc/files/lib/mu_rb.html +121 -0
- data/rdoc/files/test/helper_rb.html +112 -0
- data/rdoc/files/test/tc_test_mu_rb.html +111 -0
- data/rdoc/fr_class_index.html +68 -0
- data/rdoc/fr_file_index.html +55 -0
- data/rdoc/fr_method_index.html +374 -0
- data/rdoc/index.html +24 -0
- data/rdoc/rdoc-style.css +208 -0
- data/test/data/app_id_stats.csv +1 -0
- data/test/data/data_cgi.msl +94 -0
- data/test/data/data_cgi.xml +322 -0
- data/test/data/default_test.csv +3 -0
- data/test/data/ftp_with_channel.xml +1643 -0
- data/test/data/irc.xml +3837 -0
- data/test/data/scale_configuration.json +25 -0
- data/test/data/test_data_cgi_error.xml +35 -0
- data/test/helper.rb +18 -0
- data/test/tc_test_mu.rb +716 -0
- metadata +322 -0
data/lib/mu/client.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class Mu
|
|
2
|
+
class Client
|
|
3
|
+
attr_reader :mu
|
|
4
|
+
|
|
5
|
+
def initialize user, apik, host=''
|
|
6
|
+
scheme = host.index('localhost') ? 'http' : 'https'
|
|
7
|
+
@mu = RestClient::Resource.new "#{scheme}://#{host}", \
|
|
8
|
+
:headers => {
|
|
9
|
+
:x_api_user => user,
|
|
10
|
+
:x_api_key => apik,
|
|
11
|
+
:x_api_version => ::Mu::Version
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def curl data
|
|
16
|
+
JSON.parse mu['/api/1/curl'].post(data.to_json)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def login
|
|
20
|
+
JSON.parse mu['/account/login/api'].get
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def job_status job_id
|
|
24
|
+
JSON.parse mu["/api/1/jobs/#{job_id}/status"].get
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def abort_job job_id
|
|
28
|
+
JSON.parse mu["/api/1/jobs/#{job_id}/abort"].put('')
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/mu/command.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#require 'test/unit/assertions'
|
|
2
|
+
|
|
3
|
+
# The default template string contains what was sent and received. Strip
|
|
4
|
+
# these out since we don't need them
|
|
5
|
+
=begin
|
|
6
|
+
class Test::Unit::Assertions::AssertionMessage
|
|
7
|
+
alias :old_template :template
|
|
8
|
+
|
|
9
|
+
def template
|
|
10
|
+
@template_string = ''
|
|
11
|
+
@parameters = []
|
|
12
|
+
old_template
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
=end
|
|
16
|
+
|
|
17
|
+
class Mu
|
|
18
|
+
class Command
|
|
19
|
+
#include Test::Unit::Assertions
|
|
20
|
+
include Helper
|
|
21
|
+
|
|
22
|
+
@@mu_ip = ENV['MU_IP']
|
|
23
|
+
@@mu_admin_user = ENV['MU_ADMIN_USER']
|
|
24
|
+
@@mu_admin_pass = ENV['MU_ADMIN_PASS']
|
|
25
|
+
end
|
|
26
|
+
end # Mu
|
|
27
|
+
|
|
28
|
+
Dir["#{File.dirname(__FILE__)}/command/*.rb"].each { |c| require c }
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
class Mu
|
|
2
|
+
class Command
|
|
3
|
+
class API < Command
|
|
4
|
+
attr_accessor :credentials
|
|
5
|
+
|
|
6
|
+
def cmd_init argv
|
|
7
|
+
FileUtils.rm credentials_file rescue nil
|
|
8
|
+
API.client
|
|
9
|
+
|
|
10
|
+
msg "You are now ready to use mu!"
|
|
11
|
+
msg "Try mu help to learn more about the commands."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def client
|
|
15
|
+
get_credentials
|
|
16
|
+
Mu::Client.new(user, password, host)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def user
|
|
20
|
+
get_credentials
|
|
21
|
+
@credentials[0]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def password
|
|
25
|
+
get_credentials
|
|
26
|
+
@credentials[1]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def host
|
|
30
|
+
ENV['MU_IP'] || ''
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def credentials_file
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def get_credentials
|
|
37
|
+
return if @credentials
|
|
38
|
+
unless @credentials = read_credentials
|
|
39
|
+
@credentials = ask_for_credentials
|
|
40
|
+
save_credentials
|
|
41
|
+
end
|
|
42
|
+
@credentials
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def read_credentials
|
|
46
|
+
File.exists?(credentials_file) and File.read(credentials_file).split("\n")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def ask_for_credentials
|
|
50
|
+
msg "Enter your credentials."
|
|
51
|
+
print "User-ID: "
|
|
52
|
+
user = ask
|
|
53
|
+
print "API-Key: "
|
|
54
|
+
apik = ask
|
|
55
|
+
apik2 = Mu::Client.new(user, apik, host).login['api_key']
|
|
56
|
+
if not apik2
|
|
57
|
+
error "Authentication failed"
|
|
58
|
+
exit 1
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
[ user, apik2 ]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def save_credentials
|
|
65
|
+
write_credentials
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def write_credentials
|
|
69
|
+
FileUtils.mkdir_p(File.dirname(credentials_file))
|
|
70
|
+
File.open(credentials_file, 'w') do |f|
|
|
71
|
+
f.puts self.credentials
|
|
72
|
+
end
|
|
73
|
+
set_credentials_permissions
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def set_credentials_permissions
|
|
77
|
+
FileUtils.chmod 0700, File.dirname(credentials_file)
|
|
78
|
+
FileUtils.chmod 0600, credentials_file
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.instance
|
|
82
|
+
@instance ||= API.new
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.client
|
|
86
|
+
self.instance.client
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
def initialize
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
Api = API
|
|
94
|
+
end # Command
|
|
95
|
+
end # Mu
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
# runs Mu Studio multi-host app_id msl files in Studio Scale, in client/server passthrough
|
|
2
|
+
# mode, collapsing all hosts in the scenario to two. Runs either a single msl file or
|
|
3
|
+
# a directory of msl files, and has command-line options to specify the Mu parameters,
|
|
4
|
+
# the interfaces to use, and the pattern in which to run
|
|
5
|
+
require 'mu/api/scale'
|
|
6
|
+
class Mu
|
|
7
|
+
class Command
|
|
8
|
+
class Cmd_appid < Command
|
|
9
|
+
|
|
10
|
+
attr_accessor :api, :params, :hosts, :addr_indexes, :hash
|
|
11
|
+
|
|
12
|
+
# displays command-line help
|
|
13
|
+
def cmd_help argv
|
|
14
|
+
help
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# returns a boolean indicating whether the scale test is running or not
|
|
18
|
+
# * argv = command-line arguments
|
|
19
|
+
def cmd_running? argv
|
|
20
|
+
if @api.nil?
|
|
21
|
+
msg "false"
|
|
22
|
+
return
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
status = @api.status
|
|
26
|
+
if !status.nil?
|
|
27
|
+
if !status["status"].nil?
|
|
28
|
+
msg status["status"]["running"]
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
msg "false"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# runs a single Studio Scale test
|
|
36
|
+
# * argv = command-line arguments, requires a scenario (-s) argument
|
|
37
|
+
def cmd_run_file argv
|
|
38
|
+
setup argv
|
|
39
|
+
|
|
40
|
+
if not @hash['scenario']
|
|
41
|
+
raise "*** Error: scenario required, using -s option"
|
|
42
|
+
else
|
|
43
|
+
scenario = @hash['scenario']
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if !File.exists?(scenario)
|
|
47
|
+
raise "*** Error: Scenario file #{scenario} was not found"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
|
51
|
+
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
|
52
|
+
|
|
53
|
+
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
|
54
|
+
@api.configure("pattern", @cmd_line_pattern)
|
|
55
|
+
@params = {}
|
|
56
|
+
@params["msl"] = scenario
|
|
57
|
+
@params["hosts"] = @cmd_line_hosts
|
|
58
|
+
run(scenario)
|
|
59
|
+
@api.release
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# runs through a directory of msl files and executes a Studio Scale test for each one
|
|
63
|
+
# * argv = command-line arguments, require a directory (-d) argument
|
|
64
|
+
# * optional -r argument for recursive directory search (default is a flat directory)
|
|
65
|
+
def cmd_run_dir argv
|
|
66
|
+
setup argv
|
|
67
|
+
|
|
68
|
+
if not @hash['dir']
|
|
69
|
+
raise "*** Error: directory required, using -d option"
|
|
70
|
+
else
|
|
71
|
+
dir = @hash['dir']
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
|
75
|
+
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
|
76
|
+
|
|
77
|
+
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
|
78
|
+
@api.configure("pattern", @cmd_line_pattern)
|
|
79
|
+
@params = {}
|
|
80
|
+
@params["dir"] = dir
|
|
81
|
+
@params["hosts"] = @cmd_line_hosts
|
|
82
|
+
Dir.chdir(@params["dir"])
|
|
83
|
+
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
|
84
|
+
if @hash['recursive'].nil?
|
|
85
|
+
files = Dir.glob("*.msl")
|
|
86
|
+
else
|
|
87
|
+
files = Dir.glob("**/*.msl")
|
|
88
|
+
end
|
|
89
|
+
if !files.empty?
|
|
90
|
+
files.sort.each do | f |
|
|
91
|
+
run(f)
|
|
92
|
+
output_csv(f)
|
|
93
|
+
sleep 2
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
msg "no msl files found in #{dir}"
|
|
97
|
+
end
|
|
98
|
+
@api.release
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
def setup argv
|
|
104
|
+
parse_cli argv
|
|
105
|
+
@params = {}
|
|
106
|
+
|
|
107
|
+
if @hash['test']
|
|
108
|
+
@verify_only = true
|
|
109
|
+
else
|
|
110
|
+
@verify_only = false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
if not @hash['pattern']
|
|
114
|
+
@cmd_line_pattern = "{ \"iterations\": 1, \"intervals\": [ {\"iterations\":1, \"end\":100, \"start\":1, \"duration\":20 } ] }"
|
|
115
|
+
else
|
|
116
|
+
@cmd_line_pattern = @hash['pattern']
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
if not @hash['interfaces']
|
|
120
|
+
@cmd_line_hosts = "b1,b2"
|
|
121
|
+
else
|
|
122
|
+
@cmd_line_hosts = @hash['interfaces']
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
if not @hash['testset']
|
|
126
|
+
@testset = ""
|
|
127
|
+
else
|
|
128
|
+
@testset = @hash['testset']
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def run(msl)
|
|
134
|
+
if !File.exists?(msl)
|
|
135
|
+
return "file not found: #{msl}"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
@api.configure("musl", File.read(msl))
|
|
139
|
+
|
|
140
|
+
unless @testset.empty?
|
|
141
|
+
if @testset.include?("/") # assume it is the full path in this case
|
|
142
|
+
csv_file = @testset
|
|
143
|
+
else
|
|
144
|
+
csv_file = @params["dir"] + "/" + @testset
|
|
145
|
+
end
|
|
146
|
+
@api.configure("csv", File.read(csv_file))
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
set_global_hosts
|
|
150
|
+
all_hosts = get_all_hosts_from_musl(msl)
|
|
151
|
+
@hosts_config = map_all_hosts_to_json(all_hosts)
|
|
152
|
+
@api.configure("hosts", @hosts_config)
|
|
153
|
+
msg "verifying #{msl} ..."
|
|
154
|
+
response = @api.verify
|
|
155
|
+
# sleep 3
|
|
156
|
+
v = parse_verify_response(response)
|
|
157
|
+
if v.nil?
|
|
158
|
+
msg "error in verify"
|
|
159
|
+
return
|
|
160
|
+
end
|
|
161
|
+
if @verify_only
|
|
162
|
+
msg v
|
|
163
|
+
return
|
|
164
|
+
end
|
|
165
|
+
msg "starting #{msl} ..."
|
|
166
|
+
@api.start
|
|
167
|
+
start_time = Time.now.to_i
|
|
168
|
+
while true
|
|
169
|
+
sleep 5
|
|
170
|
+
status = @api.status
|
|
171
|
+
if !status.nil?
|
|
172
|
+
if !status["status"].nil?
|
|
173
|
+
if status["status"]["running"] == false
|
|
174
|
+
msg "running = #{status["status"]["running"]}", Logger::DEBUG
|
|
175
|
+
r = parse_status(status)
|
|
176
|
+
dump_status(status, msl)
|
|
177
|
+
return
|
|
178
|
+
else
|
|
179
|
+
r = parse_status(status)
|
|
180
|
+
end
|
|
181
|
+
else # status['status'].nil? ... no bonafide status was returned
|
|
182
|
+
time_now = Time.now.to_i
|
|
183
|
+
if time_now - start_time > 20
|
|
184
|
+
# puts "\nError: timing out after 20 seconds. Test had failed to start or verify"
|
|
185
|
+
break
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
ensure
|
|
191
|
+
msg "stopping #{msl} ..."
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def set_global_hosts
|
|
195
|
+
@hosts = Array.new
|
|
196
|
+
@addr_indexes = Array.new
|
|
197
|
+
hosts = @params["hosts"]
|
|
198
|
+
if !hosts.nil?
|
|
199
|
+
p = hosts.split(",")
|
|
200
|
+
p.each do | h |
|
|
201
|
+
if h.include?("-") # b1-1000,b2-1 to indicate addr_count
|
|
202
|
+
q = h.split("-")
|
|
203
|
+
@hosts << q[0]
|
|
204
|
+
@addr_indexes << q[1]
|
|
205
|
+
else # default to the 1st addr index
|
|
206
|
+
@hosts << h
|
|
207
|
+
@addr_indexes << 1
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
else
|
|
211
|
+
@hosts = ['b1','b2']
|
|
212
|
+
@addr_indexes = [1,1]
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def dump_status(status, msl)
|
|
217
|
+
filename = "app_id_status.json"
|
|
218
|
+
f = File.open(filename, "a")
|
|
219
|
+
status["filename"] = msl
|
|
220
|
+
str = JSON.pretty_generate(status)
|
|
221
|
+
f.write(",") if !File.zero?(f) # if appending, we need to insert a comma
|
|
222
|
+
f.write(str)
|
|
223
|
+
f.close
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def output_csv(msl_file)
|
|
227
|
+
filename = "app_id_stats.csv"
|
|
228
|
+
f = File.open(filename, "a")
|
|
229
|
+
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"
|
|
230
|
+
File.open(filename, 'a') {|f| f.write(doc) }
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# finds all the hosts in the musl file
|
|
234
|
+
def get_all_hosts_from_musl(msl)
|
|
235
|
+
f = IO.read(msl)
|
|
236
|
+
hosts = f.scan(/host_\d+/)
|
|
237
|
+
hosts.uniq!
|
|
238
|
+
return hosts
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# maps host_0 to the client interface
|
|
242
|
+
# maps all other hosts to the server interface
|
|
243
|
+
def map_all_hosts_to_json(hosts=[])
|
|
244
|
+
new_hosts = Array.new
|
|
245
|
+
hosts.each_with_index do | h, i |
|
|
246
|
+
if i == 0
|
|
247
|
+
new_hosts << @hosts[0] + "/*,#{@addr_indexes[0]}"
|
|
248
|
+
else
|
|
249
|
+
new_hosts << @hosts[1] + "/*,#{@addr_indexes[1]}"
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
hosts_config = {}
|
|
254
|
+
|
|
255
|
+
# assign hosts to consecutive string keys, host_0, host_1, etc ...
|
|
256
|
+
new_hosts.each_with_index do | h, i |
|
|
257
|
+
hosts_config["host_#{i}"] = h # new_hosts[i]
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# convert keys to symbols
|
|
261
|
+
new_hosts_config = {}
|
|
262
|
+
hosts_config.each_key { |k| new_hosts_config[k.to_sym] = hosts_config[k] }
|
|
263
|
+
|
|
264
|
+
return new_hosts_config
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def parse_verify_response(response)
|
|
268
|
+
if response.nil? # || response.empty?
|
|
269
|
+
msg "*** error = no response received from /verify ***\n\n"
|
|
270
|
+
return nil
|
|
271
|
+
end
|
|
272
|
+
begin
|
|
273
|
+
msg JSON.pretty_generate(response), Logger::DEBUG
|
|
274
|
+
if !response["status"].nil?
|
|
275
|
+
if response["status"]["error"] == true
|
|
276
|
+
@error = response["status"]["error"]
|
|
277
|
+
@reason = response["status"]["reason"]
|
|
278
|
+
dump_status(response)
|
|
279
|
+
msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
|
|
280
|
+
return nil
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
msg "*** verify: okay ***", Logger::DEBUG
|
|
284
|
+
return "*** verify: okay ***"
|
|
285
|
+
rescue
|
|
286
|
+
# could nbe json parse error
|
|
287
|
+
return nil
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def parse_status(status)
|
|
292
|
+
return nil if status.nil?
|
|
293
|
+
msg JSON.pretty_generate(status), Logger::DEBUG
|
|
294
|
+
@reported_volume = 0
|
|
295
|
+
if !status["status"]["error"].nil?
|
|
296
|
+
if status["status"]["error"] == true
|
|
297
|
+
@error = status["status"]["error"]
|
|
298
|
+
@reason = status["status"]["reason"]
|
|
299
|
+
# puts "*** Error = #{@error}, reason = #{@reason} ***\n\n"
|
|
300
|
+
return nil
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
@stats_summary = status["status"]["statistics"]["summary"]
|
|
305
|
+
@duration = @stats_summary["duration"]
|
|
306
|
+
@instances = @stats_summary["instances"]
|
|
307
|
+
@total_instances = @instances["total"]
|
|
308
|
+
@executed = @instances["executed"]
|
|
309
|
+
@timeouts = @instances["timeouts"]
|
|
310
|
+
@errors = @instances["errors"]
|
|
311
|
+
@asserts_failed = @stats_summary["asserts"]["failed"]
|
|
312
|
+
@server = @stats_summary["server"]
|
|
313
|
+
@server_tx_bytes = @server["tx"]["bytes"]
|
|
314
|
+
@server_tx_msgs = @server["tx"]["msgs"]
|
|
315
|
+
@server_rx_bytes = @server["rx"]["bytes"]
|
|
316
|
+
@server_rx_msgs = @server["rx"]["msgs"]
|
|
317
|
+
@client = @stats_summary["client"]
|
|
318
|
+
@client_tx_bytes = @client["tx"]["bytes"]
|
|
319
|
+
@client_tx_msgs = @client["tx"]["msgs"]
|
|
320
|
+
@client_rx_bytes = @client["rx"]["bytes"]
|
|
321
|
+
@client_rx_msgs = @client["rx"]["msgs"]
|
|
322
|
+
@scenarios = status["status"]["statistics"]["scenarios"]
|
|
323
|
+
@scenarios.each do | scenario |
|
|
324
|
+
@reported_volume = @reported_volume + scenario["volume"]
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
msg ""
|
|
328
|
+
msg "duration: #{format_float(2, @duration)}"
|
|
329
|
+
msg "concurrency: #{@reported_volume}"
|
|
330
|
+
msg "tests/sec: #{format_float(2, @executed.to_f / @duration)}" if @duration.to_i > 0
|
|
331
|
+
msg "passed: #{@executed}"
|
|
332
|
+
msg "errors: #{@errors}"
|
|
333
|
+
msg "timeouts: #{@timeouts}"
|
|
334
|
+
msg "client tx bytes/sec #{format_float(2, @client_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
|
335
|
+
msg "client tx msgs/sec #{format_float(2, @client_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
|
336
|
+
msg "client rx bytes/sec #{format_float(2, @client_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
|
337
|
+
msg "client rx msgs/sec #{format_float(2, @client_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
|
338
|
+
msg "server tx bytes/sec #{format_float(2, @server_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
|
339
|
+
msg "server tx msgs/sec #{format_float(2, @server_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
|
340
|
+
msg "server rx bytes/sec #{format_float(2, @server_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
|
341
|
+
msg "server rx msgs/sec #{format_float(2, @server_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
|
342
|
+
msg ""
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def parse_cli argv
|
|
346
|
+
@hash = Hash.new
|
|
347
|
+
while not argv.empty?
|
|
348
|
+
break if argv.first[0,1] != '-'
|
|
349
|
+
|
|
350
|
+
k = argv.shift
|
|
351
|
+
|
|
352
|
+
if [ '-c', '--csv' ].member? k
|
|
353
|
+
@hash['testset'] = shift(k, argv)
|
|
354
|
+
next
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
if [ '-d', '--dir' ].member? k
|
|
358
|
+
@hash['dir'] = shift(k, argv)
|
|
359
|
+
next
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
if [ '-i', '--interfaces' ].member? k
|
|
363
|
+
@hash['interfaces'] = shift(k, argv)
|
|
364
|
+
next
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
if [ '-h', '--help' ].member? k
|
|
368
|
+
help
|
|
369
|
+
exit
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
if [ '-m', '--mu_string' ].member? k
|
|
373
|
+
mu_string = shift(k, argv)
|
|
374
|
+
if mu_string =~ /(.+?):(.+?)@(.*)/
|
|
375
|
+
@@mu_admin_user = $1
|
|
376
|
+
@@mu_admin_pass = $2
|
|
377
|
+
@@mu_ip = $3
|
|
378
|
+
end
|
|
379
|
+
next
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
if [ '-o', '--output'].member? k
|
|
383
|
+
$stdout.reopen(shift(k, argv), "w")
|
|
384
|
+
next
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
if [ '-p', '--pattern' ].member? k
|
|
388
|
+
patterns = Array.new
|
|
389
|
+
pattern_string = shift(k, argv)
|
|
390
|
+
pstrings = pattern_string.split(",")
|
|
391
|
+
pstrings.each do | p |
|
|
392
|
+
if p =~ /(.+?)-(.+?):(.*)/ # e.g. 1-10000:60
|
|
393
|
+
start_vol = $1
|
|
394
|
+
end_vol = $2
|
|
395
|
+
duration = $3
|
|
396
|
+
patterns << "{\"iterations\":1, \"end\":#{end_vol}, \"start\":#{start_vol}, \"duration\":#{duration} }"
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
ps = "{ \"iterations\": 1, \"intervals\": ["
|
|
400
|
+
patterns.each do | p |
|
|
401
|
+
ps = ps + p + ","
|
|
402
|
+
end
|
|
403
|
+
ps = ps[0..ps.length-2] # remove final comma
|
|
404
|
+
ps = ps + "] }"
|
|
405
|
+
@hash['pattern'] = ps
|
|
406
|
+
next
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
if [ '-r', '--recursive'].member? k
|
|
410
|
+
@hash['recursive'] = true
|
|
411
|
+
next
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
if [ '-s', '--scenario' ].member? k
|
|
415
|
+
@hash['scenario'] = shift(k, argv)
|
|
416
|
+
next
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
if [ '-t', '--test' ].member? k
|
|
420
|
+
@hash['test'] = true
|
|
421
|
+
next
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
if [ '-v', '--verbose' ].member? k
|
|
425
|
+
$log.level = Logger::DEBUG
|
|
426
|
+
next
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
raise ArgumentError, "Unknown option #{k}"
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
hash
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def help
|
|
436
|
+
helps = [
|
|
437
|
+
{ :short => '-c', :long => '--csv', :value => '<string>', :help => 'name of the csv testset to run' },
|
|
438
|
+
{ :short => '-d', :long => '--dir', :value => '<string>', :help => 'directory containing msl files, required for run_dir' },
|
|
439
|
+
{ :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
|
|
440
|
+
{ :short => '-i', :long => '--interfaces', :value => '<string>', :help => 'comma-separated list of interfaces, e.g. b1,b2 or b1-1000:0,b2 for ip range and offset' },
|
|
441
|
+
{ :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
|
|
442
|
+
{ :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
|
|
443
|
+
{ :short => '-p', :long => '--pattern', :value => '<string>', :help => 'pattern in the form of comma-separated concurrency_start-end:duration strings, e.g. 1-10000:60,10000-1:30. Duration is in seconds' },
|
|
444
|
+
{ :short => '-r', :long => '--recursive', :value => '', :help => 'for run_dir, recurse through sub-directories' },
|
|
445
|
+
{ :short => '-s', :long => '--scenario', :value => '<string>', :help => 'msl file, required for run_msl' },
|
|
446
|
+
{ :short => '-t', :long => '--test', :value => '', :help => 'do verify only' },
|
|
447
|
+
{ :short => '-v', :long => '--verbose', :value => '', :help => 'set Logger::DEBUG level' }
|
|
448
|
+
]
|
|
449
|
+
|
|
450
|
+
cmds = [
|
|
451
|
+
"mu cmd_appid:help",
|
|
452
|
+
"mu cmd_appid:run_file -s <file>",
|
|
453
|
+
"mu cmd_appid:run_dir -d <dir> [-r]",
|
|
454
|
+
"mu cmd_appid:running?"
|
|
455
|
+
]
|
|
456
|
+
|
|
457
|
+
max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
|
|
458
|
+
max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
|
|
459
|
+
puts
|
|
460
|
+
puts "Usage: mu cmd_appid:<command> <options>"
|
|
461
|
+
puts
|
|
462
|
+
helps.each do |h|
|
|
463
|
+
puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
|
|
464
|
+
end
|
|
465
|
+
puts
|
|
466
|
+
puts "Available Commands"
|
|
467
|
+
puts
|
|
468
|
+
cmds.each do | c |
|
|
469
|
+
puts c
|
|
470
|
+
end
|
|
471
|
+
puts
|
|
472
|
+
puts "Outputs"
|
|
473
|
+
puts
|
|
474
|
+
puts "app_id_stats.csv"
|
|
475
|
+
puts "scenario_name , passed , errors , timeouts,"
|
|
476
|
+
puts "client tx bytes/sec , client tx msgs/sec , client rx bytes/sec , client rx msgs/src,"
|
|
477
|
+
puts "server tx bytes/sec , server tx msgs/sec , server rx bytes/sec , server rx msgs/src"
|
|
478
|
+
puts
|
|
479
|
+
puts "app_id_status.json"
|
|
480
|
+
puts "contains the last status json object returned from polling, per scenario"
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
end
|
|
484
|
+
end # Command
|
|
485
|
+
end # Mu
|
|
486
|
+
|