scout 2.0.7 → 4.0.0

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 (128) hide show
  1. data/CHANGELOG +15 -0
  2. data/Rakefile +14 -59
  3. data/data/cacert.pem +3154 -0
  4. data/data/gpl-2.0.txt +339 -0
  5. data/data/lgpl-2.1.txt +504 -0
  6. data/lib/scout.rb +4 -4
  7. data/lib/scout/command.rb +9 -0
  8. data/lib/scout/command/test.rb +8 -6
  9. data/lib/scout/plugin.rb +17 -6
  10. data/lib/scout/server.rb +127 -123
  11. data/vendor/json_pure/CHANGES +119 -0
  12. data/vendor/json_pure/GPL +340 -0
  13. data/vendor/json_pure/README +78 -0
  14. data/vendor/json_pure/RUBY +58 -0
  15. data/vendor/json_pure/Rakefile +270 -0
  16. data/vendor/json_pure/TODO +1 -0
  17. data/vendor/json_pure/VERSION +1 -0
  18. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
  19. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
  20. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
  21. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
  22. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
  23. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
  24. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
  25. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
  26. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
  27. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
  28. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
  29. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
  30. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
  31. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
  32. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
  33. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
  34. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
  35. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
  36. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
  37. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
  38. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
  39. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
  40. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
  41. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
  42. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
  43. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
  44. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
  45. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
  46. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
  47. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
  48. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
  49. data/vendor/json_pure/benchmarks/generator_benchmark.rb +165 -0
  50. data/vendor/json_pure/benchmarks/parser_benchmark.rb +197 -0
  51. data/vendor/json_pure/bin/edit_json.rb +9 -0
  52. data/vendor/json_pure/bin/prettify_json.rb +75 -0
  53. data/vendor/json_pure/data/example.json +1 -0
  54. data/vendor/json_pure/data/index.html +38 -0
  55. data/vendor/json_pure/data/prototype.js +4184 -0
  56. data/vendor/json_pure/doc-templates/main.txt +283 -0
  57. data/vendor/json_pure/ext/json/ext/generator/extconf.rb +11 -0
  58. data/vendor/json_pure/ext/json/ext/generator/generator.c +919 -0
  59. data/vendor/json_pure/ext/json/ext/generator/unicode.c +182 -0
  60. data/vendor/json_pure/ext/json/ext/generator/unicode.h +53 -0
  61. data/vendor/json_pure/ext/json/ext/parser/extconf.rb +11 -0
  62. data/vendor/json_pure/ext/json/ext/parser/parser.c +1829 -0
  63. data/vendor/json_pure/ext/json/ext/parser/parser.rl +686 -0
  64. data/vendor/json_pure/ext/json/ext/parser/unicode.c +154 -0
  65. data/vendor/json_pure/ext/json/ext/parser/unicode.h +58 -0
  66. data/vendor/json_pure/install.rb +26 -0
  67. data/vendor/json_pure/lib/json.rb +10 -0
  68. data/vendor/json_pure/lib/json/Array.xpm +21 -0
  69. data/vendor/json_pure/lib/json/FalseClass.xpm +21 -0
  70. data/vendor/json_pure/lib/json/Hash.xpm +21 -0
  71. data/vendor/json_pure/lib/json/Key.xpm +73 -0
  72. data/vendor/json_pure/lib/json/NilClass.xpm +21 -0
  73. data/vendor/json_pure/lib/json/Numeric.xpm +28 -0
  74. data/vendor/json_pure/lib/json/String.xpm +96 -0
  75. data/vendor/json_pure/lib/json/TrueClass.xpm +21 -0
  76. data/vendor/json_pure/lib/json/add/core.rb +135 -0
  77. data/vendor/json_pure/lib/json/add/rails.rb +58 -0
  78. data/vendor/json_pure/lib/json/common.rb +354 -0
  79. data/vendor/json_pure/lib/json/editor.rb +1371 -0
  80. data/vendor/json_pure/lib/json/ext.rb +15 -0
  81. data/vendor/json_pure/lib/json/json.xpm +1499 -0
  82. data/vendor/json_pure/lib/json/pure.rb +77 -0
  83. data/vendor/json_pure/lib/json/pure/generator.rb +430 -0
  84. data/vendor/json_pure/lib/json/pure/parser.rb +269 -0
  85. data/vendor/json_pure/lib/json/version.rb +8 -0
  86. data/vendor/json_pure/tests/fixtures/fail1.json +1 -0
  87. data/vendor/json_pure/tests/fixtures/fail10.json +1 -0
  88. data/vendor/json_pure/tests/fixtures/fail11.json +1 -0
  89. data/vendor/json_pure/tests/fixtures/fail12.json +1 -0
  90. data/vendor/json_pure/tests/fixtures/fail13.json +1 -0
  91. data/vendor/json_pure/tests/fixtures/fail14.json +1 -0
  92. data/vendor/json_pure/tests/fixtures/fail18.json +1 -0
  93. data/vendor/json_pure/tests/fixtures/fail19.json +1 -0
  94. data/vendor/json_pure/tests/fixtures/fail2.json +1 -0
  95. data/vendor/json_pure/tests/fixtures/fail20.json +1 -0
  96. data/vendor/json_pure/tests/fixtures/fail21.json +1 -0
  97. data/vendor/json_pure/tests/fixtures/fail22.json +1 -0
  98. data/vendor/json_pure/tests/fixtures/fail23.json +1 -0
  99. data/vendor/json_pure/tests/fixtures/fail24.json +1 -0
  100. data/vendor/json_pure/tests/fixtures/fail25.json +1 -0
  101. data/vendor/json_pure/tests/fixtures/fail27.json +2 -0
  102. data/vendor/json_pure/tests/fixtures/fail28.json +2 -0
  103. data/vendor/json_pure/tests/fixtures/fail3.json +1 -0
  104. data/vendor/json_pure/tests/fixtures/fail4.json +1 -0
  105. data/vendor/json_pure/tests/fixtures/fail5.json +1 -0
  106. data/vendor/json_pure/tests/fixtures/fail6.json +1 -0
  107. data/vendor/json_pure/tests/fixtures/fail7.json +1 -0
  108. data/vendor/json_pure/tests/fixtures/fail8.json +1 -0
  109. data/vendor/json_pure/tests/fixtures/fail9.json +1 -0
  110. data/vendor/json_pure/tests/fixtures/pass1.json +56 -0
  111. data/vendor/json_pure/tests/fixtures/pass15.json +1 -0
  112. data/vendor/json_pure/tests/fixtures/pass16.json +1 -0
  113. data/vendor/json_pure/tests/fixtures/pass17.json +1 -0
  114. data/vendor/json_pure/tests/fixtures/pass2.json +1 -0
  115. data/vendor/json_pure/tests/fixtures/pass26.json +1 -0
  116. data/vendor/json_pure/tests/fixtures/pass3.json +6 -0
  117. data/vendor/json_pure/tests/test_json.rb +312 -0
  118. data/vendor/json_pure/tests/test_json_addition.rb +164 -0
  119. data/vendor/json_pure/tests/test_json_fixtures.rb +34 -0
  120. data/vendor/json_pure/tests/test_json_generate.rb +106 -0
  121. data/vendor/json_pure/tests/test_json_rails.rb +146 -0
  122. data/vendor/json_pure/tests/test_json_unicode.rb +62 -0
  123. data/vendor/json_pure/tools/fuzz.rb +139 -0
  124. data/vendor/json_pure/tools/server.rb +61 -0
  125. metadata +120 -6
  126. data/lib/scout/command/clone.rb +0 -21
  127. data/setup.rb +0 -1360
  128. data/test/scout_test.rb +0 -91
