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.
Files changed (117) hide show
  1. data/Mu_Gem.html +1591 -0
  2. data/bin/mu +11 -0
  3. data/lib/mu.rb +65 -0
  4. data/lib/mu/api/ddt.rb +233 -0
  5. data/lib/mu/api/homepage.rb +54 -0
  6. data/lib/mu/api/muapi.rb +231 -0
  7. data/lib/mu/api/netconfig.rb +233 -0
  8. data/lib/mu/api/scale.rb +199 -0
  9. data/lib/mu/api/system.rb +40 -0
  10. data/lib/mu/client.rb +31 -0
  11. data/lib/mu/command.rb +28 -0
  12. data/lib/mu/command/api.rb +95 -0
  13. data/lib/mu/command/cmd_appid.rb +486 -0
  14. data/lib/mu/command/cmd_cli.rb +151 -0
  15. data/lib/mu/command/cmd_ddt.rb +449 -0
  16. data/lib/mu/command/cmd_homepage.rb +146 -0
  17. data/lib/mu/command/cmd_muapi.rb +361 -0
  18. data/lib/mu/command/cmd_netconfig.rb +262 -0
  19. data/lib/mu/command/cmd_runscale.rb +533 -0
  20. data/lib/mu/command/cmd_runscenario.rb +258 -0
  21. data/lib/mu/command/cmd_runverify.rb +336 -0
  22. data/lib/mu/command/cmd_scale.rb +333 -0
  23. data/lib/mu/command/cmd_system.rb +127 -0
  24. data/lib/mu/command/curl.rb +246 -0
  25. data/lib/mu/command/help.rb +29 -0
  26. data/lib/mu/curl/error.rb +54 -0
  27. data/lib/mu/curl/verify.rb +137 -0
  28. data/lib/mu/helper.rb +55 -0
  29. data/lib/mu/http_helper.rb +232 -0
  30. data/rdoc/classes/Mu.html +305 -0
  31. data/rdoc/classes/Mu/Client.html +265 -0
  32. data/rdoc/classes/Mu/Command.html +208 -0
  33. data/rdoc/classes/Mu/Command/API.html +524 -0
  34. data/rdoc/classes/Mu/Command/Cmd_appid.html +934 -0
  35. data/rdoc/classes/Mu/Command/Cmd_cli.html +515 -0
  36. data/rdoc/classes/Mu/Command/Cmd_ddt.html +1169 -0
  37. data/rdoc/classes/Mu/Command/Cmd_homepage.html +489 -0
  38. data/rdoc/classes/Mu/Command/Cmd_muapi.html +968 -0
  39. data/rdoc/classes/Mu/Command/Cmd_netconfig.html +743 -0
  40. data/rdoc/classes/Mu/Command/Cmd_runscale.html +970 -0
  41. data/rdoc/classes/Mu/Command/Cmd_runscenario.html +530 -0
  42. data/rdoc/classes/Mu/Command/Cmd_runverify.html +621 -0
  43. data/rdoc/classes/Mu/Command/Cmd_scale.html +939 -0
  44. data/rdoc/classes/Mu/Command/Cmd_system.html +426 -0
  45. data/rdoc/classes/Mu/Command/Curl.html +524 -0
  46. data/rdoc/classes/Mu/Command/Help.html +166 -0
  47. data/rdoc/classes/Mu/Curl.html +116 -0
  48. data/rdoc/classes/Mu/Curl/Error.html +157 -0
  49. data/rdoc/classes/Mu/Curl/Error/Authorize.html +178 -0
  50. data/rdoc/classes/Mu/Curl/Error/Connect.html +149 -0
  51. data/rdoc/classes/Mu/Curl/Error/DNS.html +113 -0
  52. data/rdoc/classes/Mu/Curl/Error/Region.html +160 -0
  53. data/rdoc/classes/Mu/Curl/Error/Status.html +149 -0
  54. data/rdoc/classes/Mu/Curl/Error/Timeout.html +149 -0
  55. data/rdoc/classes/Mu/Curl/Verify.html +282 -0
  56. data/rdoc/classes/Mu/Curl/Verify/Request.html +227 -0
  57. data/rdoc/classes/Mu/Curl/Verify/Response.html +187 -0
  58. data/rdoc/classes/Mu/Curl/Verify/Result.html +188 -0
  59. data/rdoc/classes/Mu/Ddt.html +914 -0
  60. data/rdoc/classes/Mu/Helper.html +308 -0
  61. data/rdoc/classes/Mu/Homepage.html +377 -0
  62. data/rdoc/classes/Mu/HttpHelper.html +639 -0
  63. data/rdoc/classes/Mu/Muapi.html +816 -0
  64. data/rdoc/classes/Mu/Netconfig.html +781 -0
  65. data/rdoc/classes/Mu/Scale.html +832 -0
  66. data/rdoc/classes/Mu/System.html +281 -0
  67. data/rdoc/classes/Object.html +148 -0
  68. data/rdoc/classes/TCTestMu.html +1793 -0
  69. data/rdoc/classes/Test.html +107 -0
  70. data/rdoc/classes/Test/Unit.html +107 -0
  71. data/rdoc/classes/Test/Unit/TestCase.html +113 -0
  72. data/rdoc/created.rid +1 -0
  73. data/rdoc/files/lib/mu/api/ddt_rb.html +101 -0
  74. data/rdoc/files/lib/mu/api/homepage_rb.html +101 -0
  75. data/rdoc/files/lib/mu/api/muapi_rb.html +101 -0
  76. data/rdoc/files/lib/mu/api/netconfig_rb.html +101 -0
  77. data/rdoc/files/lib/mu/api/scale_rb.html +101 -0
  78. data/rdoc/files/lib/mu/api/system_rb.html +101 -0
  79. data/rdoc/files/lib/mu/client_rb.html +101 -0
  80. data/rdoc/files/lib/mu/command/api_rb.html +101 -0
  81. data/rdoc/files/lib/mu/command/cmd_appid_rb.html +119 -0
  82. data/rdoc/files/lib/mu/command/cmd_cli_rb.html +108 -0
  83. data/rdoc/files/lib/mu/command/cmd_ddt_rb.html +117 -0
  84. data/rdoc/files/lib/mu/command/cmd_homepage_rb.html +115 -0
  85. data/rdoc/files/lib/mu/command/cmd_muapi_rb.html +116 -0
  86. data/rdoc/files/lib/mu/command/cmd_netconfig_rb.html +116 -0
  87. data/rdoc/files/lib/mu/command/cmd_runscale_rb.html +119 -0
  88. data/rdoc/files/lib/mu/command/cmd_runscenario_rb.html +115 -0
  89. data/rdoc/files/lib/mu/command/cmd_runverify_rb.html +117 -0
  90. data/rdoc/files/lib/mu/command/cmd_scale_rb.html +115 -0
  91. data/rdoc/files/lib/mu/command/cmd_system_rb.html +116 -0
  92. data/rdoc/files/lib/mu/command/curl_rb.html +101 -0
  93. data/rdoc/files/lib/mu/command/help_rb.html +101 -0
  94. data/rdoc/files/lib/mu/command_rb.html +107 -0
  95. data/rdoc/files/lib/mu/curl/error_rb.html +101 -0
  96. data/rdoc/files/lib/mu/curl/verify_rb.html +101 -0
  97. data/rdoc/files/lib/mu/helper_rb.html +101 -0
  98. data/rdoc/files/lib/mu/http_helper_rb.html +101 -0
  99. data/rdoc/files/lib/mu_rb.html +121 -0
  100. data/rdoc/files/test/helper_rb.html +112 -0
  101. data/rdoc/files/test/tc_test_mu_rb.html +111 -0
  102. data/rdoc/fr_class_index.html +68 -0
  103. data/rdoc/fr_file_index.html +55 -0
  104. data/rdoc/fr_method_index.html +374 -0
  105. data/rdoc/index.html +24 -0
  106. data/rdoc/rdoc-style.css +208 -0
  107. data/test/data/app_id_stats.csv +1 -0
  108. data/test/data/data_cgi.msl +94 -0
  109. data/test/data/data_cgi.xml +322 -0
  110. data/test/data/default_test.csv +3 -0
  111. data/test/data/ftp_with_channel.xml +1643 -0
  112. data/test/data/irc.xml +3837 -0
  113. data/test/data/scale_configuration.json +25 -0
  114. data/test/data/test_data_cgi_error.xml +35 -0
  115. data/test/helper.rb +18 -0
  116. data/test/tc_test_mu.rb +716 -0
  117. metadata +322 -0
