Skip to content

Commit

Permalink
Merge branch 'ccc' into arbesulo-feat/add_ip_whitelisting
Browse files Browse the repository at this point in the history
  • Loading branch information
ianheggie committed Nov 28, 2016
2 parents 3d676f3 + 0551380 commit d7de5ee
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 54 deletions.
14 changes: 8 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ matrix:
# gemfile: test/rails_4.0.gemfile
# env: RAILS_ENV2=development RAILS_VERSION=4.0

- rvm: 2.1.2
gemfile: test/rails_4.2.gemfile
env: RAILS_SERVER=unicorn RAILS_VERSION=4.2 MIDDLEWARE=no
#= Dropped - server hangs around rather than exiting when signalled
#- rvm: 2.1.2
# gemfile: test/rails_4.2.gemfile
# env: RAILS_SERVER=unicorn RAILS_VERSION=4.2 MIDDLEWARE=no

# Disabled because it takes way too long (40+ mins)
# Temporary version lock until Bundler >= 1.13.2
Expand Down Expand Up @@ -142,9 +143,10 @@ matrix:
# gemfile: test/rails_4.0.gemfile
# env: RAILS_ENV2=development RAILS_VERSION=4.0 MIDDLEWARE=YES

- rvm: 2.1.2
gemfile: test/rails_4.2.gemfile
env: RAILS_SERVER=unicorn RAILS_VERSION=4.2 MIDDLEWARE=YES
#= Dropped - server hangs around rather than exiting when signalled
#- rvm: 2.1.2
# gemfile: test/rails_4.2.gemfile
# env: RAILS_SERVER=unicorn RAILS_VERSION=4.2 MIDDLEWARE=YES

# Disabled because it takes way too long (40+ mins)
# Temporary version lock until Bundler >= 1.13.2
Expand Down
19 changes: 12 additions & 7 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ To change the configuration of health_check, create a file `config/initializers/

HealthCheck.setup do |config|

# uri prefix
# uri prefix (no leading slash)
config.uri = 'health_check'

# Text output upon success
Expand Down Expand Up @@ -130,10 +130,10 @@ To change the configuration of health_check, create a file `config/initializers/
config.origin_ip_whitelist = %w(123.123.123.123)

# http status code used when the ip is not allowed for the request
config.http_status_for_ip_whitelist_error_text = 503
config.http_status_for_ip_whitelist_error_text = 403

# http status code used when the ip is not allowed for the request (json or xml)
config.http_status_for_ip_whitelist_error_object = 503
config.http_status_for_ip_whitelist_error_object = 403
end

You may call add_custom_check multiple times with different tests. These tests will be included in the default list ("standard").
Expand All @@ -143,15 +143,20 @@ If you have a catchall route then add the following line above the catch all rou

=== Installing As Middleware

Install health_check as middleware if you want to ignore exceptions from later parts of the Rails middleware stack,
eg DB connection errors from QueryCache. Include "middleware" in the list of checks to have the checks processed by the middleware
health check rather than the full stack check. The "middleware" check will fail if you have not installed health_check as middleware.
Install health_check as middleware if you want to sometimes ignore exceptions from later parts of the Rails middleware stack,
eg DB connection errors from QueryCache. The "middleware" check will fail if you have not installed health_check as middleware.

To install health_check as middleware add the following line to the config/application.rb:
config.middleware.insert_after "Rails::Rack::Logger", HealthCheck::MiddlewareHealthcheck

Note: health_check is installed as a full rails engine even if it has been installed as middleware. This is so the
standard checks continue to test the complete rails stack.
remaining checks continue to run through the complete rails stack.

You can also adjust what checks are run from middleware, eg if you want to exclude the checking of the database etc, then set
config.middleware_checks = ['middleware', 'standard', 'custom']
config.standard_checks = ['middleware', 'custom']

Middleware checks are run first, and then full stack checks.

== Uptime Monitoring

Expand Down
12 changes: 9 additions & 3 deletions lib/health_check.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ class Engine < Rails::Engine

# http status code used when the ip is not allowed for the request
mattr_accessor :http_status_for_ip_whitelist_error_text
self.http_status_for_ip_whitelist_error_text = 503
self.http_status_for_ip_whitelist_error_text = 403