data/lib/scout.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby -wKU
2
2
 
3
+ module Scout
4
+ VERSION = "4.0.0".freeze
5
+ end
6
+
3
7
  require "scout/command"
4
8
  require "scout/plugin"
5
9
  require "scout/server"
6
-
7
- module Scout
8
- VERSION = "2.0.7".freeze
9
- end
data/lib/scout/command.rb CHANGED
@@ -199,6 +199,15 @@ module Scout
199
199
  running = true
200
200
  begin
201
201
  Process.kill(0, pid)
202
+ if stat = File.stat(pid_file)
203
+ if mtime = stat.mtime
204
+ if Time.now - mtime > 25 * 60 # assume process is hung after 25m
205
+ log.info "Trying to KILL an old process..." if log
206
+ Process.kill("KILL", pid)
207
+ running = false
208
+ end
209
+ end
210
+ end
202
211
  rescue Errno::ESRCH
203
212
  running = false
204
213
  rescue
@@ -25,12 +25,14 @@ module Scout
25
25
  end
26
26
 
27
27
  Scout::Server.new(nil, nil, history, log) do |scout|
28
- pp scout.process_plugin( :interval => 0,
29
- :plugin_id => 1,
30
- :name => "Local Plugin",
31
- :code => plugin_code,
32
- :options => plugin_options,
33
- :path => plugin )
28
+ scout.prepare_checkin
29
+ scout.process_plugin( 'interval' => 0,
30
+ 'plugin_id' => 1,
31
+ 'name' => "Local Plugin",
32
+ 'code' => plugin_code,
33
+ 'options' => plugin_options,
34
+ 'path' => plugin )
35
+ scout.show_checkin(:pp)
34
36
  end
