solutious-stella 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/CHANGES.txt +36 -0
  2. data/README.textile +162 -0
  3. data/Rakefile +88 -0
  4. data/bin/stella +12 -0
  5. data/bin/stella.bat +12 -0
  6. data/lib/daemonize.rb +56 -0
  7. data/lib/pcaplet.rb +180 -0
  8. data/lib/stella.rb +101 -0
  9. data/lib/stella/adapter/ab.rb +337 -0
  10. data/lib/stella/adapter/base.rb +106 -0
  11. data/lib/stella/adapter/httperf.rb +305 -0
  12. data/lib/stella/adapter/pcap_watcher.rb +221 -0
  13. data/lib/stella/adapter/proxy_watcher.rb +76 -0
  14. data/lib/stella/adapter/siege.rb +341 -0
  15. data/lib/stella/cli.rb +258 -0
  16. data/lib/stella/cli/agents.rb +73 -0
  17. data/lib/stella/cli/base.rb +55 -0
  18. data/lib/stella/cli/language.rb +18 -0
  19. data/lib/stella/cli/localtest.rb +78 -0
  20. data/lib/stella/cli/sysinfo.rb +16 -0
  21. data/lib/stella/cli/watch.rb +278 -0
  22. data/lib/stella/command/base.rb +40 -0
  23. data/lib/stella/command/localtest.rb +358 -0
  24. data/lib/stella/data/domain.rb +82 -0
  25. data/lib/stella/data/http.rb +131 -0
  26. data/lib/stella/logger.rb +84 -0
  27. data/lib/stella/response.rb +85 -0
  28. data/lib/stella/storable.rb +201 -0
  29. data/lib/stella/support.rb +276 -0
  30. data/lib/stella/sysinfo.rb +257 -0
  31. data/lib/stella/test/definition.rb +79 -0
  32. data/lib/stella/test/run/summary.rb +70 -0
  33. data/lib/stella/test/stats.rb +114 -0
  34. data/lib/stella/text.rb +64 -0
  35. data/lib/stella/text/resource.rb +38 -0
  36. data/lib/utils/crypto-key.rb +84 -0
  37. data/lib/utils/domainutil.rb +47 -0
  38. data/lib/utils/escape.rb +302 -0
  39. data/lib/utils/fileutil.rb +78 -0
  40. data/lib/utils/httputil.rb +266 -0
  41. data/lib/utils/mathutil.rb +15 -0
  42. data/lib/utils/stats.rb +88 -0
  43. data/lib/utils/textgraph.rb +267 -0
  44. data/lib/utils/timerutil.rb +58 -0
  45. data/lib/win32/Console.rb +970 -0
  46. data/lib/win32/Console/ANSI.rb +305 -0
  47. data/support/kvm.h +91 -0
  48. data/support/ruby-pcap-takuma-notes.txt +19 -0
  49. data/support/ruby-pcap-takuma-patch.txt +30 -0
  50. data/support/text/en.yaml +80 -0
  51. data/support/text/nl.yaml +7 -0
  52. data/support/useragents.txt +75 -0
  53. data/tests/01-util_test.rb +0 -0
  54. data/tests/02-stella-util_test.rb +42 -0
  55. data/tests/10-stella_test.rb +104 -0
  56. data/tests/11-stella-storable_test.rb +68 -0
  57. data/tests/60-stella-command_test.rb +248 -0
  58. data/tests/80-stella-cli_test.rb +45 -0
  59. data/tests/spec-helper.rb +31 -0
  60. metadata +165 -0