# http status code used when the ip is not allowed for the request (json or xml)
mattr_accessor :http_status_for_ip_whitelist_error_object
self.http_status_for_ip_whitelist_error_object = 503
self.http_status_for_ip_whitelist_error_object = 403

# ips allowed to perform requests
mattr_accessor :origin_ip_whitelist
Expand All @@ -44,7 +44,7 @@ class Engine < Rails::Engine
mattr_accessor :buckets
self.buckets = {}

# health check uri path for middleware check
# health check uri path
mattr_accessor :uri
self.uri = 'health_check'

Expand All @@ -61,6 +61,12 @@ class Engine < Rails::Engine
self.full_checks = ['database', 'migrations', 'custom', 'email', 'cache', 'redis-if-present', 'sidekiq-redis-if-present', 'resque-redis-if-present', 's3-if-present']
self.standard_checks = [ 'database', 'migrations', 'custom', 'emailconf' ]

# Middleware based checks
mattr_accessor :middleware_checks
self.middleware_checks = [ 'middleware' ]

mattr_accessor :installed_as_middleware

def self.add_custom_check(&block)
custom_checks << block
end
Expand Down
48 changes: 21 additions & 27 deletions lib/health_check/health_check_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,19 @@ def index
end
public = (max_age > 1) && ! HealthCheck.basic_auth_username
if stale?(:last_modified => last_modified, :public => public)
checks = params[:checks] || 'standard'
checks = params[:checks] ? params[:checks].split('_') : ['standard']
checks -= HealthCheck.middleware_checks if HealthCheck.installed_as_middleware
begin
errors = HealthCheck::Utils.process_checks(checks)
rescue Exception => e
errors = e.message.blank? ? e.class.to_s : e.message.to_s
end
response.headers['Cache-control'] = (public ? 'public' : 'private') + ', no-cache, must-revalidate' + (max_age > 0 ? ", max-age=#{max_age}" : '')
if errors.blank?
obj = { :healthy => true, :message => HealthCheck.success }
respond_to do |format|
format.html { render plain_key => HealthCheck.success, :content_type => 'text/plain' }
format.json { render :json => obj }
format.xml { render :xml => obj }
format.any { render plain_key => HealthCheck.success, :content_type => 'text/plain' }
end
send_response nil, :ok, :ok
else
msg = "health_check failed: #{errors}"
obj = { :healthy => false, :message => msg }
respond_to do |format|
format.html { render plain_key => msg, :status => HealthCheck.http_status_for_error_text, :content_type => 'text/plain' }
format.json { render :json => obj, :status => HealthCheck.http_status_for_error_object}
format.xml { render :xml => obj, :status => HealthCheck.http_status_for_error_object }
format.any { render plain_key => msg, :status => HealthCheck.http_status_for_error_text, :content_type => 'text/plain' }
end
send_response msg, HealthCheck.http_status_for_error_text, HealthCheck.http_status_for_error_object
# Log a single line as some uptime checkers only record that it failed, not the text returned
if logger
logger.info msg
Expand All @@ -48,9 +37,20 @@ def index
end
end


protected

def send_response(msg, text_status, obj_status)
healthy = !msg
msg ||= HealthCheck.success
obj = { :healthy => healthy, :message => msg}
respond_to do |format|
format.html { render plain_key => msg, :status => text_status, :content_type => 'text/plain' }
format.json { render :json => obj, :status => obj_status }
format.xml { render :xml => obj, :status => obj_status }
format.any { render plain_key => msg, :status => text_status, :content_type => 'text/plain' }
end
end

def authenticate
return unless HealthCheck.basic_auth_username && HealthCheck.basic_auth_password
authenticate_or_request_with_http_basic do |username, password|
Expand All @@ -59,17 +59,11 @@ def authenticate
end

def check_origin_ip
return if HealthCheck.origin_ip_whitelist.blank?
return if HealthCheck.origin_ip_whitelist.any? { |whitelisted_ip| whitelisted_ip == request.ip }

msg = 'Health check is not allowed for the requesting IP'
obj = { :healthy => false, :message => msg }