35
37
  end
36
38
  end
data/lib/scout/plugin.rb CHANGED
@@ -69,22 +69,33 @@ module Scout
69
69
  # add_error(:subject => "subject", :body => "body")
70
70
  #
71
71
  def data_for_server
72
- @data_for_server ||= { :reports => [ ],
73
- :alerts => [ ],
74
- :errors => [ ],
72
+ @data_for_server ||= { :reports => [ ],
73
+ :alerts => [ ],
74
+ :errors => [ ],
75
+ :summaries => [ ],
75
76
  :memory => { } }
76
77
  end
77
78
 
78
- %w[report alert error].each do |kind|
79
+ %w[report alert error summary].each do |kind|
79
80
  class_eval <<-END
80
- def #{kind}s
81
- data_for_server[:#{kind}s]
81
+ if "#{kind}" == "summary"
82
+ def summaries
83
+ data_for_server[:summaries]
84
+ end
85
+ else
86
+ def #{kind}s
87
+ data_for_server[:#{kind}s]
88
+ end
82
89
  end
83
90
 
84
91
  if "#{kind}" == "report"
85
92
  def report(new_entry)
86
93
  reports << new_entry
87
94
  end
95
+ elsif "#{kind}" == "summary"
96
+ def summary(new_entry)
97
+ summaries << new_entry
98
+ end
88
99
  else
89
100
  def #{kind}(*fields)
90
101
  #{kind}s << ( fields.first.is_a?(Hash) ?
data/lib/scout/server.rb CHANGED
@@ -4,6 +4,12 @@ require "net/https"
4
4
  require "uri"
5
5
  require "yaml"
6
6
  require "timeout"
7
+ require "stringio"
8
+ require "zlib"
9
+ require "socket"
10
+
11
+ $LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. .. vendor json_pure lib])
12
+ require "json"
7
13
 
8
14
  module Scout
9
15
  class Server
@@ -12,18 +18,17 @@ module Scout
12
18
  # A new class for API Timeout errors.
13
19
  class APITimeoutError < RuntimeError; end
14
20
 
15
- # The default URLS are used to communicate with the Scout Server.
16
- URLS = { :plan => "/clients/CLIENT_KEY/plugins.scout?version=CLIENT_VERSION",
17
- :report => "/clients/CLIENT_KEY/plugins/PLUGIN_ID/reports.scout?version=CLIENT_VERSION",
18
- :error => "/clients/CLIENT_KEY/plugins/PLUGIN_ID/errors.scout?version=CLIENT_VERSION",
19
- :alert => "/clients/CLIENT_KEY/plugins/PLUGIN_ID/alerts.scout?version=CLIENT_VERSION",
20
- :clone => "/clients/CLIENT_KEY/clone_from?version=CLIENT_VERSION" }
21
-
21
+ # Headers passed up with all API requests.
22
+ HTTP_HEADERS = { "CLIENT_VERSION" => Scout::VERSION,
23
+ "CLIENT_HOSTNAME" => Socket.gethostname,
24
+ "ACCEPT_ENCODING" => "gzip" }
25
+
22
26
  #
23
- # A plugin cannot take more than PLUGIN_TIMEOUT seconds to execute,
24
- # otherwise, a timeout error is generated.
27
+ # A plugin cannot take more than DEFAULT_PLUGIN_TIMEOUT seconds to execute,
28
+ # otherwise, a timeout error is generated. This can be overriden by
29
+ # individual plugins.
25
30
  #
26
- PLUGIN_TIMEOUT = 60
31
+ DEFAULT_PLUGIN_TIMEOUT = 60
27
32
  #
28
33
  # A fuzzy range of seconds in which it is okay to rerun a plugin.
29
34
  # We consider the interval close enough at this point.
@@ -45,6 +50,18 @@ module Scout
45
50
  end
46
51
  end
47
52
 
53
+ # Prepares a check-in data structure to hold Plugin generated data.
54
+ def prepare_checkin
55
+ @checkin = { :reports => Array.new,
56
+ :alerts => Array.new,
57
+ :errors => Array.new,
58
+ :summaries => Array.new }
59
+ end
60
+
61
+ def show_checkin(printer = :p)
62
+ send(printer, @checkin)
63
+ end
64
+
48
65
  #
49
66
  # Loads the history file from disk. If the file does not exist,
50
67
  # it creates one.
@@ -72,7 +89,9 @@ module Scout
72
89
  # Runs all plugins from a given plan. Calls process_plugin on each plugin.
73
90
  def run_plugins_by_plan
74
91
  plan do |plugin|
92
+ prepare_checkin
75
93
  process_plugin(plugin)
94
+ checkin
76
95
  end
77
96
  end
78
97
 
@@ -86,17 +105,23 @@ module Scout
86
105
  # set memory and last_run information in the history file.
87
106
  #
88
107
  def process_plugin(plugin)
89
- info "Processing the #{plugin[:name]} plugin:"
90
- last_run = @history["last_runs"][plugin[:name]]
91
- memory = @history["memory"][plugin[:name]]
92
- run_time = Time.now
93
- delta = last_run.nil? ? nil : run_time - (last_run + plugin[:interval])
108
+ info "Processing the #{plugin['name']} plugin:"
109
+ id_and_name = "#{plugin['id']}-#{plugin['name']}".sub(/\A-/, "")
110
+ last_run = @history["last_runs"][id_and_name] ||
111
+ @history["last_runs"][plugin['name']]
112
+ memory = @history["memory"][id_and_name] ||
113
+ @history["memory"][plugin['name']]
114
+ run_time = Time.now
115
+ delta = last_run.nil? ? nil : run_time -
116
+ (last_run + plugin['interval'] * 60)
94
117
  if last_run.nil? or delta.between?(-RUN_DELTA, 0) or delta >= 0
95
118
  debug "Plugin is past interval and needs to be run. " +
96
119
  "(last run: #{last_run || 'nil'})"
97
120
  debug "Compiling plugin..."
98
121
  begin
99
- eval(plugin[:code], TOPLEVEL_BINDING, plugin[:path] || plugin[:name])
122
+ eval( plugin['code'],
123
+ TOPLEVEL_BINDING,
124
+ plugin['path'] || plugin['name'] )
100
125
  info "Plugin compiled."
101
126
  rescue Exception
102
127
  raise if $!.is_a? SystemExit
@@ -105,12 +130,14 @@ module Scout
105
130
  end
106
131
  debug "Loading plugin..."
107
132
  if job = Plugin.last_defined.load( last_run, (memory || Hash.new),
108
- plugin[:options] || Hash.new )
133
+ plugin['options'] || Hash.new )
109
134
  info "Plugin loaded."
