is_it_working 1.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/License.txt +674 -0
- data/README.rdoc +75 -0
- data/Rakefile +38 -0
- data/lib/is_it_working.rb +18 -0
- data/lib/is_it_working/checks/action_mailer_check.rb +25 -0
- data/lib/is_it_working/checks/active_record_check.rb +28 -0
- data/lib/is_it_working/checks/dalli_check.rb +48 -0
- data/lib/is_it_working/checks/directory_check.rb +44 -0
- data/lib/is_it_working/checks/memcache_check.rb +46 -0
- data/lib/is_it_working/checks/ping_check.rb +53 -0
- data/lib/is_it_working/checks/url_check.rb +81 -0
- data/lib/is_it_working/filter.rb +55 -0
- data/lib/is_it_working/handler.rb +152 -0
- data/lib/is_it_working/status.rb +50 -0
- data/spec/action_mailer_check_spec.rb +51 -0
- data/spec/active_record_check_spec.rb +51 -0
- data/spec/dalli_check_spec.rb +53 -0
- data/spec/directory_check_spec.rb +70 -0
- data/spec/filter_spec.rb +46 -0
- data/spec/handler_spec.rb +140 -0
- data/spec/memecache_check_spec.rb +51 -0
- data/spec/ping_check_spec.rb +47 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/status_spec.rb +44 -0
- data/spec/url_check_spec.rb +144 -0
- metadata +121 -0
data/README.rdoc
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
= Is It Working
|
2
|
+
|
3
|
+
This gem provides a mechanism for setting up a Rack handler that tests the status of various components of an application and reports the output. It is designed to be modular and give a comprehensive view of the application status with a consistent URL (/is_it_working by default).
|
4
|
+
|
5
|
+
This handler can be used by monitoring to determine if an application is working or not, but it does not replace system level monitoring of low level resources. Rather it adds another level which tells if the application can actually use those resources.
|
6
|
+
|
7
|
+
== Use It As Documentation
|
8
|
+
|
9
|
+
A feature of this gem is that it gives you a consistent place to document the external dependencies of you application as code. The handler checking the status of you application should have a check for every line drawn from it to another box on a system architecture diagram.
|
10
|
+
|
11
|
+
== Example
|
12
|
+
|
13
|
+
Suppose you have a Rails application that uses the following services:
|
14
|
+
|
15
|
+
* ActiveRecord uses PostgreSQL database
|
16
|
+
* Caching is done using Rails.cache with a cluster of memcached instances
|
17
|
+
* Web service API hosted at https://api.example.com
|
18
|
+
* NFS shared directory symlinked to from system/data in the Rails root directory
|
19
|
+
* SMTP server at mail.example.com
|
20
|
+
* A black box service encapsulated in AwesomeService
|
21
|
+
|
22
|
+
A monitoring handler for this set up could be set up in <tt>config/initializers/is_it_working.rb</tt> like this:
|
23
|
+
|
24
|
+
Rails.configuration.middleware.use(IsItWorking::Handler) do |h|
|
25
|
+
# Check the ActiveRecord database connection without spawning a new thread
|
26
|
+
h.check :active_record, :async => false
|
27
|
+
|
28
|
+
# Check the memcache servers used by Rails.cache if using the MemCacheStore implementation
|
29
|
+
h.check :memcache, :cache => Rails.cache if Rails.cache.is_a?(ActiveSupport::Cache::MemCacheStore)
|
30
|
+
|
31
|
+
# Check that the web service is working by hitting a known URL with Basic authentication
|
32
|
+
h.check :url, :get => "http://api.example.com/version", :username => "appname", :password => "abc123"
|
33
|
+
|
34
|
+
# Check that the NFS mount directory is available with read/write permissions
|
35
|
+
h.check :directory, :path => Rails.root + "system/data", :permission => [:read, :write]
|
36
|
+
|
37
|
+
# Check the mail server configured for ActionMailer
|
38
|
+
h.check :action_mailer if ActionMailer::Base.delivery_method == :smtp
|
39
|
+
|
40
|
+
# Ping another mail server
|
41
|
+
h.check :ping, :host => "mail.example.com", :port => "smtp"
|
42
|
+
|
43
|
+
# Check that AwesomeService is working using the service's own logic
|
44
|
+
h.check :awesome_service do |status|
|
45
|
+
if AwesomeService.active?
|
46
|
+
status.ok("service active")
|
47
|
+
else
|
48
|
+
status.fail("service down")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
== Output
|
54
|
+
|
55
|
+
The response from the handler will be a plain text description of the checks that were run and the results of those checks. If all the checks passed, the response code will be 200. If any checks fail, the response code will be 500. The response will look something like this:
|
56
|
+
|
57
|
+
Host: example.com
|
58
|
+
PID: 696
|
59
|
+
Timestamp: 2011-01-13T16:55:13-06:00
|
60
|
+
Elapsed Time: 84ms
|
61
|
+
|
62
|
+
OK: active_record - ActiveRecord::Base.connection is active (2.516ms)
|
63
|
+
OK: memcache - cache1.example.com:11211 is available (0.022ms)
|
64
|
+
OK: memcache - cache2.example.com:11211 is available (0.022ms)
|
65
|
+
OK: url - GET http://www.example.com/ responded with response '200 OK' (81.775ms)
|
66
|
+
OK: directory - /app/myapp/system/data exists with read/write permission (0.044ms)
|
67
|
+
OK: ping - mail.example.com is accepting connections on port "smtp" (61.854ms)
|
68
|
+
|
69
|
+
== Security
|
70
|
+
|
71
|
+
Keep in mind that the output from the status check will be available on a publicly accessible URL. This can pose a security risk if some servers are not on a private network behind a firewall. If necessary, you can obscure the host names in the predefined checks by providing an <tt>:alias</tt> option that will be output instead of the actual host name or IP address. Also, you can manually specify the hostname that the handler reports for the application with the Handler#hostname= method.
|
72
|
+
|
73
|
+
== Thread Safety
|
74
|
+
|
75
|
+
By default status checks each happen in their own thread. If you write your own status check, you must make sure it is thread safe. If you need to synchronize the check logic, you can use the +synchronize+ method on the handler object to do so. Alternatively, you can pass <tt>:async => false</tt> to any +check+ specification. This will cause the check to be executed in the main request thread.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
desc 'Default: run unit tests'
|
5
|
+
task :default => :test
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'rspec'
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
desc 'Run the unit tests'
|
11
|
+
RSpec::Core::RakeTask.new(:test)
|
12
|
+
rescue LoadError
|
13
|
+
task :test do
|
14
|
+
raise "You must have rspec 2.0 installed to run the tests"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'jeweler'
|
20
|
+
Jeweler::Tasks.new do |gem|
|
21
|
+
gem.name = "is_it_working"
|
22
|
+
gem.summary = %Q{Rack handler for monitoring several parts of a web application.}
|
23
|
+
gem.description = %Q{Rack handler for monitoring several parts of a web application so one request can determine which system or dependencies are down.}
|
24
|
+
gem.authors = ["Brian Durand"]
|
25
|
+
gem.email = ["mdobrota@tribune.com", "ddpr@tribune.com"]
|
26
|
+
gem.files = FileList["lib/**/*", "spec/**/*", "bin/**/*", "example/**/*" "README.rdoc", "Rakefile", "License.txt"].to_a
|
27
|
+
gem.has_rdoc = true
|
28
|
+
gem.rdoc_options << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc'
|
29
|
+
gem.extra_rdoc_files = ["README.rdoc"]
|
30
|
+
# Add dependencies with gem.add_dependency('gem_name')
|
31
|
+
gem.add_development_dependency('rspec', '>= 2.0')
|
32
|
+
gem.add_development_dependency('webmock', '>= 1.6.0')
|
33
|
+
gem.add_development_dependency('memcache-client')
|
34
|
+
gem.add_development_dependency('dalli')
|
35
|
+
end
|
36
|
+
Jeweler::RubygemsDotOrgTasks.new
|
37
|
+
rescue LoadError
|
38
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module IsItWorking
|
5
|
+
autoload :Check, File.expand_path("../is_it_working/check.rb", __FILE__)
|
6
|
+
autoload :Filter, File.expand_path("../is_it_working/filter.rb", __FILE__)
|
7
|
+
autoload :Handler, File.expand_path("../is_it_working/handler.rb", __FILE__)
|
8
|
+
autoload :Status, File.expand_path("../is_it_working/status.rb", __FILE__)
|
9
|
+
|
10
|
+
# Predefined checks
|
11
|
+
autoload :ActionMailerCheck, File.expand_path("../is_it_working/checks/action_mailer_check.rb", __FILE__)
|
12
|
+
autoload :ActiveRecordCheck, File.expand_path("../is_it_working/checks/active_record_check.rb", __FILE__)
|
13
|
+
autoload :DalliCheck, File.expand_path("../is_it_working/checks/dalli_check.rb", __FILE__)
|
14
|
+
autoload :DirectoryCheck, File.expand_path("../is_it_working/checks/directory_check.rb", __FILE__)
|
15
|
+
autoload :MemcacheCheck, File.expand_path("../is_it_working/checks/memcache_check.rb", __FILE__)
|
16
|
+
autoload :PingCheck, File.expand_path("../is_it_working/checks/ping_check.rb", __FILE__)
|
17
|
+
autoload :UrlCheck, File.expand_path("../is_it_working/checks/url_check.rb", __FILE__)
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'action_mailer'
|
2
|
+
|
3
|
+
module IsItWorking
|
4
|
+
# Check if the mail server configured for ActionMailer is responding.
|
5
|
+
#
|
6
|
+
# The ActionMailer class that yields the configuration can be specified with the <tt>:class</tt>
|
7
|
+
# option. By default this will be ActionMailer::Base. You can also set a <tt>:timeout</tt> option
|
8
|
+
# for how long to wait for a response and an <tt>:alias</tt> option which will be the name reported
|
9
|
+
# back by the check (defaults to the ActionMailer class).
|
10
|
+
#
|
11
|
+
# === Example
|
12
|
+
#
|
13
|
+
# IsItWorking::Handler.new do |h|
|
14
|
+
# h.check :action_mailer, :class => UserMailer
|
15
|
+
# end
|
16
|
+
class ActionMailerCheck < PingCheck
|
17
|
+
def initialize(options={})
|
18
|
+
options = options.dup
|
19
|
+
klass = options.delete(:class) || ActionMailer::Base
|
20
|
+
options.merge!(:host => klass.smtp_settings[:address], :port => klass.smtp_settings[:port] || 'smtp')
|
21
|
+
options[:alias] ||= klass.name
|
22
|
+
super(options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module IsItWorking
|
4
|
+
# Check if the database connection used by an ActiveRecord class is up.
|
5
|
+
#
|
6
|
+
# The ActiveRecord class that yields the connection can be specified with the <tt>:class</tt>
|
7
|
+
# option. By default this will be ActiveRecord::Base.
|
8
|
+
#
|
9
|
+
# === Example
|
10
|
+
#
|
11
|
+
# IsItWorking::Handler.new do |h|
|
12
|
+
# h.check :active_record, :class => User
|
13
|
+
# end
|
14
|
+
class ActiveRecordCheck
|
15
|
+
def initialize(options={})
|
16
|
+
@class = options[:class] || ActiveRecord::Base
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(status)
|
20
|
+
@class.connection.verify!
|
21
|
+
if @class.connection.active?
|
22
|
+
status.ok("#{@class}.connection is active")
|
23
|
+
else
|
24
|
+
status.fail("#{@class}.connection is not active")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'dalli'
|
2
|
+
|
3
|
+
module IsItWorking
|
4
|
+
class DalliCheck
|
5
|
+
# Check if all the memcached servers in a cluster are responding.
|
6
|
+
# The memcache cluster to check is specified with the <tt>:cache</tt> options. The
|
7
|
+
# value can be either a Dalli::Client object (from the dalli gem) or an
|
8
|
+
# ActiveSupport::Cache::DalliStore (i.e. Rails.cache).
|
9
|
+
#
|
10
|
+
# If making the IP addresses of the memcache servers known to the world could
|
11
|
+
# pose a security risk because they are not on a private network behind a firewall,
|
12
|
+
# you can provide the <tt>:alias</tt> option to change the host names that are reported.
|
13
|
+
#
|
14
|
+
# === Example
|
15
|
+
#
|
16
|
+
# IsItWorking::Handler.new do |h|
|
17
|
+
# h.check :dalli, :cache => Rails.cache, :alias => "memcache server"
|
18
|
+
# end
|
19
|
+
def initialize(options={})
|
20
|
+
memcache = options[:cache]
|
21
|
+
raise ArgumentError.new(":cache not specified") unless memcache
|
22
|
+
unless memcache.is_a?(Dalli::Client)
|
23
|
+
if defined?(ActiveSupport::Cache::DalliStore) && memcache.is_a?(ActiveSupport::Cache::DalliStore)
|
24
|
+
# Big hack to get the MemCache object from Rails.cache
|
25
|
+
@memcache = memcache.instance_variable_get(:@data)
|
26
|
+
else
|
27
|
+
raise ArgumentError.new("#{memcache} is not a Dalli::Client")
|
28
|
+
end
|
29
|
+
else
|
30
|
+
@memcache = memcache
|
31
|
+
end
|
32
|
+
@alias = options[:alias]
|
33
|
+
end
|
34
|
+
|
35
|
+
def call(status)
|
36
|
+
servers = @memcache.send(:ring).servers
|
37
|
+
servers.each_with_index do |server, i|
|
38
|
+
public_host_name = @alias ? "#{@alias} #{i + 1}" : "#{server.hostname}:#{server.port}"
|
39
|
+
|
40
|
+
if server.alive?
|
41
|
+
status.ok("#{public_host_name} is available")
|
42
|
+
else
|
43
|
+
status.fail("#{public_host_name} is not available")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module IsItWorking
|
2
|
+
class DirectoryCheck
|
3
|
+
# Check if a file system directory exists and has the correct access. This
|
4
|
+
# can be very useful to check if the application relies on a shared file sytem
|
5
|
+
# being mounted. The <tt>:path</tt> options must be supplied to the initializer. You
|
6
|
+
# may also supply an <tt>:permission</tt> option with the values <tt>:read</tt>, <tt>:write</tt>, or
|
7
|
+
# <tt>[:read, :write]</tt> to check the permission on the directory as well.
|
8
|
+
#
|
9
|
+
# === Example
|
10
|
+
#
|
11
|
+
# IsItWorking::Handler.new do |h|
|
12
|
+
# h.check :directory, :path => "/var/shared/myapp", :permission => [:read, :write]
|
13
|
+
# end
|
14
|
+
def initialize (options={})
|
15
|
+
raise ArgumentError.new(":path not specified") unless options[:path]
|
16
|
+
@path = File.expand_path(options[:path])
|
17
|
+
@permission = options[:permission]
|
18
|
+
@permission = [@permission] if @permission && !@permission.is_a?(Array)
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(status)
|
22
|
+
stat = File.stat(@path) if File.exist?(@path)
|
23
|
+
if stat
|
24
|
+
if stat.directory?
|
25
|
+
if @permission
|
26
|
+
if @permission.include?(:read) && !stat.readable?
|
27
|
+
status.fail("#{@path} is not readable by #{ENV['USER']}")
|
28
|
+
elsif @permission.include?(:write) && !stat.writable?
|
29
|
+
status.fail("#{@path} is not writable by #{ENV['USER']}")
|
30
|
+
else
|
31
|
+
status.ok("#{@path} exists with #{@permission.collect{|a| a.to_s}.join('/')} permission")
|
32
|
+
end
|
33
|
+
else
|
34
|
+
status.ok("#{@path} exists")
|
35
|
+
end
|
36
|
+
else
|
37
|
+
status.fail("#{@path} is not a directory")
|
38
|
+
end
|
39
|
+
else
|
40
|
+
status.fail("#{@path} does not exist")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'memcache'
|
2
|
+
|
3
|
+
module IsItWorking
|
4
|
+
class MemcacheCheck
|
5
|
+
# Check if all the memcached servers in a cluster are responding.
|
6
|
+
# The memcache cluster to check is specified with the <tt>:cache</tt> options. The
|
7
|
+
# value can be either a MemCache object (from the memcache-client gem) or an
|
8
|
+
# ActiveSupport::Cache::MemCacheStore (i.e. Rails.cache).
|
9
|
+
#
|
10
|
+
# If making the IP addresses of the memcache servers known to the world could
|
11
|
+
# pose a security risk because they are not on a private network behind a firewall,
|
12
|
+
# you can provide the <tt>:alias</tt> option to change the host names that are reported.
|
13
|
+
#
|
14
|
+
# === Example
|
15
|
+
#
|
16
|
+
# IsItWorking::Handler.new do |h|
|
17
|
+
# h.check :memcache, :cache => Rails.cache, :alias => "memcache server"
|
18
|
+
# end
|
19
|
+
def initialize(options={})
|
20
|
+
memcache = options[:cache]
|
21
|
+
raise ArgumentError.new(":cache not specified") unless memcache
|
22
|
+
unless memcache.is_a?(MemCache)
|
23
|
+
if defined?(ActiveSupport::Cache::MemCacheStore) && memcache.is_a?(ActiveSupport::Cache::MemCacheStore)
|
24
|
+
# Big hack to get the MemCache object from Rails.cache
|
25
|
+
@memcache = memcache.instance_variable_get(:@data)
|
26
|
+
else
|
27
|
+
raise ArgumentError.new("#{memcache} is not a MemCache")
|
28
|
+
end
|
29
|
+
else
|
30
|
+
@memcache = memcache
|
31
|
+
end
|
32
|
+
@alias = options[:alias]
|
33
|
+
end
|
34
|
+
|
35
|
+
def call(status)
|
36
|
+
@memcache.servers.each_with_index do |server, i|
|
37
|
+
public_host_name = @alias ? "#{@alias} #{i + 1}" : "#{server.host}:#{server.port}"
|
38
|
+
if server.alive?
|
39
|
+
status.ok("#{public_host_name} is available")
|
40
|
+
else
|
41
|
+
status.fail("#{public_host_name} is not available")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
module IsItWorking
|
5
|
+
class PingCheck
|
6
|
+
# Check if a host is reachable and accepting connections on a specified port.
|
7
|
+
#
|
8
|
+
# The host and port to ping are specified with the <tt>:host</tt> and <tt>:port</tt> options. The port
|
9
|
+
# can be either a port number or port name for a well known port (i.e. "smtp" and 25 are
|
10
|
+
# equivalent). The default timeout to wait for a response is 2 seconds. This can be
|
11
|
+
# changed with the <tt>:timeout</tt> option.
|
12
|
+
#
|
13
|
+
# By default, the host name will be included in the output. If this could pose a security
|
14
|
+
# risk by making the existence of the host known to the world, you can supply the <tt>:alias</tt>
|
15
|
+
# option which will be used for output purposes. In general, you should supply this option
|
16
|
+
# unless the host is on a private network behind a firewall.
|
17
|
+
#
|
18
|
+
# === Example
|
19
|
+
#
|
20
|
+
# IsItWorking::Handler.new do |h|
|
21
|
+
# h.check :ping, :host => "example.com", :port => "ftp", :timeout => 4
|
22
|
+
# end
|
23
|
+
def initialize(options={})
|
24
|
+
@host = options[:host]
|
25
|
+
raise ArgumentError.new(":host not specified") unless @host
|
26
|
+
@port = options[:port]
|
27
|
+
raise ArgumentError.new(":port not specified") unless @port
|
28
|
+
@timeout = options[:timeout] || 2
|
29
|
+
@alias = options[:alias] || @host
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(status)
|
33
|
+
begin
|
34
|
+
ping(@host, @port)
|
35
|
+
status.ok("#{@alias} is accepting connections on port #{@port.inspect}")
|
36
|
+
rescue Errno::ECONNREFUSED
|
37
|
+
status.fail("#{@alias} is not accepting connections on port #{@port.inspect}")
|
38
|
+
rescue SocketError => e
|
39
|
+
status.fail("connection to #{@alias} on port #{@port.inspect} failed with '#{e.message}'")
|
40
|
+
rescue Timeout::Error
|
41
|
+
status.fail("#{@alias} did not respond on port #{@port.inspect} within #{@timeout} seconds")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def ping(host, port)
|
46
|
+
timeout(@timeout) do
|
47
|
+
s = TCPSocket.new(host, port)
|
48
|
+
s.close
|
49
|
+
end
|
50
|
+
true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
module IsItWorking
|
5
|
+
# Check if getting a URL returns a successful response. Only responses in the range 2xx or 304
|
6
|
+
# are considered successful. Redirects will not be followed.
|
7
|
+
#
|
8
|
+
# Available options are:
|
9
|
+
#
|
10
|
+
# * <tt>:get</tt> - The URL to get.
|
11
|
+
# * <tt>:headers</tt> - Hash of headers to send with the request
|
12
|
+
# * <tt>:proxy</tt> - Hash of proxy server information. The hash must contain a <tt>:host</tt> key and may contain <tt>:port</tt>, <tt>:username</tt>, and <tt>:password</tt>
|
13
|
+
# * <tt>:username</tt> - Username to use for Basic Authentication
|
14
|
+
# * <tt>:password</tt> - Password to use for Basic Authentication
|
15
|
+
# * <tt>:open_timeout</tt> - Time in seconds to wait for opening the connection (defaults to 5 seconds)
|
16
|
+
# * <tt>:read_timeout</tt> - Time in seconds to wait for data from the connection (defaults to 10 seconds)
|
17
|
+
# * <tt>:alias</tt> - Alias used for reporting in case making the URL known to the world could provide a security risk.
|
18
|
+
#
|
19
|
+
# === Example
|
20
|
+
#
|
21
|
+
# IsItWorking::Handler.new do |h|
|
22
|
+
# h.check :url, :get => "http://services.example.com/api", :headers => {"Accept" => "text/xml"}
|
23
|
+
# end
|
24
|
+
class UrlCheck
|
25
|
+
def initialize(options={})
|
26
|
+
raise ArgumentError.new(":get must provide the URL to check") unless options[:get]
|
27
|
+
@uri = URI.parse(options[:get])
|
28
|
+
@headers = options[:headers] || {}
|
29
|
+
@proxy = options[:proxy]
|
30
|
+
@username = options[:username]
|
31
|
+
@password = options[:password]
|
32
|
+
@open_timeout = options[:open_timeout] || 5
|
33
|
+
@read_timeout = options[:read_timeout] || 10
|
34
|
+
@alias = options[:alias] || options[:get]
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(status)
|
38
|
+
t = Time.now
|
39
|
+
response = perform_http_request
|
40
|
+
if response.is_a?(Net::HTTPSuccess)
|
41
|
+
status.ok("GET #{@alias} responded with response '#{response.code} #{response.message}'")
|
42
|
+
else
|
43
|
+
status.fail("GET #{@alias} failed with response '#{response.code} #{response.message}'")
|
44
|
+
end
|
45
|
+
rescue Timeout::Error
|
46
|
+
status.fail("GET #{@alias} timed out after #{Time.now - t} seconds")
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
# Create an HTTP object with the options set.
|
51
|
+
def instantiate_http #:nodoc:
|
52
|
+
http_class = nil
|
53
|
+
|
54
|
+
if @proxy && @proxy[:host]
|
55
|
+
http_class = Net::HTTP::Proxy(@proxy[:host], @proxy[:port], @proxy[:username], @proxy[:password])
|
56
|
+
else
|
57
|
+
http_class = Net::HTTP
|
58
|
+
end
|
59
|
+
|
60
|
+
http = http_class.new(@uri.host, @uri.port)
|
61
|
+
if @uri.scheme == 'https'
|
62
|
+
http.use_ssl = true
|
63
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
64
|
+
end
|
65
|
+
http.open_timeout = @open_timeout
|
66
|
+
http.read_timeout = @read_timeout
|
67
|
+
|
68
|
+
return http
|
69
|
+
end
|
70
|
+
|
71
|
+
# Perform an HTTP request and return the response
|
72
|
+
def perform_http_request #:nodoc:
|
73
|
+
request = Net::HTTP::Get.new(@uri.request_uri, @headers)
|
74
|
+
request.basic_auth(@username, @password) if @username || @password
|
75
|
+
http = instantiate_http
|
76
|
+
http.start do
|
77
|
+
http.request(request)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|