respond_to do |format|
format.html { render plain_key => msg, :status => HealthCheck.http_status_for_ip_whitelist_error_text, :content_type => 'text/plain' }
format.json { render :json => obj, :status => HealthCheck.http_status_for_ip_whitelist_error_object}
format.xml { render :xml => obj, :status => HealthCheck.http_status_for_ip_whitelist_error_object }
format.any { render plain_key => msg, :status => HealthCheck.http_status_for_ip_whitelist_error_text, :content_type => 'text/plain' }
unless HealthCheck.origin_ip_whitelist.blank? ||
HealthCheck.origin_ip_whitelist.include?(request.ip)
send_response 'Health check is not allowed for the requesting IP',
HealthCheck.http_status_for_ip_whitelist_error_text,
HealthCheck.http_status_for_ip_whitelist_error_object
end
end

Expand Down
17 changes: 13 additions & 4 deletions lib/health_check/middleware_health_check.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ def initialize(app)

def call(env)
uri = env['PATH_INFO']
if uri =~ /^\/?#{HealthCheck.uri}\/([-_0-9a-zA-Z]*)middleware_?([-_0-9a-zA-Z]*)(\.(\w*))?/
checks = $1 + ($1 != '' && $2 != '' ? '_' : '') + $2
checks = 'standard' if checks == ''
if uri =~ /^\/#{Regexp.escape HealthCheck.uri}(\/([-_0-9a-zA-Z]*))?(\.(\w*))?$/
checks = $2.to_s == '' ? ['standard'] : $2.split('_')
response_type = $4
HealthCheck.installed_as_middleware = true
errors = ''
middleware_checks = checks & HealthCheck.middleware_checks
full_stack_checks = (checks - HealthCheck.middleware_checks) - ['and']

begin
errors = HealthCheck::Utils.process_checks(checks)
# Process the checks to be run from middleware
errors = HealthCheck::Utils.process_checks(middleware_checks, true)
# Process remaining checks through the full stack if there are any
unless full_stack_checks.empty?
return @app.call(env)
end
rescue => e
errors = e.message.blank? ? e.class.to_s : e.message.to_s
end
Expand Down
13 changes: 8 additions & 5 deletions lib/health_check/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ class Utils

cattr_accessor :default_smtp_settings

def self.process_checks(checks)
# process an array containing a list of checks
def self.process_checks(checks, called_from_middleware = false)
errors = ''
checks.split('_').each do |check|
checks.each do |check|
case check
when 'and', 'site'
# do nothing
Expand Down Expand Up @@ -63,15 +64,17 @@ def self.process_checks(checks)
when 's3'
errors << HealthCheck::S3HealthCheck.check
when "standard"
errors << HealthCheck::Utils.process_checks(HealthCheck.standard_checks.join('_'))
errors << HealthCheck::Utils.process_checks(HealthCheck.standard_checks, called_from_middleware)
when "middleware"
errors << "Health check not called from middleware - probably not installed as middleware." unless called_from_middleware
when "custom"
HealthCheck.custom_checks.each do |custom_check|
errors << custom_check.call(self)
end
when "all", "full"
errors << HealthCheck::Utils.process_checks(HealthCheck.full_checks.join('_'))
errors << HealthCheck::Utils.process_checks(HealthCheck.full_checks, called_from_middleware)
else
return "invalid argument to health_test. "
return "invalid argument to health_test."
end
end
return errors
Expand Down
12 changes: 10 additions & 2 deletions test/test_with_railsapp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ stop_server()
echo ========================================================
echo "Killing rails server [pid: $server_pid]"
kill -1 $server_pid || true
[ ! -x bin/spring ] || bin/spring stop || true
if [ -x bin/spring ] ; then
echo Stopping spring ...
bin/spring stop || true
fi
sleep 2
kill -9 $server_pid || true
;;
Expand All @@ -158,7 +161,10 @@ stop_server()
esac
server_pid=''
fake_smtp_pid=''
ps -f
echo Waiting for sub processes to complete ...
wait
echo Finished waiting for sub processes, sleeping 2 seconds ...
sleep 2
}

Expand Down Expand Up @@ -188,7 +194,9 @@ finish()
stop_server
trap "" 0
echo ========================================================
echo TEST ${1:-FAILED}
ps uxf || echo ps failed
echo ========================================================
echo TEST ${1:-FAILED}, exiting with status ${2:-2}
echo ========================================================
exit ${2:-2}
}
Expand Down

0 comments on commit d7de5ee

Please sign in to comment.