110
135
  debug "Running plugin..."
111
136
  begin
112
- data = {}
113
- Timeout.timeout(PLUGIN_TIMEOUT, PluginTimeoutError) do
137
+ data = {}
138
+ timeout = plugin['timeout'].to_i
139
+ timeout = DEFAULT_PLUGIN_TIMEOUT unless timeout > 0
140
+ Timeout.timeout(timeout, PluginTimeoutError) do
114
141
  data = job.run
115
142
  end
116
143
  rescue Timeout::Error
@@ -118,30 +145,27 @@ module Scout
118
145
  return
119
146
  rescue Exception
120
147
  raise if $!.is_a? SystemExit
121
- error "Plugin failed to run: #{$!.class}: #{$!}\n#{$!.backtrace.join("\n")}"
148
+ error "Plugin failed to run: #{$!.class}: #{$!.message}\n" +
149
+ "#{$!.backtrace.join("\n")}"
122
150
  end
123
151
  info "Plugin completed its run."
124
152
 
125
- # handle single report or array of reports
126
- send_report(data[:report], plugin[:plugin_id]) if data[:report]
127
- if data[:reports] and not data[:reports].empty?
128
- data[:reports].each { |r| send_report(r, plugin[:plugin_id]) }
129
- end
130
- # handle single alert or array of alerts
131
- send_alert(data[:alert], plugin[:plugin_id]) if data[:alert]
132
- if data[:alerts] and not data[:alerts].empty?
133
- data[:alerts].each { |a| send_alert(a, plugin[:plugin_id]) }
134
- end
135
- # handle single error or array of errors
136
- send_error(data[:error], plugin[:plugin_id]) if data[:error]
137
- if data[:errors] and not data[:errors].empty?
138
- data[:errors].each { |e| send_error(e, plugin[:plugin_id]) }
153
+ %w[report alert error summary].each do |type|
154
+ plural = "#{type}s".sub(/ys\z/, "ies").to_sym
155
+ (Array(data[type.to_sym]) + Array(data[plural])).each do |fields|
156
+ @checkin[plural] << build_report(plugin['id'], fields)
157
+ end
139
158
  end