@@ -0,0 +1,131 @@
1
+
2
+ require 'utils/httputil'
3
+ require 'base64'
4
+
5
+ module Stella::Data
6
+
7
+ # TODO: Implement HTTPHeaders. We should be printing untouched headers.
8
+ # HTTPUtil should split the HTTP event lines and that's it. Replace
9
+ # parse_header_body with split_header_body
10
+ class HTTPHeaders < Stella::Storable
11
+ attr_reader :raw_data
12
+
13
+ def to_s
14
+ @raw_data
15
+ end
16
+
17
+ end
18
+
19
+ class HTTPRequest < Stella::Storable
20
+ attr_reader :raw_data
21
+
22
+ field :time => DateTime
23
+ field :client_ip => String
24
+ field :server_ip => String
25
+ field :header => String
26
+ field :uri => String
27
+ field :body => String
28
+ field :method => String
29
+ field :http_version => String
30
+
31
+ def has_body?
32
+ @body && !@body.nil & !@body.empty?
33
+ end
34
+ def has_request?
35
+ false
36
+ end
37
+ def has_response?
38
+ (@response && @response.status && !@response.status.nil?)
39
+ end
40
+
41
+ def initialize(raw_data=nil)
42
+ @raw_data = raw_data
43
+ if @raw_data
44
+ @method, @http_version, @uri, @header, @body = HTTPUtil::parse_http_request(raw_data)
45
+ end
46
+ @response = Stella::Data::HTTPResponse.new
47
+ end
48
+
49
+ def uri
50
+ @uri.host = @server_ip.to_s if @uri && (@uri.host == 'unknown' || @uri.host.empty?)
51
+ @uri
52
+ end
53
+
54
+ def body
55
+ return nil unless @body
56
+ @body
57
+ #(!header || header[:Content_Type] || header[:Content_Type] !~ /text/) ? Base64.encode64(@body) : @body
58
+ end
59
+
60
+
61
+
62
+ def inspect
63
+ headers = []
64
+ header.each_pair do |n,v|
65
+ headers << "#{n.to_s.gsub('_', '-')}: #{v[0]}"
66
+ end
67
+ str = "%s %s HTTP/%s" % [method, uri.to_s, http_version]
68
+ str << $/ + headers.join($/)
69
+ str << $/ + $/ + body if body
70
+ str
71
+ end
72
+
73
+ def to_s
74
+ str = "%s: %s %s HTTP/%s" % [time.strftime(NICE_TIME_FORMAT), method, uri.to_s, http_version]
75
+ str
76
+ end
77
+
78
+ end
79
+
80
+ class HTTPResponse < Stella::Storable
81
+ attr_reader :raw_data
82
+
83
+ field :time => DateTime
84
+ field :client_ip => String
85
+ field :server_ip => String
86
+ field :header => String
87
+ field :body => String
88
+ field :status => String
89
+ field :message => String
90
+ field :http_version => String
91
+
92
+ def initialize(raw_data=nil)
93
+ @raw_data = raw_data
94
+ if @raw_data
95
+ @status, @http_version, @message, @header, @body = HTTPUtil::parse_http_response(@raw_data)
96
+ end
97
+ end
98
+
99
+ def has_body?
100
+ @body && !@body.nil & !@body.empty?
101
+ end
102
+ def has_request?
103
+ false
104
+ end
105
+ def has_response?
106
+ false
107
+ end
108
+
109
+ def body
110
+ return nil unless @body
111
+ #Base64.encode64(@body)
112
+ (!header || !header[:Content_Type] || header[:Content_Type] !~ /text/) ? '' : @body
113
+ end
114
+
115
+ def inspect
116
+ headers = []
117
+ header.each_pair do |n,v|
118
+ headers << "#{n.to_s.gsub('_', '-')}: #{v[0]}"
119
+ end
120
+ str = "HTTP/%s %s (%s)" % [@http_version, @status, @message]
121
+ str << $/ + headers.join($/)
122
+ str << $/ + $/ + body if body
123
+ str
124
+ end
125
+
126
+ def to_s
127
+ str = "%s: HTTP/%s %s (%s)" % [time.strftime(NICE_TIME_FORMAT), @http_version, @status, @message]
128
+ str
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,84 @@
1
+
2
+
3
+ module Stella
4
+ class Logger
5
+ attr_accessor :debug_level
6
+
7
+ # +args+ is a hash of initialization arguments
8
+ # * <tt>:info_logger</tt> The IO class for info level logging. Default: STDOUT
9
+ # * <tt>:error_logger</tt> The IO class for error level logging. Default: STDERR
10
+ # * <tt>:debug_logger</tt> The IO class for error level logging. Default: STDERR
11
+ # * <tt>:debug</tt> Log debugging output, true or false (default)
12
+ def initialize(args={})
13
+ @debug_level = args[:debug] || false
14
+ @info_logger = args[:info_logger]
15
+ @error_logger = args[:error_logger]
16
+ @debug_logger = args[:debug_logger]
17
+ end
18
+
19
+ # +msgs+ is an array which can contain a list of messages or a symbol and a list of values
20
+ # If the first element is a symbol, this will return the output of Stella::Text.msg(msgs[0],msgs[1..-1])
21
+ def info(*msgs)
22
+ return if !msgs || msgs.empty?
23
+ if msgs[0].is_a? Symbol
24
+ txtsym = msgs.shift
25
+ info_logger.puts Stella::TEXT.msg(txtsym, msgs)
26
+ else
27
+ msgs.each do |m|
28
+ info_logger.puts m
29
+ end
30
+ end
31
+ info_logger.flush
32
+ end
33
+
34
+ def info_logger
35
+ @info_logger || $stdout
36
+ end
37
+ def debug_logger
38
+ @debug_logger || $stderr
39
+ end
40
+ def error_logger
41
+ @error_logger || $stderr
42
+ end
43
+
44
+ def flush
45
+ info_logger.flush
46
+ error_logger.flush
47
+ debug_logger.flush
48
+ end
49
+
50
+ # Print all messages on a single line.
51
+ def info_print(*msgs)
52
+ msgs.each do |m|
53
+ info_logger.print m
54
+ end
55
+ info_logger.flush
56
+ end
57
+
58
+ # Print all messages on a single line.
59
+ def info_printf(pattern, *vals)
60
+ info_logger.printf(pattern, *vals)
61
+ info_logger.flush
62
+ end
63
+
64
+ def debug(*msgs)
65
+ return unless @debug_level
66
+ msgs.each do |m|
67
+ debug_logger.puts "DEBUG: #{m}"
68
+ end
69
+ debug_logger.flush
70
+ end
71
+ def warn(ex, prefix="WARN: ")
72
+ error(ex, prefix)
73
+ end
74
+
75
+ def error(ex, prefix="ERR: ")
76
+ msg = (ex.kind_of? String) ? ex : ex.message
77
+ error_logger.puts "#{prefix}#{msg}"
78
+ return unless @debug_level && ex.kind_of?(Exception)
79
+ error_logger.puts("#{prefix}------------------------------------------")
80
+ error_logger.puts("#{prefix}#{ex.backtrace.join("\n")}")
81
+ error_logger.puts("#{prefix}------------------------------------------")
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,85 @@
1
+
2
+
3
+
4
+ module Stella
5
+
6
+ # An object for HTTP response content
7
+ #
8
+ class Response < Storable
9
+
10
+ field :errors => Array
11
+ field :content => Hash
12
+ field :messages => Array
13
+ field :success => TrueClass
14
+
15
+ def initialize
16
+ @success = false
17
+ @errors = []
18
+ @messages = []
19
+ @content = {}
20
+ end
21
+
22
+ def success?
23
+ @success
24
+ end
25
+
26
+ def add(key, value)
27
+ @content[key] = value
28
+ end
29
+
30
+ def get(key)
31
+ @content[key] if @content.has_key? key
32
+ end
33
+
34
+ def message(msg)
35
+ @messages.push(msg)
36
+ end
37
+
38
+ def error(msg)
39
+ @errors.push(msg)
40
+ end
41
+
42
+ def output(format='yaml')
43
+ format = 'yaml' unless self.respond_to? "output_#{format}"
44
+ #STDERR.puts "OUTPUT: #{format}"
45
+ self.send("output_#{format}")
46
+ end
47
+
48
+ def to_hash
49
+ h = {}
50
+ h[:version] = API_VERSION
51
+ h[:errors] = @errors unless @errors.empty?
52
+ h[:messages] = @messages unless @messages.empty?
53
+ h[:content] = @content || {}
54
+ h[:success] = @success || false
55
+ h
56
+ end
57
+
58
+ def output_zip
59
+ output = @content
60
+ end
61
+
62
+ def output_yaml
63
+ to_hash.to_yaml
64
+ end
65
+
66
+ # http://evang.eli.st/blog/2007/2/22/my-rails-gotcha-custom-to_xml-in-a-hash-or-array
67
+ # http://api.rubyonrails.org/classes/ActiveRecord/XmlSerialization.html#M000910
68
+ def output_xml
69
+ output = "<StellaResponse success=\":[\">\n"
70
+ output << "<todo>implement XML</todo>\n"
71
+ output << "</StellaResponse>\n"
72
+ end
73
+
74
+ def output_json
75
+ to_hash.to_json
76
+ end
77
+
78
+ def output_html
79
+ "hello!"
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
@@ -0,0 +1,201 @@
1
+
2
+ # TODO: Handle nested hashes and arrays.
3
+
4
+ require 'yaml'
5
+ require 'utils/fileutil'
6
+
7
+ module Stella
8
+ class Storable
9
+ NICE_TIME_FORMAT = "%Y-%m-%d@%H:%M:%S".freeze unless defined? NICE_TIME_FORMAT
10
+ SUPPORTED_FORMATS = %w{tsv csv yaml json}.freeze unless defined? SUPPORTED_FORMATS
11
+
12
+ attr_reader :format
13
+
14
+ def format=(v)
15
+ raise "Unsupported format: #{v}" unless SUPPORTED_FORMATS.member?(v)
16
+ @format = v
17
+ end
18
+
19
+ def init
20
+ self.class.send(:class_variable_set, :@@field_names, []) unless class_variable_defined?(:@@field_names)
21
+ self.class.send(:class_variable_set, :@@field_types, []) unless class_variable_defined?(:@@field_types)
22
+ end
23
+
24
+ def self.field(args={})
25
+ args.each_pair do |m,t|
26
+
27
+ [[:@@field_names, m], [:@@field_types, t]].each do |tuple|
28
+ class_variable_set(tuple[0], []) unless class_variable_defined?(tuple[0])
29
+ class_variable_set(tuple[0], class_variable_get(tuple[0]) << tuple[1])
30
+ end
31
+
32
+ next if method_defined?(m)
33
+
34
+ # NOTE: I need a way to put these in the caller's namespace... Here's they're shared by all
35
+ # the subclasses which is not helpful. It will likely involve Kernel#caller and binding.
36
+ # Maybe class_eval, wraped around def field.
37
+
38
+
39
+ define_method(m) do instance_variable_get("@#{m}") end
40
+
41
+ define_method("#{m}=") do |val|
42
+ instance_variable_set("@#{m}",val)
43
+ end
44
+ end
45
+ end
46
+
47
+ def self.field_names
48
+ class_variable_get(:@@field_names)
49
+ end
50
+ def self.field_types
51
+ class_variable_get(:@@field_types)
52
+ end
53
+
54
+ def field_names
55
+ self.class.send(:class_variable_get, :@@field_names)
56
+ end
57
+
58
+ def field_types
59
+ self.class.send(:class_variable_get, :@@field_types)
60
+ end
61
+
62
+ def format=(v)
63
+ raise "Unsupported format: #{v}" unless SUPPORTED_FORMATS.member?(v)
64
+ @format = v
65
+ end
66
+
67
+
68
+ def dump(format=nil, with_titles=true)
69
+ format ||= @format
70
+ raise "Format not defined (#{format})" unless SUPPORTED_FORMATS.member?(format)
71
+ send("to_#{format}", with_titles)
72
+ end
73
+
74
+ def self.from_file(file_path=nil, format=nil)
75
+ raise "Cannot read file (#{file_path})" unless File.exists?(file_path)
76
+ format = format || File.extname(file_path).tr('.', '')
77
+ me = send("from_#{format}", FileUtil.read_file_to_array(file_path))
78
+ me.format = format
79
+ me
80
+ end
81
+ def to_file(file_path=nil, with_titles=true)
82
+ raise "Cannot store to nil path" if file_path.nil?
83
+ format = File.extname(file_path).tr('.', '')
84
+ format ||= @format
85
+ FileUtil.write_file(file_path, dump(format, with_titles))
86
+ end
87
+
88
+
89
+ def self.from_hash(from={})
90
+ me = self.new
91
+
92
+ return me if !from || from.empty?
93
+
94
+ fnames = field_names
95
+ fnames.each_with_index do |key,index|
96
+
97
+ value = from[key]
98
+
99
+ # TODO: Correct this horrible implementation (sorry, me. It's just one of those days.)
100
+
101
+ if field_types[index] == Time
102
+ value = Time.parse(from[key].to_s)
103
+ elsif field_types[index] == DateTime
104
+ value = DateTime.parse(from[key].to_s)
105
+ elsif field_types[index] == TrueClass
106
+ value = (from[key].to_s == "true")
107
+ elsif field_types[index] == Float
108
+ value = from[key].to_f
109
+ elsif field_types[index] == Integer
110
+ value = from[key].to_i
111
+ end
112
+
113
+ me.send("#{key}=", value) if self.method_defined?("#{key}=")
114
+ end
115
+ me
116
+ end
117
+ def to_hash(with_titles=true)
118
+ tmp = {}
119
+ field_names.each do |fname|
120
+ tmp[fname] = self.send(fname)
121
+ end
122
+ tmp
123
+ end
124
+
125
+
126
+ def self.from_yaml(from=[])
127
+ # from is an array of strings
128
+ from_str = from.join('')
129
+ hash = YAML::load(from_str)
130
+ hash = from_hash(hash) if hash.is_a? Hash
131
+ hash
132
+ end
133
+ def to_yaml(with_titles=true)
134
+ to_hash.to_yaml
135
+ end
136
+
137
+
138
+ def self.from_json(from=[])
139
+ require 'json'
140
+ # from is an array of strings
141
+ from_str = from.join('')
142
+ tmp = JSON::load(from_str)
143
+ hash_sym = tmp.keys.inject({}) do |hash, key|
144
+ hash[key.to_sym] = tmp[key]
145
+ hash
146
+ end
147
+ hash_sym = from_hash(hash_sym) if hash_sym.is_a? Hash
148
+ hash_sym
149
+ end
150
+ def to_json(with_titles=true)
151
+ require 'json'
152
+ to_hash.to_json
153
+ end
154
+
155
+ def to_delimited(with_titles=false, delim=',')
156
+ values = []
157
+ field_names.each do |fname|
158
+ values << self.send(fname.to_s) # TODO: escape values
159
+ end
160
+ output = values.join(delim)
161
+ output = field_names.join(delim) << $/ << output if with_titles
162
+ output
163
+ end
164
+ def to_tsv(with_titles=false)
165
+ to_delimited(with_titles, "\t")
166
+ end
167
+ def to_csv(with_titles=false)
168
+ to_delimited(with_titles, ',')
169
+ end
170
+ def self.from_tsv(from=[])
171
+ self.from_delimited(from, "\t")
172
+ end
173
+ def self.from_csv(from=[])
174
+ self.from_delimited(from, ',')
175
+ end
176
+
177
+ def self.from_delimited(from=[],delim=',')
178
+ return if from.empty?
179
+ # We grab an instance of the class so we can
180
+ hash = {}
181
+
182
+ fnames = values = []
183
+ if (from.size > 1 && !from[1].empty?)
184
+ fnames = from[0].chomp.split(delim)
185
+ values = from[1].chomp.split(delim)
186
+ else
187
+ fnames = self.field_names
188
+ values = from[0].chomp.split(delim)
189
+ end
190
+
191
+ fnames.each_with_index do |key,index|
192
+ next unless values[index]
193
+ hash[key.to_sym] = values[index]
194
+ end
195
+ hash = from_hash(hash) if hash.is_a? Hash
196
+ hash
197
+ end
198
+
199
+
200
+ end
201
+ end