@@ -0,0 +1,262 @@
1
+ # Use these commands to access the legacy REST API for configuring Mu interfaces, network hosts, and routes
2
+ require 'mu/api/netconfig'
3
+ class Mu
4
+ class Command
5
+ class Cmd_netconfig < Command
6
+
7
+ attr_accessor :host, :username, :password, :api
8
+
9
+ # displays command-line help
10
+ def cmd_help argv
11
+ help
12
+ end
13
+
14
+ # returns a json representation of the specified element
15
+ # * argv = command-line arguments, requires an element (-e) argument, such as 'interfaces', 'hosts' or 'routes' or 'interfaces/a1' or 'hosts/dell-9'
16
+ def cmd_get argv
17
+ setup argv
18
+ e = @hash['element']
19
+ response = @api.get(e)
20
+ msg JSON.pretty_generate(response)
21
+ return response
22
+ end
23
+
24
+ # modifies a network element
25
+ # * argv = command-line arguments, requires a json configuration (-j) and the element (-e) to modify, such as 'interfaces', 'hosts' or 'routes' or 'interfaces/a1' or 'hosts/dell-9'
26
+ def cmd_modify argv
27
+ setup argv
28
+ json = @hash['json']
29
+ e = @hash['element']
30
+ response = @api.modify(json, e)
31
+ msg response
32
+ return response
33
+ end
34
+
35
+
36
+ # creates a new network element
37
+ # * argv = command-line arguments, requires a json configuration (-j) and the element (-e) to modify, such as 'interfaces', 'hosts' or 'routes'
38
+ def cmd_create argv
39
+ setup argv
40
+ json = @hash['json']
41
+ e = @hash['element']
42
+ response = @api.create(json, e)
43
+ msg response
44
+ return response
45
+ end
46
+
47
+ # deletes an existing network element
48
+ # * argv = command-line arguments, requires a json configuration (-j) and the element (-e) to modify, such as 'interfaces', 'hosts' or 'routes' or 'interfaces/a1' or 'hosts/dell-9'
49
+ def cmd_delete argv
50
+ setup argv
51
+ e = @hash['element']
52
+ response = @api.delete(e)
53
+ msg response
54
+ return response
55
+ end
56
+
57
+ # restores the network configuration from a file
58
+ # * argv = command-line arguments, requires a path to a json configuration file (-f) , and a boolean (-b true|false) argument indicating whether or not existing elements should be cleared
59
+ def cmd_restore argv
60
+ setup argv
61
+ filepath = @hash['filepath']
62
+ clear_existing = to_boolean(@hash['boolean'])
63
+ response = @api.restore(filepath, clear_existing)
64
+ msg response
65
+ return response
66
+ end
67
+
68
+ # clears existing network configuration hosts
69
+ # * argv = command-line arguments
70
+ def cmd_clear_hosts argv
71
+ setup argv
72
+ response = @api.clear_hosts
73
+ msg JSON.pretty_generate(response)
74
+ return response
75
+ end
76
+
77
+ # resolves network configuration hosts
78
+ # * argv = command-line arguments, requires the name (-n) of the host to resolve (determines its ip address and adds it to the network configuration)
79
+ def cmd_resolve_hosts argv
80
+ setup argv
81
+ name = @hash['name']
82
+ response = @api.resolve_hosts(name)
83
+ msg response
84
+ return response
85
+ end
86
+
87
+ # clears existing network interfaces
88
+ # * argv = command-line arguments, require the names of the interfaces to clear (-i name)
89
+ def cmd_clear_interface argv
90
+ setup argv
91
+ interface = @hash['interfaces']
92
+ response = @api.clear_interface(interface)
93
+ msg response
94
+ return response
95
+ end
96
+
97
+ # clears existing vlan configurations
98
+ # * argv = command-line arguments
99
+ def cmd_clear_vlans argv
100
+ setup argv
101
+ response = @api.clear_vlans
102
+ msg response
103
+ return response
104
+ end
105
+
106
+ # clears existing network routes
107
+ # * argv = command-line arguments
108
+ def cmd_clear_routes argv
109
+ setup argv
110
+ response = @api.clear_routes
111
+ msg response
112
+ return response
113
+ end
114
+
115
+
116
+ # saves the network configuration to a file
117
+ # * argv = command-line arguments, requires the element (-e element, such as 'interfaces', or -e all) to save, and a file name (-f) to save the settings to
118
+ def cmd_save argv
119
+ setup argv
120
+ e = @hash['elements']
121
+ filepath = @hash['filepath'] || "config.json"
122
+ response = @api.save(e, filepath)
123
+ msg response
124
+ return response
125
+ end
126
+
127
+ private
128
+
129
+ def setup argv
130
+ parse_cli argv
131
+ @host = (@@mu_ip.nil?) ? "127.0.0.1" : @@mu_ip
132
+ @username = (@@mu_admin_user.nil?) ? "admin" : @@mu_admin_user
133
+ @password = (@@mu_admin_pass.nil?) ? "admin" : @@mu_admin_pass
134
+ @response = nil
135
+ @element = "" # sticky variable will hold a default element, the last element specified
136
+ @api = Netconfig.new(@host, @username, @password)
137
+ msg "Created Netconfig API object to :#{@host}", Logger::DEBUG
138
+ end
139
+
140
+ def parse_cli argv
141
+ args = Array.new
142
+ @hash = {}
143
+ while not argv.empty?
144
+ args << argv.shift if argv.first[0,1] != '-'
145
+
146
+ k = argv.shift
147
+
148
+ if [ '-b', '--boolean' ].member? k
149
+ @hash['boolean'] = shift(k, argv)
150
+ next
151
+ end
152
+
153
+ if [ '-e', '--element' ].member? k
154
+ @hash['element'] = shift(k, argv)
155
+ next
156
+ end
157
+
158
+ if [ '-f', '--filepath' ].member? k
159
+ @hash['filepath'] = shift(k, argv)
160
+ next
161
+ end
162
+
163
+ if [ '-h', '--help' ].member? k
164
+ help
165
+ exit
166
+ end
167
+
168
+ if [ '-i', '--interfaces' ].member? k
169
+ @hash['interfaces'] = shift(k, argv)
170
+ next
171
+ end
172
+
173
+ if [ '-j', '--json' ].member? k
174
+ @hash['json'] = shift(k, argv)
175
+ next
176
+ end
177
+
178
+ if [ '-m', '--mu_string' ].member? k
179
+ mu_string = shift(k, argv)
180
+ if mu_string =~ /(.+?):(.+?)@(.*)/
181
+ @@mu_admin_user = $1
182
+ @@mu_admin_pass = $2
183
+ @@mu_ip = $3
184
+ end
185
+ next
186
+ end
187
+
188
+ if [ '-n', '--name' ].member? k
189
+ @hash['name'] = shift(k, argv)
190
+ next
191
+ end
192
+
193
+ if [ '-o', '--output' ].member? k
194
+ $stdout.reopen(shift(k, argv), "w")
195
+ next
196
+ end
197
+
198
+ if [ '-r', '--routes' ].member? k
199
+ @hash['routes'] = shift(k, argv)
200
+ next
201
+ end
202
+
203
+ if [ '-v', '--verbose' ].member? k
204
+ $log.level = Logger::DEBUG
205
+ next
206
+ end
207
+ end
208
+
209
+ args
210
+ end
211
+
212
+ def help
213
+ helps = [
214
+ { :short => '-b', :long => '--boolean', :value => '<string>', :help => 'boolean arg' },
215
+ { :short => '-e', :long => '--element', :value => '<string>', :help => 'http string' },
216
+ { :short => '-f', :long => '--filepath', :value => '<string>', :help => 'filepath' },
217
+ { :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
218
+ { :short => '-i', :long => '--interfaces', :value => '<string>', :help => 'interfaces/hosts' },
219
+ { :short => '-j', :long => '--json', :value => '<string>', :help => 'json object' },
220
+ { :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
221
+ { :short => '-n', :long => '--name', :value => '<string>', :help => 'host name' },
222
+ { :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
223
+ { :short => '-v', :long => '--verbose', :value => '', :help => 'set Logger::DEBUG level' }
224
+ ]
225
+
226
+ cmds = [
227
+ "mu cmd_netconfig:clear_hosts",
228
+ "mu cmd_netconfig:clear_interfaces -i <interfaces>",
229
+ "mu cmd_netconfig:clear_routes",
230
+ "mu cmd_netconfig:clear_vlans",
231
+ "mu cmd_netconfig:create -j <json> -e <element>",
232
+ "mu cmd_netconfig:delete -e <element>",
233
+ "mu cmd_netconfig:get -e <element>",
234
+ "mu cmd_netconfig:help",
235
+ "mu cmd_netconfig:modify -j <json> -e <element>",
236
+ "mu cmd_netconfig:resolve_hosts -n <name>",
237
+ "mu cmd_netconfig:restore -f <filepath> [-b <clear_existing>]",
238
+ "mu cmd_netconfig:save -e <element> -f <filepath>",
239
+ ]
240
+
241
+ max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
242
+ max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
243
+ puts
244
+ puts "Usage: mu cmd_netconfig <options>"
245
+ puts
246
+ helps.each do |h|
247
+ puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
248
+ end
249
+ puts
250
+ puts "Available Commands"
251
+ puts
252
+ cmds.each do | c |
253
+ puts c
254
+ end
255
+ puts
256
+ end
257
+
258
+ end
259
+ end # Command
260
+ end # Mu
261
+
262
+
@@ -0,0 +1,533 @@
1
+ # Runs Mu Studio scenario msl files in Studio Scale, requiring that all interfaces and
2
+ # hosts used in the scenario are specified on the command-line through the –i option.
3
+ # Runs either a single msl file or a directory of msl files, and has command-line options
4
+ # to specify the Mu parameters, 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_runscale < Command
9
+
10
+ attr_accessor :api, :params, :hosts, :addr_indexes, :offset_indexes
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
+
102
+ if @hash['test']
103
+ @verify_only = true
104
+ else
105
+ @verify_only = false
106
+ end
107
+
108
+ if not @hash['testset']
109
+ @testset = ""
110
+ else
111
+ @testset = @hash['testset']
112
+ end
113
+
114
+ if not @hash['pattern']
115
+ @cmd_line_pattern = "{ \"iterations\": 1, \"intervals\": [ {\"iterations\":1, \"end\":100, \"start\":1, \"duration\":20 } ] }"
116
+ else
117
+ @cmd_line_pattern = @hash['pattern']
118
+ end
119
+
120
+ if not @hash['interfaces']
121
+ @cmd_line_hosts = "b1,b2"
122
+ else
123
+ @cmd_line_hosts = @hash['interfaces']
124
+ end
125
+
126
+ end
127
+
128
+ def run(scenario)
129
+ # assume the scenario and testset files are in dir unless they contain '/'
130
+ # in which case they are assumed to be absolute paths
131
+ if scenario.include?("/")
132
+ musl_file = scenario
133
+ else
134
+ musl_file = @params["dir"] + "/" + scenario
135
+ end
136
+ # msg musl_file, Logger::DEBUG
137
+ @api.configure("musl", File.read(musl_file))
138
+
139
+ unless @testset.empty?
140
+ if @testset.include?("/")
141
+ csv_file = @testset
142
+ else
143
+ csv_file = @params["dir"] + "/" + @testset
144
+ end
145
+ @api.configure("csv", File.read(csv_file))
146
+ end
147
+
148
+ File.delete("app_id_status.json") if File.exists?("app_id_status.json")
149
+ File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
150
+
151
+ configure_hosts
152
+
153
+ msg "verifying #{scenario} ..."
154
+ response = @api.verify
155
+ msg response, Logger::DEBUG
156
+ # sleep 3
157
+ v = parse_verify_response(response)
158
+ msg "#{v}", Logger::DEBUG
159
+ if v.nil?
160
+ msg "error in verify"
161
+ return
162
+ end
163
+ if @verify_only
164
+ msg v
165
+ return
166
+ end
167
+ msg "starting #{scenario} ..."
168
+ @api.start
169
+ start_time = Time.now.to_i
170
+ while true
171
+ sleep 5
172
+ status = @api.status
173
+ if !status.nil?
174
+ if !status["status"].nil?
175
+ if status["status"]["running"] == false
176
+ msg "running = #{status["status"]["running"]}", Logger::DEBUG
177
+ r = parse_status(status)
178
+ dump_status(status, musl_file)
179
+ return
180
+ else
181
+ r = parse_status(status)
182
+ end
183
+ else # status['status'].nil? ... no bonafide status was returned
184
+ time_now = Time.now.to_i
185
+ if time_now - start_time > 20
186
+ # puts "\nError: timing out after 20 seconds. Test had failed to start or verify"
187
+ break
188
+ end
189
+ end
190
+ end
191
+ end
192
+ ensure
193
+ msg "stopping #{scenario} ..."
194
+ end
195
+
196
+ def cmd_running?
197
+ if @api.nil?
198
+ msg "false"
199
+ return
200
+ end
201
+
202
+ status = @api.status
203
+ if !status.nil?
204
+ if !status["status"].nil?
205
+ msg status["status"]["running"]
206
+ end
207
+ else
208
+ msg "false"
209
+ end
210
+ end
211
+
212
+ def configure_hosts
213
+ @hosts = Array.new
214
+ @addr_indexes = Array.new
215
+ @offset_indexes = Array.new
216
+ hosts = @params["hosts"]
217
+ if !hosts.nil?
218
+ p = hosts.split(",")
219
+ p.each do | h |
220
+ if h.include?("-") # b1-1000,b2-1 to indicate addr_count
221
+ q = h.split("-")
222
+ @hosts << q[0]
223
+ if q[1].include?(":") # -1000:20 to indicate offset within range
224
+ r = q[1].split(":")
225
+ @addr_indexes << r[0]
226
+ @offset_indexes << r[1]
227
+ else
228
+ @addr_indexes << q[1]
229
+ @offset_indexes << 1
230
+ end
231
+ else # default to the 1st addr index
232
+ @hosts << h
233
+ @addr_indexes << 1
234
+ @offset_indexes << 1
235
+ end
236
+ end
237
+ else
238
+ @hosts = ['b1','b2']
239
+ @addr_indexes = [1,1]
240
+ @offset_indexes = [1,1]
241
+ end
242
+
243
+ set_hosts_byname(@hosts, @addr_indexes, @offset_indexes)
244
+ end
245
+
246
+ def set_hosts_byname(hosts=@hosts, count=[1,1], offset=[1,1], v4=true)
247
+ new_hosts = Array.new
248
+ str = ""
249
+ hosts.each_with_index do |n, i|
250
+ if n.match(/^[ab][1-4]$/) or n.include?(".") # possible vlan
251
+ if count[i] == 1 or count[i].nil?
252
+ str = "#{n}/*"
253
+ else
254
+ str = "#{n}/*,#{count[i]},#{offset[i]}"
255
+ end
256
+ msg "using host #{str}", Logger::DEBUG
257
+ else
258
+ @net = Netconfig.new
259
+ @net.setup(@hosts, @username, @password)
260
+ if v4
261
+ addr = @net.get("hosts/#{n}")['v4_addr']
262
+ else
263
+ addr = @net.get("hosts/#{n}")['v6_addr']
264
+ end
265
+ str = "#{addr}"
266
+ msg "using host #{str}", Logger::DEBUG
267
+ end
268
+ new_hosts << str
269
+ end
270
+ set_hosts(new_hosts)
271
+ end
272
+
273
+ # expects full strings: e.g. b1/12.89.0.1 ...
274
+ def set_hosts(hosts=["b1","b2"])
275
+ host_params = {}
276
+
277
+ # assign hosts to consecutive string keys, host_0, host_1, etc ...
278
+ hosts.each_with_index do | h, i |
279
+ host_params["host_#{i}"] = hosts[i]
280
+ end
281
+
282
+ # convert keys to symbols
283
+ # host_params.each_key { |k| host_params[k.to_sym] = host_params[k] }
284
+ new_host_params = {}
285
+ host_params.each_key { |k| new_host_params[k.to_sym] = host_params[k] }
286
+
287
+ =begin
288
+ # add default host, set to host_1 if it exists, unless specified on the command-line
289
+ if @hash['default_host'].nil?
290
+ new_host_params[:default_host] = new_host_params[:host_1] unless new_host_params[:host_1].nil?
291
+ else
292
+ new_host_params[:default_host] = @hash['default_host'] if !@hash['default_host'].nil?
293
+ end
294
+ =end
295
+
296
+ @api.configure("hosts", new_host_params)
297
+
298
+ end
299
+
300
+ def dump_status(status, msl)
301
+ filename = "app_id_status.json"
302
+ f = File.open(filename, "a")
303
+ status["filename"] = msl
304
+ str = JSON.pretty_generate(status)
305
+ f.write(",") if !File.zero?(f) # if appending, we need to insert a comma
306
+ f.write(str)
307
+ f.close
308
+ end
309
+
310
+ def output_csv(msl_file)
311
+ filename = "app_id_stats.csv"
312
+ f = File.open(filename, "a")
313
+ 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"
314
+ File.open(filename, 'a') {|f| f.write(doc) }
315
+ end
316
+
317
+ def parse_verify_response(response)
318
+ if response.nil? # || response.empty?
319
+ msg "*** error = no response received from /verify ***\n\n"
320
+ return nil
321
+ end
322
+ begin
323
+ msg JSON.pretty_generate(response), Logger::DEBUG
324
+ if !response["status"].nil?
325
+ if response["status"]["error"] == true
326
+ @error = response["status"]["error"]
327
+ @reason = response["status"]["reason"]
328
+ dump_status(response)
329
+ msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
330
+ return nil
331
+ end
332
+ end
333
+ msg "*** verify: okay ***", Logger::DEBUG
334
+ return "*** verify: okay ***"
335
+ rescue => e
336
+ msg e, Logger::DEBUG
337
+ return nil
338
+ end
339
+ end
340
+
341
+ def parse_status(status)
342
+ return nil if status.nil?
343
+ @reported_volume = 0
344
+ if !status["status"]["error"].nil?
345
+ if status["status"]["error"] == true
346
+ @error = status["status"]["error"]
347
+ @reason = status["status"]["reason"]
348
+ msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
349
+ return nil
350
+ end
351
+ end
352
+
353
+ @stats_summary = status["status"]["statistics"]["summary"]
354
+ @duration = @stats_summary["duration"]
355
+ @instances = @stats_summary["instances"]
356
+ @total_instances = @instances["total"]
357
+ @executed = @instances["executed"]
358
+ @timeouts = @instances["timeouts"]
359
+ @errors = @instances["errors"]
360
+ @asserts_failed = @stats_summary["asserts"]["failed"]
361
+ @server = @stats_summary["server"]
362
+ @server_tx_bytes = @server["tx"]["bytes"]
363
+ @server_tx_msgs = @server["tx"]["msgs"]
364
+ @server_rx_bytes = @server["rx"]["bytes"]
365
+ @server_rx_msgs = @server["rx"]["msgs"]
366
+ @client = @stats_summary["client"]
367
+ @client_tx_bytes = @client["tx"]["bytes"]
368
+ @client_tx_msgs = @client["tx"]["msgs"]
369
+ @client_rx_bytes = @client["rx"]["bytes"]
370
+ @client_rx_msgs = @client["rx"]["msgs"]
371
+ @scenarios = status["status"]["statistics"]["scenarios"]
372
+ @scenarios.each do | scenario |
373
+ @reported_volume = @reported_volume + scenario["volume"]
374
+ end
375
+
376
+ msg ""
377
+ msg "duration: #{format_float(2, @duration)}"
378
+ msg "concurrency: #{@reported_volume}"
379
+ msg "tests/sec: #{format_float(2, @executed.to_f / @duration)}" if @duration.to_i > 0
380
+ msg "passed: #{@executed}"
381
+ msg "errors: #{@errors}"
382
+ msg "timeouts: #{@timeouts}"
383
+ msg "client tx bytes/sec #{format_float(2, @client_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
384
+ msg "client tx msgs/sec #{format_float(2, @client_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
385
+ msg "client rx bytes/sec #{format_float(2, @client_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
386
+ msg "client rx msgs/sec #{format_float(2, @client_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
387
+ msg "server tx bytes/sec #{format_float(2, @server_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
388
+ msg "server tx msgs/sec #{format_float(2, @server_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
389
+ msg "server rx bytes/sec #{format_float(2, @server_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
390
+ msg "server rx msgs/sec #{format_float(2, @server_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
391
+ msg ""
392
+ end
393
+
394
+ def parse_cli argv
395
+ @hash = Hash.new
396
+ while not argv.empty?
397
+ break if argv.first[0,1] != '-'
398
+
399
+ k = argv.shift
400
+
401
+ if [ '-c', '--csv' ].member? k
402
+ @hash['testset'] = shift(k, argv)
403
+ next
404
+ end
405
+
406
+ if [ '-d', '--dir' ].member? k
407
+ @hash['dir'] = shift(k, argv)
408
+ next
409
+ end
410
+
411
+ if [ '-f', '--default_host' ].member? k
412
+ @hash['default_host'] = shift(k, argv)
413
+ next
414
+ end
415
+
416
+ if [ '-i', '--interfaces' ].member? k
417
+ @hash['interfaces'] = shift(k, argv)
418
+ next
419
+ end
420
+
421
+ if [ '-h', '--help' ].member? k
422
+ help
423
+ exit
424
+ end
425
+
426
+ if [ '-m', '--mu_string' ].member? k
427
+ mu_string = shift(k, argv)
428
+ if mu_string =~ /(.+?):(.+?)@(.*)/
429
+ @@mu_admin_user = $1
430
+ @@mu_admin_pass = $2
431
+ @@mu_ip = $3
432
+ end
433
+ next
434
+ end
435
+
436
+ if [ '-o', '--output' ].member? k
437
+ $stdout.reopen(shift(k, argv), "w")
438
+ next
439
+ end
440
+
441
+ if [ '-p', '--pattern' ].member? k
442
+ patterns = Array.new
443
+ pattern_string = shift(k, argv)
444
+ pstrings = pattern_string.split(",")
445
+ pstrings.each do | p |
446
+ if p =~ /(.+?)-(.+?):(.*)/ # e.g. 1-10000:60
447
+ start_vol = $1
448
+ end_vol = $2
449
+ duration = $3
450
+ patterns << "{\"iterations\":1, \"end\":#{end_vol}, \"start\":#{start_vol}, \"duration\":#{duration} }"
451
+ end
452
+ end
453
+ ps = "{ \"iterations\": 1, \"intervals\": ["
454
+ patterns.each do | p |
455
+ ps = ps + p + ","
456
+ end
457
+ ps = ps[0..ps.length-2] # remove final comma
458
+ ps = ps + "] }"
459
+ @hash['pattern'] = ps
460
+ next
461
+ end
462
+
463
+ if [ '-r', '--recursive'].member? k
464
+ @hash['recursive'] = true
465
+ next
466
+ end
467
+
468
+
469
+ if [ '-s', '--scenario' ].member? k
470
+ @hash['scenario'] = shift(k, argv)
471
+ next
472
+ end
473
+
474
+ if [ '-t', '--test' ].member? k
475
+ @hash['test'] = true
476
+ next
477
+ end
478
+
479
+ if [ '-v', '--verbose' ].member? k
480
+ $log.level = Logger::DEBUG
481
+ next
482
+ end
483
+
484
+ raise ArgumentError, "Unknown option #{k}"
485
+ end
486
+
487
+ @hash
488
+ end
489
+
490
+ def help
491
+ helps = [
492
+ { :short => '-c', :long => '--csv', :value => '<string>', :help => 'name of the csv testset to run' },
493
+ { :short => '-d', :long => '--dir', :value => '<string>', :help => 'directory containing the scenario file' },
494
+ { :short => '-f', :long => '--default_host', :value => '<string>', :help => 'default_host setting' },
495
+ { :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
496
+ { :short => '-i', :long => '--interfaces', :value => '<string>', :help => 'comma-separated list of interfaces, e.g. b1,b2 or b1-1000,b2 for ip range' },
497
+ { :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
498
+ { :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
499
+ { :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' },
500
+ { :short => '-r', :long => '--recursive', :value => '', :help => 'for run_dir, recurse through sub-directories' },
501
+ { :short => '-s', :long => '--scenario', :value => '<string>', :help => 'scenario file to run' },
502
+ { :short => '-t', :long => '--test', :value => '', :help => 'do verify only' },
503
+ { :short => '-v', :long => '--verbose', :value => '', :help => 'set Logger::DEBUG level' }
504
+ ]
505
+
506
+ cmds = [
507
+ "mu cmd_runscale:help",
508
+ "mu cmd_runscale:run_file -s <scenario> -i <hosts, e.g. a1,dell-9> -p <pattern, e.g. 1-1000:30>",
509
+ "mu cmd_runscale:run_dir -d <scenario_directory>",
510
+ "mu cmd_runscale:running?"
511
+ ]
512
+
513
+ max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
514
+ max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
515
+ puts
516
+ puts "Usage: mu cmd_runscale:<command> <options>"
517
+ puts
518
+ helps.each do |h|
519
+ puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
520
+ end
521
+ puts
522
+ puts "Available Commands"
523
+ puts
524
+ cmds.each do | c |
525
+ puts c
526
+ end
527
+ puts
528
+ end
529
+
530
+ end
531
+ end # Command
532
+ end # Mu
533
+