solutious-stella 0.5.5 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +39 -2
- data/LICENSE.txt +19 -0
- data/README.rdoc +85 -0
- data/Rakefile +54 -59
- data/bin/example_test.rb +82 -0
- data/bin/example_webapp.rb +63 -0
- data/lib/{stella/logger.rb → logger.rb} +6 -11
- data/lib/stella.rb +76 -58
- data/lib/stella/clients.rb +161 -0
- data/lib/stella/command/base.rb +4 -24
- data/lib/stella/command/form.rb +36 -0
- data/lib/stella/command/get.rb +44 -0
- data/lib/stella/common.rb +53 -0
- data/lib/stella/crypto.rb +88 -0
- data/lib/stella/data/domain.rb +2 -2
- data/lib/stella/data/http.rb +164 -36
- data/lib/stella/environment.rb +66 -0
- data/lib/stella/functest.rb +105 -0
- data/lib/stella/loadtest.rb +186 -0
- data/lib/{utils → stella}/stats.rb +16 -20
- data/lib/stella/testplan.rb +237 -0
- data/lib/stella/testrunner.rb +64 -0
- data/lib/storable.rb +280 -0
- data/lib/threadify.rb +171 -0
- data/lib/timeunits.rb +65 -0
- data/lib/util/httputil.rb +266 -0
- data/stella.gemspec +69 -0
- data/tryouts/drb/drb_test.rb +65 -0
- data/tryouts/drb/open4.rb +19 -0
- data/tryouts/drb/slave.rb +27 -0
- data/tryouts/oo_tryout.rb +30 -0
- metadata +39 -107
- data/README.textile +0 -162
- data/bin/stella +0 -12
- data/bin/stella.bat +0 -12
- data/lib/daemonize.rb +0 -56
- data/lib/pcaplet.rb +0 -180
- data/lib/stella/adapter/ab.rb +0 -337
- data/lib/stella/adapter/base.rb +0 -106
- data/lib/stella/adapter/httperf.rb +0 -305
- data/lib/stella/adapter/pcap_watcher.rb +0 -221
- data/lib/stella/adapter/proxy_watcher.rb +0 -76
- data/lib/stella/adapter/siege.rb +0 -341
- data/lib/stella/cli.rb +0 -258
- data/lib/stella/cli/agents.rb +0 -73
- data/lib/stella/cli/base.rb +0 -55
- data/lib/stella/cli/language.rb +0 -18
- data/lib/stella/cli/localtest.rb +0 -78
- data/lib/stella/cli/sysinfo.rb +0 -16
- data/lib/stella/cli/watch.rb +0 -278
- data/lib/stella/command/localtest.rb +0 -358
- data/lib/stella/response.rb +0 -85
- data/lib/stella/storable.rb +0 -201
- data/lib/stella/support.rb +0 -276
- data/lib/stella/sysinfo.rb +0 -257
- data/lib/stella/test/definition.rb +0 -79
- data/lib/stella/test/run/summary.rb +0 -70
- data/lib/stella/test/stats.rb +0 -114
- data/lib/stella/text.rb +0 -64
- data/lib/stella/text/resource.rb +0 -38
- data/lib/utils/crypto-key.rb +0 -84
- data/lib/utils/domainutil.rb +0 -47
- data/lib/utils/escape.rb +0 -302
- data/lib/utils/fileutil.rb +0 -78
- data/lib/utils/httputil.rb +0 -266
- data/lib/utils/mathutil.rb +0 -15
- data/lib/utils/textgraph.rb +0 -267
- data/lib/utils/timerutil.rb +0 -58
- data/lib/win32/Console.rb +0 -970
- data/lib/win32/Console/ANSI.rb +0 -305
- data/support/kvm.h +0 -91
- data/support/ruby-pcap-takuma-notes.txt +0 -19
- data/support/ruby-pcap-takuma-patch.txt +0 -30
- data/support/text/en.yaml +0 -80
- data/support/text/nl.yaml +0 -7
- data/support/useragents.txt +0 -75
- data/tests/01-util_test.rb +0 -0
- data/tests/02-stella-util_test.rb +0 -42
- data/tests/10-stella_test.rb +0 -104
- data/tests/11-stella-storable_test.rb +0 -68
- data/tests/60-stella-command_test.rb +0 -248
- data/tests/80-stella-cli_test.rb +0 -45
- data/tests/spec-helper.rb +0 -31
@@ -1,76 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'webrick/httpproxy'
|
3
|
-
require 'observer'
|
4
|
-
|
5
|
-
|
6
|
-
module Stella
|
7
|
-
module Adapter
|
8
|
-
|
9
|
-
# Stella::Adapter::ProxyWatcher
|
10
|
-
#
|
11
|
-
# Starts up an HTTP proxy using WEBrick to record HTTP events. This is used
|
12
|
-
# when PcapRecorder is not available.
|
13
|
-
class ProxyWatcher
|
14
|
-
include Observable
|
15
|
-
|
16
|
-
attr_accessor :port
|
17
|
-
|
18
|
-
def initialize(options={})
|
19
|
-
@port = options[:port]
|
20
|
-
end
|
21
|
-
require 'pp'
|
22
|
-
def run
|
23
|
-
|
24
|
-
@server = WEBrick::HTTPProxyServer.new(
|
25
|
-
:Port => @port || 3114,
|
26
|
-
:AccessLog => [],
|
27
|
-
:ProxyContentHandler => Proc.new do |req,res|
|
28
|
-
|
29
|
-
begin
|
30
|
-
res_obj = Stella::Data::HTTPResponse.new(res.to_s)
|
31
|
-
res_obj.time = Time.now
|
32
|
-
|
33
|
-
req_obj = Stella::Data::HTTPRequest.new(req.to_s)
|
34
|
-
req_obj.time = Time.now
|
35
|
-
req_obj.client_ip = '0.0.0.0'
|
36
|
-
req_obj.server_ip = '0.0.0.0'
|
37
|
-
|
38
|
-
req_obj.response = res_obj
|
39
|
-
|
40
|
-
changed
|
41
|
-
notify_observers(:http_request, req_obj)
|
42
|
-
|
43
|
-
rescue SystemExit => ex
|
44
|
-
after
|
45
|
-
|
46
|
-
rescue Exception => ex
|
47
|
-
# There are miscellaneous errors (mostly to do with
|
48
|
-
# incorrect content-length) that we don't care about.
|
49
|
-
Stella::LOGGER.error(ex.message)
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
)
|
54
|
-
|
55
|
-
# We need to trap this INT to kill WEBrick. Unlike with Pcap,
|
56
|
-
# rescuing Interrupt doesn't work.
|
57
|
-
|
58
|
-
trap('INT') do
|
59
|
-
after
|
60
|
-
end
|
61
|
-
|
62
|
-
@server.start
|
63
|
-
after
|
64
|
-
|
65
|
-
rescue => ex
|
66
|
-
after
|
67
|
-
end
|
68
|
-
|
69
|
-
def after
|
70
|
-
delete_observers
|
71
|
-
@server.shutdown
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
data/lib/stella/adapter/siege.rb
DELETED
@@ -1,341 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module Stella
|
4
|
-
module Adapter
|
5
|
-
|
6
|
-
# SIEGE
|
7
|
-
# Usage: siege [options]
|
8
|
-
# siege [options] URL
|
9
|
-
# siege -g URL
|
10
|
-
# Options:
|
11
|
-
# -V, --version VERSION, prints version number to screen.
|
12
|
-
# -h, --help HELP, prints this section.
|
13
|
-
# -C, --config CONFIGURATION, show the current configuration.
|
14
|
-
# -v, --verbose VERBOSE, prints notification to screen.
|
15
|
-
# -g, --get GET, pull down headers from the server and display HTTP
|
16
|
-
# transaction. Great for web application debugging.
|
17
|
-
# -c, --concurrent=NUM CONCURRENT users, default is 10
|
18
|
-
# -u, --url="URL" Deprecated. Set URL as the last argument.
|
19
|
-
# -i, --internet INTERNET user simulation, hits the URLs randomly.
|
20
|
-
# -b, --benchmark BENCHMARK, signifies no delay for time testing.
|
21
|
-
# -t, --time=NUMm TIME based testing where "m" is the modifier S, M, or H
|
22
|
-
# no space between NUM and "m", ex: --time=1H, one hour test.
|
23
|
-
# -r, --reps=NUM REPS, number of times to run the test, default is 25
|
24
|
-
# -f, --file=FILE FILE, change the configuration file to file.
|
25
|
-
# -R, --rc=FILE RC, change the siegerc file to file. Overrides
|
26
|
-
# the SIEGERC environmental variable.
|
27
|
-
# -l, --log LOG, logs the transaction to PREFIX/var/siege.log
|
28
|
-
# -m, --mark="text" MARK, mark the log file with a string separator.
|
29
|
-
# -d, --delay=NUM Time DELAY, random delay between 1 and num designed
|
30
|
-
# to simulate human activity. Default value is 3
|
31
|
-
# -H, --header="text" Add a header to request (can be many)
|
32
|
-
# -A, --user-agent="text" Sets User-Agent in request
|
33
|
-
class Siege < Stella::Adapter::Base
|
34
|
-
|
35
|
-
attr_writer :reps, :concurrent, :version
|
36
|
-
attr_reader :user_agent
|
37
|
-
attr_accessor :help, :config, :verbose, :get, :log, :mark, :delay, :header
|
38
|
-
attr_accessor :rc, :file, :time, :benchmark, :internet
|
39
|
-
|
40
|
-
def initialize(options={}, arguments=[])
|
41
|
-
|
42
|
-
@name = 'siege'
|
43
|
-
@reps = 1
|
44
|
-
@concurrent = 1
|
45
|
-
@private_variables = ['private_variables', 'name', 'arguments', 'load_factor', 'working_directory', 'orig_logfile']
|
46
|
-
@load_factor = 1
|
47
|
-
|
48
|
-
@rc = File.join(ENV['HOME'] || ENV['USERPROFILE'], '.siegerc')
|
49
|
-
|
50
|
-
super(options, arguments)
|
51
|
-
|
52
|
-
# Siege won't run unless there's a siegerc file. If the default one doesn't exist
|
53
|
-
# we need to call siege.config to create it. This should only happen once.
|
54
|
-
# We use capture_output here so STDOUT and STDERR don't print to the screen.
|
55
|
-
Stella::Util.capture_output("#{@name}.config") do 'nothing' end unless File.exists? @rc
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
def error
|
61
|
-
(File.exists? stderr_path) ? FileUtil.read_file(stderr_path) : "Unknown error"
|
62
|
-
end
|
63
|
-
|
64
|
-
def version
|
65
|
-
vsn = 0
|
66
|
-
Stella::Util.capture_output("#{@name} --version") do |stdout, stderr|
|
67
|
-
stderr.join.scan(/SIEGE (\d+?\.\d+)/) { |v| vsn = v[0] }
|
68
|
-
end
|
69
|
-
vsn
|
70
|
-
end
|
71
|
-
|
72
|
-
# loadtest
|
73
|
-
#
|
74
|
-
# True or false: is the call to siege a load test? If it's a call to help or version or
|
75
|
-
# to display the config this with return false. It's no reason for someone to make this
|
76
|
-
# call through Stella but it's here for goodness sake.
|
77
|
-
def loadtest?
|
78
|
-
!@arguments.empty? # The argument is a URI
|
79
|
-
end
|
80
|
-
|
81
|
-
def ready?
|
82
|
-
@name && !instance_variables.empty?
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
# Before calling run
|
87
|
-
def before
|
88
|
-
|
89
|
-
# Keep a copy of the configuration file.
|
90
|
-
copy_siegerc
|
91
|
-
|
92
|
-
# Keep a copy of the URLs file.
|
93
|
-
copy_urls_file if @file
|
94
|
-
|
95
|
-
# TODO: Print message about neither --benchmark or --internet
|
96
|
-
end
|
97
|
-
def command
|
98
|
-
raise CommandNotReady.new(self.class.to_s) unless ready?
|
99
|
-
|
100
|
-
command = "#{@name} "
|
101
|
-
|
102
|
-
instance_variables.each do |name|
|
103
|
-
canon = name.tr('@', '') # instance_variables returns '@name'
|
104
|
-
next if @private_variables.member?(canon)
|
105
|
-
|
106
|
-
# It's important that we take the value from the getter method
|
107
|
-
# because it applies the load factor.
|
108
|
-
value = self.send(canon)
|
109
|
-
if (value.is_a? Array)
|
110
|
-
value.each { |el| command << "--#{canon.tr('_', '-')} #{EscapeUtil.shell_single_word(el.to_s)} " }
|
111
|
-
else
|
112
|
-
command << "--#{canon.tr('_', '-')} #{EscapeUtil.shell_single_word(value.to_s)} "
|
113
|
-
end
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
command << (@arguments.map { |uri| "'#{uri}'" }).join(' ') unless @arguments.empty?
|
118
|
-
command
|
119
|
-
end
|
120
|
-
|
121
|
-
# After calling run
|
122
|
-
def after
|
123
|
-
|
124
|
-
update_orig_logfile if @orig_logfile
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
def process_arguments(arguments)
|
130
|
-
opts = OptionParser.new
|
131
|
-
opts.on('-V', '--version') do |v| @version = v end
|
132
|
-
opts.on('-h', '--help') do |v| @help = v end
|
133
|
-
opts.on('-C', '--config') do |v| @config = v end
|
134
|
-
opts.on('-v', '--verbose') do |v| @verbose = v end
|
135
|
-
opts.on('-g', '--get') do |v| @get = v end
|
136
|
-
opts.on('-l', '--log') do |v| @log = v end
|
137
|
-
opts.on('-m S', '--mark=S', String) do |v| @mark = v end
|
138
|
-
opts.on('-d N', '--delay=N', Float) do |v| @delay = v end
|
139
|
-
opts.on('-H S', '--header=S', String) do |v| @header ||= []; @header << v end
|
140
|
-
|
141
|
-
opts.on('-r N', '--reps=N', Integer) do |v| @reps = v.to_i end
|
142
|
-
opts.on('-c N', '--concurrent=N', Integer) do |v| @concurrent = v.to_i end
|
143
|
-
opts.on('-R S', '--rc=S', String) do |v| @rc = v end
|
144
|
-
opts.on('-f S', '--file=S', String) do |v| @file = v end
|
145
|
-
opts.on('-t S', '--time=S', String) do |v| @time = v end
|
146
|
-
opts.on('-b', '--benchmark') do |v| @benchmark = true; end
|
147
|
-
opts.on('-i', '--internet') do |v| @internet = true; end
|
148
|
-
opts.on('-A S', '--user-agent=S', String) do |v| @user_agent ||= []; @user_agent << v end
|
149
|
-
|
150
|
-
|
151
|
-
opts.on('-n N',Integer) do |v|
|
152
|
-
Stella::LOGGER.error("-n is not a Siege parameter. You probably want -r.")
|
153
|
-
exit 1
|
154
|
-
end
|
155
|
-
|
156
|
-
# parse! removes the options it finds.
|
157
|
-
# It also fails when it finds unknown switches (i.e. -X)
|
158
|
-
# Which should leave only the remaining arguments (URIs in this case)
|
159
|
-
opts.parse!(arguments)
|
160
|
-
|
161
|
-
unless @benchmark
|
162
|
-
Stella::LOGGER.warn('--benchmark (or -b) is not selected. Siege will include "think time" for all requests.')
|
163
|
-
end
|
164
|
-
|
165
|
-
self.arguments = arguments
|
166
|
-
|
167
|
-
rescue OptionParser::InvalidOption => ex
|
168
|
-
# We want to replace this text so we grab just the name of the argument
|
169
|
-
badarg = ex.message.gsub('invalid option: ', '')
|
170
|
-
raise InvalidArgument.new(badarg)
|
171
|
-
end
|
172
|
-
|
173
|
-
|
174
|
-
def add_header(name, value)
|
175
|
-
@header ||= []
|
176
|
-
@header << "#{name}: #{value}"
|
177
|
-
end
|
178
|
-
def user_agent=(list=[])
|
179
|
-
return unless list && !list.empty?
|
180
|
-
list = list.to_ary
|
181
|
-
@user_agent ||= []
|
182
|
-
@user_agent << list
|
183
|
-
@user_agent.flatten
|
184
|
-
end
|
185
|
-
|
186
|
-
def vusers
|
187
|
-
concurrent || 0
|
188
|
-
end
|
189
|
-
def vusers=(v)
|
190
|
-
@concurrent = v
|
191
|
-
end
|
192
|
-
def requests
|
193
|
-
(@reps * concurrent_f).to_i
|
194
|
-
end
|
195
|
-
def requests=(v)
|
196
|
-
@reps = (v / concurrent_f).to_i
|
197
|
-
end
|
198
|
-
def vuser_requests
|
199
|
-
@reps
|
200
|
-
end
|
201
|
-
|
202
|
-
def concurrent
|
203
|
-
(@concurrent * @load_factor).to_i
|
204
|
-
end
|
205
|
-
def concurrent_f
|
206
|
-
(@concurrent * @load_factor).to_f
|
207
|
-
end
|
208
|
-
def reps
|
209
|
-
@reps
|
210
|
-
end
|
211
|
-
|
212
|
-
|
213
|
-
# Take the last line of the siege.log file and write it to the log file
|
214
|
-
# specified by the user. We don't this so running with Stella is
|
215
|
-
# identical to running it standalone
|
216
|
-
def update_orig_logfile
|
217
|
-
|
218
|
-
return unless (@orig_logfile)
|
219
|
-
log_str = FileUtil.read_file_to_array(log_file) || ''
|
220
|
-
return if log_str.empty?
|
221
|
-
|
222
|
-
if File.exists?(@orig_logfile)
|
223
|
-
FileUtil.append_file(@orig_logfile, log_str[-1], true)
|
224
|
-
else
|
225
|
-
FileUtil.write_file(@orig_logfile, log_str.join(''), true)
|
226
|
-
end
|
227
|
-
|
228
|
-
end
|
229
|
-
|
230
|
-
# We want to keep a copy of the configuration file and also
|
231
|
-
# modify it a little bit to make sure we get all the mad info from siege
|
232
|
-
def copy_siegerc
|
233
|
-
|
234
|
-
# Read in the siegerc file so we can manipulate it
|
235
|
-
siegerc_str = FileUtil.read_file(File.expand_path(@rc))
|
236
|
-
|
237
|
-
siegerc_vars = {
|
238
|
-
:verbose => [false, true], # We want to maximize the data output by siege
|
239
|
-
:logging => [false, true],
|
240
|
-
:csv => [false, true]
|
241
|
-
}
|
242
|
-
|
243
|
-
#if (@agent)
|
244
|
-
# siegerc_vars['user-agent'] = ['.*', 'dogs2']
|
245
|
-
#end
|
246
|
-
|
247
|
-
# We'll set the variables in the siegerc file
|
248
|
-
siegerc_vars.each_pair do |var,value|
|
249
|
-
siegerc_str.gsub!(/#{var}\s*=\s*#{value[0]}/, "#{var} = #{value[1]}") # make true
|
250
|
-
siegerc_str.gsub!(/^\#+\s*#{var}/, "#{var}") # remove comment
|
251
|
-
end
|
252
|
-
|
253
|
-
# Look for the enabled logile path
|
254
|
-
# We will use this later to update it from the last line in our copy
|
255
|
-
siegerc_str =~ /^\s*logfile\s*=\s*(.+?)$/
|
256
|
-
@orig_logfile = $1 || nil
|
257
|
-
|
258
|
-
# Replace all environment variables with literal values
|
259
|
-
@orig_logfile.gsub!(/\$\{#{$1}\}/, ENV[$1]) while (@orig_logfile =~ /\$\{(.+?)\}/ && ENV.has_key?($1))
|
260
|
-
|
261
|
-
@orig_logfile = File.expand_path(@orig_logfile) if @orig_logfile
|
262
|
-
|
263
|
-
|
264
|
-
siegerc_str.gsub!(/^\#*\s*logfile\s*=\s*.*?$/, "logfile = " + log_file)
|
265
|
-
|
266
|
-
FileUtil.write_file(rc_file, siegerc_str, true)
|
267
|
-
@rc = rc_file
|
268
|
-
end
|
269
|
-
|
270
|
-
# We want to keep a copy of the URLs file too
|
271
|
-
def copy_urls_file
|
272
|
-
if @file
|
273
|
-
File.copy(File.expand_path(@file), uris_file)
|
274
|
-
@file = uris_file
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
# Siege writes the summary to STDERR
|
279
|
-
def summary_file
|
280
|
-
File.new(stderr_path) if File.exists?(stderr_path)
|
281
|
-
end
|
282
|
-
|
283
|
-
def rc_file
|
284
|
-
File.join(@working_directory, "siegerc")
|
285
|
-
end
|
286
|
-
|
287
|
-
def log_file
|
288
|
-
File.join(@working_directory, "siege.log")
|
289
|
-
end
|
290
|
-
|
291
|
-
def uris_file
|
292
|
-
File.join(@working_directory, File.basename(@file))
|
293
|
-
end
|
294
|
-
|
295
|
-
def summary
|
296
|
-
return unless summary_file
|
297
|
-
raw = {}
|
298
|
-
summary_file.each_line { |l|
|
299
|
-
l.chomp!
|
300
|
-
nvpair = l.split(':')
|
301
|
-
next unless nvpair && nvpair.size == 2
|
302
|
-
n = nvpair[0].strip.tr(' ', '_').downcase[/\w+/]
|
303
|
-
v = nvpair[1].strip[/[\.\d]+/]
|
304
|
-
raw[n.to_sym] = v.to_f
|
305
|
-
}
|
306
|
-
|
307
|
-
stats = Stella::Test::Run::Summary.new
|
308
|
-
|
309
|
-
# Transactions: 750 hits
|
310
|
-
# Availability: 100.00 %
|
311
|
-
# Elapsed time: 2.33 secs
|
312
|
-
# Data transferred: 0.07 MB
|
313
|
-
# Response time: 0.21 secs
|
314
|
-
# Transaction rate: 321.89 trans/sec
|
315
|
-
# Throughput: 0.03 MB/sec
|
316
|
-
# Concurrency: 67.49
|
317
|
-
# Successful transactions: 750
|
318
|
-
# Failed transactions: 0
|
319
|
-
# Longest transaction: 0.33
|
320
|
-
# Shortest transaction: 0.10
|
321
|
-
|
322
|
-
stats.vusers = raw[:concurrency]
|
323
|
-
stats.data_transferred = raw[:data_transferred]
|
324
|
-
stats.elapsed_time = raw[:elapsed_time]
|
325
|
-
stats.response_time = raw[:response_time]
|
326
|
-
stats.transactions = raw[:transactions].to_i
|
327
|
-
stats.transaction_rate = raw[:transaction_rate]
|
328
|
-
stats.failed = raw[:failed_transactions].to_i
|
329
|
-
stats.successful = raw[:successful_transactions].to_i
|
330
|
-
|
331
|
-
#stats.shortest_transaction = raw[:shortest_transaction]
|
332
|
-
#stats.longest_transaction = raw[:longest_transaction]
|
333
|
-
|
334
|
-
stats
|
335
|
-
end
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
end
|
340
|
-
end
|
341
|
-
end
|
data/lib/stella/cli.rb
DELETED
@@ -1,258 +0,0 @@
|
|
1
|
-
|
2
|
-
# http://www.ruby-doc.org/stdlib/libdoc/observer/rdoc/index.html
|
3
|
-
|
4
|
-
|
5
|
-
require 'stella/cli/base'
|
6
|
-
|
7
|
-
module Stella
|
8
|
-
|
9
|
-
|
10
|
-
# Stella::CLI
|
11
|
-
#
|
12
|
-
# The is the front-end class for the command-line implementation. The stella script
|
13
|
-
# creates an instance of this class which is the glue between the command-line
|
14
|
-
# and the Stella command classes.
|
15
|
-
# Note: All Stella::CLI classes are autoloaded and they add themselves to @@commands.
|
16
|
-
class CLI
|
17
|
-
|
18
|
-
# Auto populated with 'command' => Stella::CLI::[class] by each cli class on 'require'.
|
19
|
-
@@commands = {}
|
20
|
-
|
21
|
-
attr_reader :command_name
|
22
|
-
attr_reader :options
|
23
|
-
attr_reader :logger
|
24
|
-
attr_reader :stella_arguments
|
25
|
-
attr_reader :command_arguments
|
26
|
-
|
27
|
-
|
28
|
-
def initialize(arguments=[], stdin=nil)
|
29
|
-
@arguments = arguments
|
30
|
-
@stdin = stdin
|
31
|
-
|
32
|
-
@options = OpenStruct.new
|
33
|
-
@options.verbose = 0
|
34
|
-
@options.data_path = 'stella'
|
35
|
-
@options.agents = []
|
36
|
-
|
37
|
-
@stella_arguments = []
|
38
|
-
@command_arguments = []
|
39
|
-
|
40
|
-
process_arguments
|
41
|
-
process_options
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
def commands
|
46
|
-
@@commands
|
47
|
-
end
|
48
|
-
|
49
|
-
def run
|
50
|
-
|
51
|
-
unless (@command_name)
|
52
|
-
process_options(:display)
|
53
|
-
exit 0
|
54
|
-
end
|
55
|
-
|
56
|
-
# Pull the requested command object out of the list
|
57
|
-
# and tell it what shortname that was used to call it.
|
58
|
-
command = @@commands[@command_name].new(@command_name)
|
59
|
-
|
60
|
-
# Give the command object access to the runtime options and arguments
|
61
|
-
command.stella_options = @options
|
62
|
-
command.arguments = @command_arguments
|
63
|
-
command.working_directory = @options.data_path
|
64
|
-
|
65
|
-
command.run
|
66
|
-
|
67
|
-
rescue => ex
|
68
|
-
Stella::LOGGER.error(ex)
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
protected
|
73
|
-
|
74
|
-
|
75
|
-
# process_arguments
|
76
|
-
#
|
77
|
-
# Split the arguments into stella args and command args
|
78
|
-
# i.e. stella -H push -f (-H is a stella arg, -f is a command arg)
|
79
|
-
# True if required arguments were provided
|
80
|
-
def process_arguments
|
81
|
-
|
82
|
-
@command_name = nil
|
83
|
-
@arguments.each do |arg|
|
84
|
-
if (@@commands.has_key? arg)
|
85
|
-
@command_name = arg
|
86
|
-
index = @arguments.index(@command_name)
|
87
|
-
@command_arguments = @arguments[index + 1..@arguments.size]
|
88
|
-
@stella_arguments = @arguments[0..index - 1] if index > 0
|
89
|
-
break
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
@stella_arguments = [] unless @stella_arguments
|
94
|
-
@command_arguments = [] unless @command_arguments
|
95
|
-
|
96
|
-
# If there's no command we'll assume all the options are for Stella
|
97
|
-
unless @command_name
|
98
|
-
@stella_arguments = @arguments
|
99
|
-
@arguments = []
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
# process_options
|
105
|
-
#
|
106
|
-
# Handle the command-line options for stella. Note: The command specific
|
107
|
-
# options are handled by the command/*.rb classes
|
108
|
-
# display:: When true, it'll print out the options and not parse the arguments
|
109
|
-
def process_options(display=false)
|
110
|
-
|
111
|
-
opts = OptionParser.new
|
112
|
-
opts.banner = Stella::TEXT.msg(:option_help_usage)
|
113
|
-
opts.on Stella::TEXT.msg(:option_help_preamble, @@commands.keys.sort.join(', '))
|
114
|
-
|
115
|
-
opts.on(Stella::TEXT.msg(:option_help_options_title))
|
116
|
-
opts.on('-V', '--version', Stella::TEXT.msg(:option_help_version)) do
|
117
|
-
output_version
|
118
|
-
exit 0
|
119
|
-
end
|
120
|
-
opts.on('-h', '--help', Stella::TEXT.msg(:option_help_help)) { puts opts; exit 0 }
|
121
|
-
opts.on('-F', '--force', Stella::TEXT.msg(:option_help_force)) { |v| @options.force = true }
|
122
|
-
|
123
|
-
opts.on('-v', '--verbose', Stella::TEXT.msg(:option_help_verbose)) do
|
124
|
-
|
125
|
-
@options.verbose ||= 0
|
126
|
-
@options.verbose += 1
|
127
|
-
end
|
128
|
-
opts.on('-q', '--quiet', Stella::TEXT.msg(:option_help_quiet)) do
|
129
|
-
@options.quiet = true
|
130
|
-
end
|
131
|
-
|
132
|
-
# Overhead is interesting for development and auditing but we're not
|
133
|
-
# currently tracking this. It needed to be re-implemented from scratch
|
134
|
-
# so we'll redo this soon. It's also useful for comparing Ruby/JRuby/IronRuby
|
135
|
-
#opts.on('--overhead', String, Stella::TEXT.msg(:option_help_overhead)) do
|
136
|
-
# @options.showoverhead = true
|
137
|
-
#end
|
138
|
-
|
139
|
-
opts.on('-O', '--stdout', Stella::TEXT.msg(:option_help_stdout)) do
|
140
|
-
@options.stdout = true
|
141
|
-
end
|
142
|
-
opts.on('-E', '--stderr', Stella::TEXT.msg(:option_help_stderr)) do
|
143
|
-
@options.stdout = true
|
144
|
-
end
|
145
|
-
|
146
|
-
opts.on('-m', '--message=M', String, Stella::TEXT.msg(:option_help_message)) do |v|
|
147
|
-
@options.message = v.to_s
|
148
|
-
end
|
149
|
-
opts.on('-s', '--sleep=N', Float, Stella::TEXT.msg(:option_help_sleep)) do |v|
|
150
|
-
@options.sleep = v.to_f
|
151
|
-
end
|
152
|
-
|
153
|
-
# Ramp up, establish default and enforce limits
|
154
|
-
opts.on('-r [R,U]', '--rampup', String, Stella::TEXT.msg(:option_help_rampup)) do |v|
|
155
|
-
amount = (v) ? Stella::Util::expand_str(v) : [10,100]
|
156
|
-
amount[0] = MathUtil.enforce_limit(amount[0].to_i, 1, 100)
|
157
|
-
amount[1] = MathUtil.enforce_limit((amount[1]) ? amount[1].to_i : 0, (amount[0]*2), 1000)
|
158
|
-
@options.rampup = amount
|
159
|
-
end
|
160
|
-
|
161
|
-
opts.on('-x', '--repetitions=N', Integer, Stella::TEXT.msg(:option_help_testreps)) do |v|
|
162
|
-
@options.repetitions = MathUtil.enforce_limit(v,1,99)
|
163
|
-
end
|
164
|
-
|
165
|
-
opts.on('-w [N]', '--warmup', Float, Stella::TEXT.msg(:option_help_warmup, 0.1)) do |v|
|
166
|
-
@options.warmup = MathUtil.enforce_limit(((v) ? v : 0), 0.1, 1)
|
167
|
-
end
|
168
|
-
|
169
|
-
opts.on('-a', '--agent=[S]', String, Stella::TEXT.msg(:option_help_agent)) do |v|
|
170
|
-
@options.agents ||= []
|
171
|
-
agent_ary = Stella::Util::expand_str(v || 'random')
|
172
|
-
@options.agents.push(agent_ary)
|
173
|
-
end
|
174
|
-
|
175
|
-
opts.on('-d', '--datapath=S', String, Stella::TEXT.msg(:option_help_datapath, ".#{File::SEPARATOR}stella")) do |v|
|
176
|
-
@options.data_path = v.to_s
|
177
|
-
end
|
178
|
-
opts.on('-f', '--format=S', String, Stella::TEXT.msg(:option_help_format)) do |v|
|
179
|
-
@options.format = v.to_s
|
180
|
-
end
|
181
|
-
|
182
|
-
# This is used for printing the help from other parts of this class
|
183
|
-
if display
|
184
|
-
Stella::LOGGER.info opts
|
185
|
-
return
|
186
|
-
end
|
187
|
-
|
188
|
-
# This applies the configuration above to the arguments provided.
|
189
|
-
# It also removes the discovered options from @stella_arguments
|
190
|
-
# leaving only the unnamed arguments.
|
191
|
-
opts.parse!(@stella_arguments)
|
192
|
-
|
193
|
-
# Quiet supercedes verbose
|
194
|
-
@options.verbose = 0 if @options.quiet
|
195
|
-
|
196
|
-
|
197
|
-
# This outputs when debugging is enabled.
|
198
|
-
dump_inputs
|
199
|
-
|
200
|
-
|
201
|
-
rescue OptionParser::InvalidOption => ex
|
202
|
-
# We want to replace this text so we grab just the name of the argument
|
203
|
-
badarg = ex.message.gsub('invalid option: ', '')
|
204
|
-
raise InvalidArgument.new(badarg)
|
205
|
-
end
|
206
|
-
|
207
|
-
#
|
208
|
-
# Process data sent to STDIN (a pipe for example).
|
209
|
-
# We assume each line is a URI and add it to @arguments.
|
210
|
-
def process_standard_input
|
211
|
-
return if @stdin.tty? # We only want piped data
|
212
|
-
|
213
|
-
while !@stdin.eof? do
|
214
|
-
line = @stdin.readline
|
215
|
-
line.chomp!
|
216
|
-
@arguments << line
|
217
|
-
end
|
218
|
-
|
219
|
-
end
|
220
|
-
|
221
|
-
def output_version
|
222
|
-
Stella::LOGGER.info(:cli_print_version, Stella::VERSION.to_s)
|
223
|
-
end
|
224
|
-
|
225
|
-
def dump_inputs
|
226
|
-
|
227
|
-
#ENV.each_pair do |n,v|
|
228
|
-
# Stella::LOGGER.debug("ENV[#{n}]=#{v}")
|
229
|
-
#end
|
230
|
-
|
231
|
-
Stella::LOGGER.debug("Commands (#{@command_name}): #{@@commands.keys.join(',')}")
|
232
|
-
|
233
|
-
|
234
|
-
Stella::LOGGER.debug("Options: ")
|
235
|
-
@options.marshal_dump.each_pair do |n,v|
|
236
|
-
v = [v] unless v.is_a? Array
|
237
|
-
Stella::LOGGER.debug(" #{n} = #{v.join(',')}")
|
238
|
-
end
|
239
|
-
|
240
|
-
Stella::LOGGER.debug("Stella Arguments: #{@stella_arguments.join(',')}")
|
241
|
-
Stella::LOGGER.debug("Command Arguments: #{@command_arguments.join(',')}" )
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
# Autoload CLI classes. These classes add themselves to the class variable @@commands.
|
247
|
-
begin
|
248
|
-
previous_path = ""
|
249
|
-
cli_classes = Dir.glob(File.join(STELLA_HOME, 'lib', 'stella', 'cli', "*.rb"))
|
250
|
-
cli_classes.each do |path|
|
251
|
-
previous_path = path
|
252
|
-
require path
|
253
|
-
end
|
254
|
-
rescue LoadError => ex
|
255
|
-
Stella::LOGGER.info("Error loading #{previous_path}: #{ex.message}")
|
256
|
-
end
|
257
|
-
|
258
|
-
|