140
159
 
141
- @history["last_runs"][plugin[:name]] = run_time
142
- @history["memory"][plugin[:name]] = data[:memory]
160
+ @history["last_runs"].delete(plugin['name'])
161
+ @history["memory"].delete(plugin['name'])
162
+ @history["last_runs"][id_and_name] = run_time
163
+ @history["memory"][id_and_name] = data[:memory]
143
164
  else
144
- scout_error({:subject => "Plugin would not load."}, plugin[:plugin_id])
165
+ @checkin[:errors] << build_report(
166
+ plugin_id['id'],
167
+ :subject => "Plugin would not load."
168
+ )
145
169
  end
146
170
  else
147
171
  debug "Plugin does not need to be run at this time. " +
@@ -160,7 +184,7 @@ module Scout
160
184
  error "Unable to remove plugin."
161
185
  end
162
186
  end
163
- info "Plugin #{plugin[:name]} processing complete."
187
+ info "Plugin #{plugin['name']} processing complete."
164
188
  end
165
189
 
166
190
  #
@@ -170,118 +194,80 @@ module Scout
170
194
  def plan
171
195
  url = urlify(:plan)
172
196
  info "Loading plan from #{url}..."
173
- get(url, "Could not retrieve plan from server.") do |res|
174
- begin
175
- plugin_execution_plan = Marshal.load(res.body)
176
- # pp plugin_execution_plan
177
- info "Plan loaded. (#{plugin_execution_plan.size} plugins: " +
178
- "#{plugin_execution_plan.map { |p| p[:name] }.join(', ')})"
179
- rescue TypeError
180
- fatal "Plan from server was malformed."
181
- exit
197
+ headers = Hash.new
198
+ if @history["last_modified_for_plugins"] and @history["old_plugins"]
199
+ headers["If-Modified-Since"] = @history["last_modified_for_plugins"]
200
+ end
201
+ get(url, "Could not retrieve plan from server.", headers) do |res|
202
+ if res.is_a? Net::HTTPNotModified
203
+ info "Plan not modified. Reusing saved plan."
204
+ plugin_execution_plan = Array(@history["old_plugins"])
205
+ else
206
+ begin
207
+ body = res.body
208
+ if res["Content-Encoding"] == "gzip" and body and not body.empty?
209
+ body = Zlib::GzipReader.new(StringIO.new(body)).read
210
+ end
211
+ plugin_execution_plan = Array(JSON.parse(body)["plugins"])
212
+ if res["Last-Modified"]
213
+ @history["last_modified_for_plugins"] = res["last-modified"]
214
+ @history["old_plugins"] = plugin_execution_plan
215
+ end
216
+ info "Plan loaded. (#{plugin_execution_plan.size} plugins: " +
217
+ "#{plugin_execution_plan.map { |p| p['name'] }.join(', ')})"
218
+ rescue Exception
219
+ fatal "Plan from server was malformed."
220
+ exit
221
+ end
182
222
  end
