solutious-stella 0.5.5

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 (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