183
223
  plugin_execution_plan.each do |plugin|
184
224
  begin
185
225
  yield plugin if block_given?
186
226
  rescue RuntimeError
187
- scout_error( { :subject => "Exception: #{$!.message}.",
188
- :body => $!.backtrace },
189
- plugin[:plugin_id] )
227
+ @checkin[:errors] << build_report(
228
+ plugin_id['id'],
229
+ :subject => "Exception: #{$!.message}.",
230
+ :body => $!.backtrace
231
+ )
190
232
  end
191
233
  end
192
234
  end
193
235
  end
194
236
  alias_method :test, :plan
195
-
196
- # Sends report data to the Scout Server.
197
- def send_report(data, plugin_id)
198
- url = urlify(:report, :plugin_id => plugin_id)
199
- report_hash = {:data => data, :plugin_id => plugin_id}
200
-
201
- # add in any special fields
202
- if time = ( data.delete(:scout_time) || data.delete("scout_time") )
203
- report_hash[:time] = time
204
- end
205
-
206
- debug "Sending report to #{url} (#{data.inspect})..."
207
- post url,
208
- "Unable to send report to server.",
209
- :report => report_hash
210
- info "Report sent."
211
- end
212
-
213
- # Sends an alert to the Scout Server.
214
- def send_alert(data, plugin_id)
215
- url = urlify(:alert, :plugin_id => plugin_id)
216
- debug "Sending alert to #{url} (subject: #{data[:subject]})..."
217
- post url,
218
- "Unable to send alert to server.",
219
- :alert => data.merge(:plugin_id => plugin_id)
220
- info "Alert sent."
221
- end
222
-
223
- # Sends an error to the Scout Server.
224
- def send_error(data, plugin_id)
225
- url = urlify(:error, :plugin_id => plugin_id)
226
- debug "Sending error to #{url} (subject: #{data[:subject]})..."
227
- post url,
228
- "Unable to log error on server.",
229
- :error => data.merge(:plugin_id => plugin_id)
230
- info "Error sent."
231
- end
232
-
233
- def clone_client(new_name, success_output)
234
- url = urlify(:clone)
235
- debug "Sending clone request to #{url}..."
236
- post( url,
237
- "Unable to send clone request to server.",
238
- "client[name]" => new_name ) do |response|
239
- case server_reply = response.body
240
- when /\AError:/i
241
- fatal "Clone error."
242
- abort server_reply
243
- else
244
- info "Client cloned."
245
- puts success_output.gsub(/\bCLIENT_KEY\b/, server_reply.strip)
246
- end
247
- end
248
- end
249
237
 
250
238
  private
239
+
240
+ def build_report(plugin_id, fields)
241
+ { :plugin_id => plugin_id,
242
+ :created_at => Time.now.utc.strftime("%Y-%m-%d %H:%M:%S"),
243
+ :fields => fields }
244
+ end
251
245
 
252
246
  def urlify(url_name, options = Hash.new)
253
247
  return unless @server
254
248
  options.merge!(:client_version => Scout::VERSION)
255
249
  URI.join( @server,
256
- URLS[url_name].
250
+ "/clients/CLIENT_KEY/#{url_name}.scout".
257
251
  gsub(/\bCLIENT_KEY\b/, @client_key).
258
252
  gsub(/\b[A-Z_]+\b/) { |k| options[k.downcase.to_sym] || k } )
259
253
  end
260
-
261
- def paramify(params, prefix = nil)
262
- params.inject(Hash.new) do |all, (key, value)|
263
- parent = prefix ? "#{prefix}[#{key}]" : String(key)
264
- if value.is_a? Hash
265
- all.merge(paramify(value, parent))
266
- else
267
- all.merge(parent => String(value))
268
- end
269
- end
270
- end
271
254
 
272
- def post(url, error, params = {}, &response_handler)
255
+ def post(url, error, body, headers = Hash.new, &response_handler)
273
256
  return unless url
274
257
  request(url, response_handler, error) do |connection|
275
- post = Net::HTTP::Post.new(url.path + (url.query ? ('?' + url.query) : ''))
276
- post.set_form_data(paramify(params))
258
+ post = Net::HTTP::Post.new( url.path +
259
+ (url.query ? ('?' + url.query) : ''),
260
+ HTTP_HEADERS.merge(headers) )
261
+ post.body = body
277
262
  connection.request(post)
278
263
  end
279
264
  end
280
265
 
281
- def get(url, error, params = {}, &response_handler)
266
+ def get(url, error, headers = Hash.new, &response_handler)
282
267
  return unless url
283
268
  request(url, response_handler, error) do |connection|
284
- connection.get(url.path + (url.query ? ('?' + url.query) : ''))
269
+ connection.get( url.path + (url.query ? ('?' + url.query) : ''),
270
+ HTTP_HEADERS.merge(headers) )
285
271
  end
286
272
  end
287
273
 
@@ -291,12 +277,15 @@ module Scout
291
277
  http = Net::HTTP.new(url.host, url.port)
292
278
  if url.is_a? URI::HTTPS
293
279
  http.use_ssl = true
294
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
280
+ http.ca_file = File.join( File.dirname(__FILE__),
281
+ *%w[.. .. data cacert.pem] )
282
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER |
283
+ OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
295
284
  end
296
285
  response = no_warnings { http.start(&connector) }
297
286
  end
298
287
  case response
299
- when Net::HTTPSuccess
288
+ when Net::HTTPSuccess, Net::HTTPNotModified
300
289
  response_handler[response] unless response_handler.nil?
301
290
  else
302
291
  fatal error
@@ -311,6 +300,21 @@ module Scout
311
300
  exit
312
301
  end
313
302
 
303
+ def checkin
304
+ io = StringIO.new
305
+ gzip = Zlib::GzipWriter.new(io)
306
+ gzip << @checkin.to_json
307
+ gzip.close
308
+ post( urlify(:checkin),
309
+ "Unable to check in with the server.",
310
+ io.string,
311
+ "Content-Type" => "application/json",
312
+ "CONTENT_ENCODING" => "gzip" )
313
+ rescue Exception
314
+ error "Unable to check in with the server."
315
+ end
316
+
317
+
314
318
  def no_warnings
315
319
  old_verbose = $VERBOSE
316
320
  $VERBOSE = false