health_check_rb 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/linters.yml +27 -0
- data/.github/workflows/tests.yml +50 -0
- data/.gitignore +33 -0
- data/.rspec +1 -0
- data/.rubocop.yml +110 -0
- data/CHANGELOG +122 -0
- data/Gemfile +23 -0
- data/MIT-LICENSE +23 -0
- data/README.md +392 -0
- data/Rakefile +27 -0
- data/config/routes.rb +7 -0
- data/health_check_rb.gemspec +26 -0
- data/init.rb +3 -0
- data/lib/health_check_rb/base_health_check.rb +7 -0
- data/lib/health_check_rb/check/elasticsearch.rb +18 -0
- data/lib/health_check_rb/check/rabbitmq.rb +19 -0
- data/lib/health_check_rb/check/redis.rb +30 -0
- data/lib/health_check_rb/check/resque.rb +18 -0
- data/lib/health_check_rb/check/s3.rb +62 -0
- data/lib/health_check_rb/check/sidekiq.rb +20 -0
- data/lib/health_check_rb/health_check_controller.rb +80 -0
- data/lib/health_check_rb/health_check_routes.rb +18 -0
- data/lib/health_check_rb/middleware_health_check.rb +108 -0
- data/lib/health_check_rb/utils.rb +194 -0
- data/lib/health_check_rb/version.rb +5 -0
- data/lib/health_check_rb.rb +129 -0
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/assets/config/manifest.js +1 -0
- data/spec/dummy/app/controllers/example_controller.rb +7 -0
- data/spec/dummy/config/database.yml +10 -0
- data/spec/dummy/config/initializers/health_check.rb +18 -0
- data/spec/dummy/config/initializers/middleware.rb +3 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/db/migrate/.keep +0 -0
- data/spec/dummy/fake_app.rb +18 -0
- data/spec/dummy/tmp/.keep +0 -0
- data/spec/fixtures/migrate/9_create_countries.rb +9 -0
- data/spec/health_check_rb_spec.rb +300 -0
- data/spec/spec_helper.rb +36 -0
- metadata +101 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ipaddr'
|
4
|
+
|
5
|
+
module HealthCheckRb
|
6
|
+
class HealthCheckController < ActionController::Base
|
7
|
+
layout false if respond_to? :layout
|
8
|
+
before_action :check_origin_ip
|
9
|
+
before_action :authenticate
|
10
|
+
|
11
|
+
def index
|
12
|
+
last_modified = Time.now.utc
|
13
|
+
max_age = HealthCheckRb.max_age
|
14
|
+
last_modified = Time.at((last_modified.to_f / max_age).floor * max_age).utc if max_age > 1
|
15
|
+
is_public = (max_age > 1) && !HealthCheckRb.basic_auth_username
|
16
|
+
return unless stale? last_modified: last_modified, public: is_public
|
17
|
+
|
18
|
+
checks = params[:checks] ? params[:checks].split('_') : ['standard']
|
19
|
+
checks -= HealthCheckRb.middleware_checks if HealthCheckRb.installed_as_middleware
|
20
|
+
begin
|
21
|
+
errors = HealthCheckRb::Utils.process_checks checks
|
22
|
+
rescue StandardError => e
|
23
|
+
errors = e.message.blank? ? e.class.to_s : e.message.to_s
|
24
|
+
end
|
25
|
+
response.headers['Cache-Control'] = "must-revalidate, max-age=#{max_age}"
|
26
|
+
if errors.blank?
|
27
|
+
send_response true, nil, :ok, :ok
|
28
|
+
HealthCheckRb.success_callbacks&.each do |callback|
|
29
|
+
callback.call checks
|
30
|
+
end
|
31
|
+
else
|
32
|
+
msg = HealthCheckRb.include_error_in_response_body ? "#{HealthCheckRb.failure}: #{errors}" : nil
|
33
|
+
send_response false, msg, HealthCheckRb.http_status_for_error_text, HealthCheckRb.http_status_for_error_object
|
34
|
+
|
35
|
+
# Log a single line as some uptime checkers only record that it failed, not the text returned
|
36
|
+
msg = "#{HealthCheckRb.failure}: #{errors}"
|
37
|
+
logger.send HealthCheckRb.log_level, msg if logger && HealthCheckRb.log_level
|
38
|
+
HealthCheckRb.failure_callbacks&.each do |callback|
|
39
|
+
callback.call checks, msg
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def send_response(healthy, msg, text_status, obj_status)
|
47
|
+
msg ||= healthy ? HealthCheckRb.success : HealthCheckRb.failure
|
48
|
+
obj = { healthy: healthy, message: msg }
|
49
|
+
respond_to do |format|
|
50
|
+
format.html { render plain: msg, status: text_status, content_type: 'text/plain' }
|
51
|
+
format.json { render json: obj, status: obj_status }
|
52
|
+
format.xml { render xml: obj, status: obj_status }
|
53
|
+
format.any { render plain: msg, status: text_status, content_type: 'text/plain' }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def authenticate
|
58
|
+
return unless HealthCheckRb.basic_auth_username && HealthCheckRb.basic_auth_password
|
59
|
+
|
60
|
+
authenticate_or_request_with_http_basic 'Health Check' do |username, password|
|
61
|
+
username == HealthCheckRb.basic_auth_username && password == HealthCheckRb.basic_auth_password
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_origin_ip
|
66
|
+
request_ipaddr = IPAddr.new(HealthCheckRb.accept_proxied_requests ? request.remote_ip : request.ip)
|
67
|
+
unless HealthCheckRb.origin_ip_whitelist.blank? ||
|
68
|
+
HealthCheckRb.origin_ip_whitelist.any? { |addr| IPAddr.new(addr).include? request_ipaddr }
|
69
|
+
render plain: 'Health check is not allowed for the requesting IP',
|
70
|
+
status: HealthCheckRb.http_status_for_ip_whitelist_error,
|
71
|
+
content_type: 'text/plain'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# turn cookies for CSRF off
|
76
|
+
def protect_against_forgery?
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module Routing
|
5
|
+
class Mapper
|
6
|
+
def health_check_rb_routes(prefix = nil)
|
7
|
+
HealthCheckRb::Engine.routes_explicitly_defined = true
|
8
|
+
add_health_check_rb_routes prefix
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_health_check_rb_routes(prefix = nil)
|
12
|
+
HealthCheckRb.uri = prefix if prefix
|
13
|
+
match "#{HealthCheckRb.uri}(/:checks)(.:format)", controller: 'health_check_rb/health_check', action: :index, via: %i[get post],
|
14
|
+
defaults: { format: 'txt' }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ipaddr'
|
4
|
+
|
5
|
+
module HealthCheckRb
|
6
|
+
class MiddlewareHealthcheck
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
(response_type, middleware_checks, full_stack_checks) = parse_env env
|
13
|
+
if response_type
|
14
|
+
if (error_response = ip_blocked(env) || not_authenticated(env))
|
15
|
+
return error_response
|
16
|
+
end
|
17
|
+
|
18
|
+
HealthCheckRb.installed_as_middleware = true
|
19
|
+
errors = ''
|
20
|
+
begin
|
21
|
+
# Process the checks to be run from middleware
|
22
|
+
errors = HealthCheckRb::Utils.process_checks middleware_checks,
|
23
|
+
called_from_middleware: true
|
24
|
+
# Process remaining checks through the full stack if there are any
|
25
|
+
return @app.call env unless full_stack_checks.empty?
|
26
|
+
rescue StandardError => e
|
27
|
+
errors = e.message.blank? ? e.class.to_s : e.message.to_s
|
28
|
+
end
|
29
|
+
healthy = errors.blank?
|
30
|
+
msg = healthy ? HealthCheckRb.success : "health_check failed: #{errors}"
|
31
|
+
if response_type == 'xml'
|
32
|
+
content_type = 'text/xml'
|
33
|
+
msg = { healthy: healthy, message: msg }.to_xml
|
34
|
+
error_code = HealthCheckRb.http_status_for_error_object
|
35
|
+
elsif response_type == 'json'
|
36
|
+
content_type = 'application/json'
|
37
|
+
msg = { healthy: healthy, message: msg }.to_json
|
38
|
+
error_code = HealthCheckRb.http_status_for_error_object
|
39
|
+
else
|
40
|
+
content_type = 'text/plain'
|
41
|
+
error_code = HealthCheckRb.http_status_for_error_text
|
42
|
+
end
|
43
|
+
[(healthy ? 200 : error_code), { 'Content-Type' => content_type }, [msg]]
|
44
|
+
else
|
45
|
+
@app.call env
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def parse_env(env)
|
52
|
+
uri = env['PATH_INFO']
|
53
|
+
return unless uri =~ %r{^/#{Regexp.escape HealthCheckRb.uri}(/([-_0-9a-zA-Z]*))?(\.(\w*))?$}
|
54
|
+
|
55
|
+
checks = ::Regexp.last_match(2).to_s == '' ? ['standard'] : ::Regexp.last_match(2).split('_')
|
56
|
+
response_type = ::Regexp.last_match(4).to_s
|
57
|
+
middleware_checks = checks & HealthCheckRb.middleware_checks
|
58
|
+
full_stack_checks = (checks - HealthCheckRb.middleware_checks) - ['and']
|
59
|
+
[response_type, middleware_checks, full_stack_checks]
|
60
|
+
end
|
61
|
+
|
62
|
+
def ip_blocked(env)
|
63
|
+
return false if HealthCheckRb.origin_ip_whitelist.blank?
|
64
|
+
|
65
|
+
req = Rack::Request.new env
|
66
|
+
request_ipaddr = IPAddr.new req.ip
|
67
|
+
return if HealthCheckRb.origin_ip_whitelist.any? { |addr| IPAddr.new(addr).include? request_ipaddr }
|
68
|
+
|
69
|
+
[HealthCheckRb.http_status_for_ip_whitelist_error,
|
70
|
+
{ 'Content-Type' => 'text/plain' },
|
71
|
+
['Health check is not allowed for the requesting IP']]
|
72
|
+
end
|
73
|
+
|
74
|
+
def not_authenticated(env)
|
75
|
+
return false unless HealthCheckRb.basic_auth_username && HealthCheckRb.basic_auth_password
|
76
|
+
|
77
|
+
auth = MiddlewareHealthcheck::Request.new env
|
78
|
+
if auth.provided? && auth.basic? && Rack::Utils.secure_compare(HealthCheckRb.basic_auth_username,
|
79
|
+
auth.username) && Rack::Utils.secure_compare(
|
80
|
+
HealthCheckRb.basic_auth_password, auth.password
|
81
|
+
)
|
82
|
+
env['REMOTE_USER'] = auth.username
|
83
|
+
return false
|
84
|
+
end
|
85
|
+
[401,
|
86
|
+
{ 'Content-Type' => 'text/plain', 'WWW-Authenticate' => 'Basic realm="Health Check"' },
|
87
|
+
[]]
|
88
|
+
end
|
89
|
+
|
90
|
+
class Request < Rack::Auth::AbstractRequest
|
91
|
+
def basic?
|
92
|
+
scheme == 'basic'
|
93
|
+
end
|
94
|
+
|
95
|
+
def credentials
|
96
|
+
@credentials ||= params.unpack1('m*').split(':', 2)
|
97
|
+
end
|
98
|
+
|
99
|
+
def username
|
100
|
+
credentials.first
|
101
|
+
end
|
102
|
+
|
103
|
+
def password
|
104
|
+
credentials.last
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HealthCheckRb
|
4
|
+
class Utils
|
5
|
+
# TODO: convert class variables to better solution
|
6
|
+
# rubocop: disable Style/ClassVars
|
7
|
+
@@default_smtp_settings =
|
8
|
+
{
|
9
|
+
address: 'localhost',
|
10
|
+
port: 25,
|
11
|
+
domain: 'localhost.localdomain',
|
12
|
+
user_name: nil,
|
13
|
+
password: nil,
|
14
|
+
authentication: nil,
|
15
|
+
enable_starttls_auto: true
|
16
|
+
}
|
17
|
+
# rubocop: enable Style/ClassVars
|
18
|
+
|
19
|
+
cattr_writer :db_migrate_path
|
20
|
+
cattr_accessor :default_smtp_settings
|
21
|
+
|
22
|
+
class << self
|
23
|
+
# process an array containing a list of checks
|
24
|
+
def process_checks(checks, called_from_middleware: false)
|
25
|
+
errors = +''
|
26
|
+
checks.each do |check|
|
27
|
+
case check
|
28
|
+
when 'and', 'site'
|
29
|
+
# do nothing
|
30
|
+
when 'database'
|
31
|
+
HealthCheckRb::Utils.database_version
|
32
|
+
when 'email'
|
33
|
+
errors << HealthCheckRb::Utils.check_email
|
34
|
+
when 'emailconf'
|
35
|
+
errors << HealthCheckRb::Utils.check_email if HealthCheckRb::Utils.mailer_configured?
|
36
|
+
when 'migrations', 'migration'
|
37
|
+
if defined?(ActiveRecord::Migration) && ActiveRecord::Migration.respond_to?(:check_all_pending!)
|
38
|
+
# Rails 7.2+
|
39
|
+
begin
|
40
|
+
ActiveRecord::Migration.check_all_pending!
|
41
|
+
rescue ActiveRecord::PendingMigrationError => e
|
42
|
+
errors << e.message
|
43
|
+
end
|
44
|
+
else
|
45
|
+
database_version = HealthCheckRb::Utils.database_version
|
46
|
+
migration_version = HealthCheckRb::Utils.migration_version
|
47
|
+
if database_version.to_i != migration_version.to_i
|
48
|
+
errors << "Current database version (#{database_version}) does not match latest migration (#{migration_version}). "
|
49
|
+
end
|
50
|
+
end
|
51
|
+
when 'cache'
|
52
|
+
errors << HealthCheckRb::Utils.check_cache
|
53
|
+
when 'resque-redis-if-present'
|
54
|
+
errors << HealthCheckRb::Check::Resque.check if defined?(::Resque)
|
55
|
+
when 'sidekiq-redis-if-present'
|
56
|
+
errors << HealthCheckRb::Check::Sidekiq.check if defined?(::Sidekiq)
|
57
|
+
when 'redis-if-present'
|
58
|
+
errors << HealthCheckRb::CheckRedis.check if defined?(::Redis)
|
59
|
+
when 's3-if-present'
|
60
|
+
errors << HealthCheckRb::Check::S3.check if defined?(::Aws)
|
61
|
+
when 'elasticsearch-if-present'
|
62
|
+
errors << HealthCheckRb::Check::Elasticsearch.check if defined?(::Elasticsearch)
|
63
|
+
when 'resque-redis'
|
64
|
+
errors << HealthCheckRb::Check::Resque.check
|
65
|
+
when 'sidekiq-redis'
|
66
|
+
errors << HealthCheckRb::Check::Sidekiq.check
|
67
|
+
when 'redis'
|
68
|
+
errors << HealthCheckRb::Check::Redis.check
|
69
|
+
when 's3'
|
70
|
+
errors << HealthCheckRb::Check::S3.check
|
71
|
+
when 'elasticsearch'
|
72
|
+
errors << HealthCheckRb::Check::Elasticsearch.check
|
73
|
+
when 'rabbitmq'
|
74
|
+
errors << HealthCheckRb::Check::RabbitMQ.check
|
75
|
+
when 'standard'
|
76
|
+
errors << HealthCheckRb::Utils.process_checks(HealthCheckRb.standard_checks, called_from_middleware:)
|
77
|
+
when 'middleware'
|
78
|
+
errors << 'Health check not called from middleware - probably not installed as middleware.' unless called_from_middleware
|
79
|
+
when 'custom'
|
80
|
+
HealthCheckRb.custom_checks.each_value do |list|
|
81
|
+
list.each do |custom_check|
|
82
|
+
errors << custom_check.call(self)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
when 'all', 'full'
|
86
|
+
errors << HealthCheckRb::Utils.process_checks(HealthCheckRb.full_checks, called_from_middleware:)
|
87
|
+
else
|
88
|
+
return 'invalid argument to health_test.' unless HealthCheckRb.custom_checks.include? check
|
89
|
+
|
90
|
+
HealthCheckRb.custom_checks[check].each do |custom_check|
|
91
|
+
errors << custom_check.call(self)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
errors << '. ' unless errors == '' || errors.end_with?('. ')
|
96
|
+
end
|
97
|
+
errors.strip
|
98
|
+
rescue StandardError => e
|
99
|
+
e.message
|
100
|
+
end
|
101
|
+
|
102
|
+
def db_migrate_path
|
103
|
+
# Lazy initialisation so Rails.root will be defined
|
104
|
+
@db_migrate_path ||= Rails.root.join 'db', 'migrate'.to_s
|
105
|
+
end
|
106
|
+
|
107
|
+
def mailer_configured?
|
108
|
+
defined?(ActionMailer::Base) &&
|
109
|
+
(ActionMailer::Base.delivery_method != :smtp ||
|
110
|
+
HealthCheckRb::Utils.default_smtp_settings != ActionMailer::Base.smtp_settings)
|
111
|
+
end
|
112
|
+
|
113
|
+
def database_version
|
114
|
+
ActiveRecord::Migrator.current_version if defined?(ActiveRecord)
|
115
|
+
end
|
116
|
+
|
117
|
+
def migration_version(dir = db_migrate_path)
|
118
|
+
latest_migration = nil
|
119
|
+
Dir[File.join(dir, '[0-9]*_*.rb')].each do |f|
|
120
|
+
l = begin
|
121
|
+
f.scan(/0*([0-9]+)_[_.a-zA-Z0-9]*.rb/).first.first
|
122
|
+
rescue StandardError
|
123
|
+
-1
|
124
|
+
end
|
125
|
+
latest_migration = l if !latest_migration || l.to_i > latest_migration.to_i
|
126
|
+
end
|
127
|
+
latest_migration
|
128
|
+
end
|
129
|
+
|
130
|
+
def check_email
|
131
|
+
case ActionMailer::Base.delivery_method
|
132
|
+
when :smtp
|
133
|
+
HealthCheckRb::Utils.check_smtp(ActionMailer::Base.smtp_settings, HealthCheckRb.smtp_timeout)
|
134
|
+
when :sendmail
|
135
|
+
HealthCheckRb::Utils.check_sendmail(ActionMailer::Base.sendmail_settings)
|
136
|
+
else
|
137
|
+
''
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def check_sendmail(settings)
|
142
|
+
File.executable?(settings[:location]) ? '' : 'no sendmail executable found. '
|
143
|
+
end
|
144
|
+
|
145
|
+
def check_smtp(settings, timeout)
|
146
|
+
begin
|
147
|
+
if @skip_external_checks
|
148
|
+
status = '250'
|
149
|
+
else
|
150
|
+
smtp = Net::SMTP.new settings[:address], settings[:port]
|
151
|
+
openssl_verify_mode = settings[:openssl_verify_mode]
|
152
|
+
|
153
|
+
openssl_verify_mode = OpenSSL::SSL.const_get("VERIFY_#{openssl_verify_mode.upcase}") if openssl_verify_mode.is_a? String
|
154
|
+
|
155
|
+
ssl_context = Net::SMTP.default_ssl_context
|
156
|
+
ssl_context.verify_mode = openssl_verify_mode if openssl_verify_mode
|
157
|
+
smtp.enable_starttls ssl_context if settings[:enable_starttls_auto]
|
158
|
+
smtp.open_timeout = timeout
|
159
|
+
smtp.read_timeout = timeout
|
160
|
+
smtp.start settings[:domain], settings[:user_name], settings[:password], settings[:authentication] do
|
161
|
+
status = smtp.helo(settings[:domain]).status
|
162
|
+
end
|
163
|
+
end
|
164
|
+
rescue StandardError => e
|
165
|
+
status = e.to_s
|
166
|
+
end
|
167
|
+
/^250/.match?(status) ? '' : "SMTP: #{status || 'unexpected error'}. "
|
168
|
+
end
|
169
|
+
|
170
|
+
def check_cache
|
171
|
+
t = Time.now.to_i
|
172
|
+
value = "ok #{t}"
|
173
|
+
ret = ::Rails.cache.read '__health_check_cache_test__'
|
174
|
+
if ret.to_s =~ /^ok (\d+)$/
|
175
|
+
diff = (::Regexp.last_match(1).to_i - t).abs
|
176
|
+
return('Cache expiry is broken. ') if diff > 30
|
177
|
+
elsif ret
|
178
|
+
return 'Cache is returning garbage. '
|
179
|
+
end
|
180
|
+
if ::Rails.cache.write '__health_check_cache_test__', value, expires_in: 2.seconds
|
181
|
+
ret = ::Rails.cache.read '__health_check_cache_test__'
|
182
|
+
if ret =~ /^ok (\d+)$/
|
183
|
+
diff = (::Regexp.last_match(1).to_i - t).abs
|
184
|
+
(diff < 2 ? '' : 'Out of date cache or time is skewed. ')
|
185
|
+
else
|
186
|
+
'Unable to read from cache. '
|
187
|
+
end
|
188
|
+
else
|
189
|
+
'Unable to write to cache. '
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HealthCheckRb
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
cattr_accessor :routes_explicitly_defined
|
6
|
+
end
|
7
|
+
|
8
|
+
# Log level
|
9
|
+
mattr_accessor :log_level
|
10
|
+
self.log_level = 'info'
|
11
|
+
|
12
|
+
# Text output upon success
|
13
|
+
mattr_accessor :success
|
14
|
+
self.success = 'success'
|
15
|
+
|
16
|
+
# Text output upon failure
|
17
|
+
mattr_accessor :failure
|
18
|
+
self.failure = 'health_check failed'
|
19
|
+
|
20
|
+
# Timeout in seconds used when checking smtp server
|
21
|
+
mattr_accessor :smtp_timeout
|
22
|
+
self.smtp_timeout = 30.0
|
23
|
+
|
24
|
+
# http status code used when plain text error message is output
|
25
|
+
mattr_accessor :http_status_for_error_text
|
26
|
+
self.http_status_for_error_text = 500
|
27
|
+
|
28
|
+
# http status code used when an error object is output (json or xml)
|
29
|
+
mattr_accessor :http_status_for_error_object
|
30
|
+
self.http_status_for_error_object = 500
|
31
|
+
|
32
|
+
# http status code used when the ip is not allowed for the request
|
33
|
+
mattr_accessor :http_status_for_ip_whitelist_error
|
34
|
+
self.http_status_for_ip_whitelist_error = 403
|
35
|
+
|
36
|
+
# check remote_ip rather than ip for ip whitelist
|
37
|
+
mattr_accessor :accept_proxied_requests
|
38
|
+
self.accept_proxied_requests = false
|
39
|
+
|
40
|
+
# ips allowed to perform requests
|
41
|
+
mattr_accessor :origin_ip_whitelist
|
42
|
+
self.origin_ip_whitelist = []
|
43
|
+
|
44
|
+
# max-age of response in seconds
|
45
|
+
# cache-control is public when max_age > 1 and basic authentication is used
|
46
|
+
mattr_accessor :max_age
|
47
|
+
self.max_age = 1
|
48
|
+
|
49
|
+
# s3 buckets
|
50
|
+
mattr_accessor :buckets
|
51
|
+
self.buckets = {}
|
52
|
+
|
53
|
+
# rabbitmq
|
54
|
+
mattr_accessor :rabbitmq_config
|
55
|
+
self.rabbitmq_config = {}
|
56
|
+
|
57
|
+
# health check uri path
|
58
|
+
mattr_accessor :uri
|
59
|
+
self.uri = 'health_check'
|
60
|
+
|
61
|
+
# Basic Authentication
|
62
|
+
mattr_accessor :basic_auth_username, :basic_auth_password
|
63
|
+
self.basic_auth_username = nil
|
64
|
+
self.basic_auth_password = nil
|
65
|
+
|
66
|
+
# Array of custom check blocks
|
67
|
+
mattr_accessor :custom_checks
|
68
|
+
mattr_accessor :full_checks
|
69
|
+
mattr_accessor :standard_checks
|
70
|
+
self.custom_checks = {}
|
71
|
+
self.full_checks = %w[database migrations custom email cache redis-if-present sidekiq-redis-if-present
|
72
|
+
resque-redis-if-present s3-if-present elasticsearch-if-present]
|
73
|
+
self.standard_checks = %w[database migrations custom emailconf]
|
74
|
+
|
75
|
+
# Middleware based checks
|
76
|
+
mattr_accessor :middleware_checks
|
77
|
+
self.middleware_checks = ['middleware']
|
78
|
+
|
79
|
+
mattr_accessor :installed_as_middleware
|
80
|
+
|
81
|
+
# Allow non-standard redis url and password
|
82
|
+
mattr_accessor :redis_url
|
83
|
+
self.redis_url = ENV.fetch 'REDIS_URL', nil
|
84
|
+
|
85
|
+
mattr_accessor :redis_password
|
86
|
+
self.redis_password = ENV.fetch 'REDIS_PASSWORD', nil
|
87
|
+
|
88
|
+
# Include the error in the response body.
|
89
|
+
# You should only do this where your /health_check endpoint is NOT open to the public internet
|
90
|
+
mattr_accessor :include_error_in_response_body
|
91
|
+
self.include_error_in_response_body = false
|
92
|
+
|
93
|
+
# used for on_failure and on_success
|
94
|
+
mattr_accessor :success_callbacks
|
95
|
+
mattr_accessor :failure_callbacks
|
96
|
+
|
97
|
+
def self.add_custom_check(name = 'custom', &block)
|
98
|
+
custom_checks[name] ||= []
|
99
|
+
custom_checks[name] << block
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.on_success(&block)
|
103
|
+
success_callbacks ||= []
|
104
|
+
success_callbacks << block
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.on_failure(&block)
|
108
|
+
failure_callbacks ||= []
|
109
|
+
failure_callbacks << block
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.setup
|
113
|
+
yield self
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
require 'health_check_rb/version'
|
118
|
+
require 'health_check_rb/base_health_check'
|
119
|
+
require 'health_check_rb/utils'
|
120
|
+
require 'health_check_rb/health_check_controller'
|
121
|
+
require 'health_check_rb/health_check_routes'
|
122
|
+
require 'health_check_rb/middleware_health_check'
|
123
|
+
|
124
|
+
require 'health_check_rb/check/resque'
|
125
|
+
require 'health_check_rb/check/s3'
|
126
|
+
require 'health_check_rb/check/redis'
|
127
|
+
require 'health_check_rb/check/elasticsearch'
|
128
|
+
require 'health_check_rb/check/sidekiq'
|
129
|
+
require 'health_check_rb/check/rabbitmq'
|
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
4
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
5
|
+
|
6
|
+
require File.expand_path('./fake_app', __dir__)
|
7
|
+
|
8
|
+
Rails.application.load_tasks
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
CUSTOM_CHECK_FILE_PATH = 'spec/dummy/tmp/custom_file'
|
4
|
+
|
5
|
+
HealthCheckRb.setup do |config|
|
6
|
+
config.success = 'custom_success_message'
|
7
|
+
config.http_status_for_error_text = 550
|
8
|
+
config.http_status_for_error_object = 555
|
9
|
+
config.uri = 'custom_route_prefix'
|
10
|
+
|
11
|
+
config.add_custom_check do
|
12
|
+
File.exist?(CUSTOM_CHECK_FILE_PATH) ? '' : 'custom_file is missing!'
|
13
|
+
end
|
14
|
+
|
15
|
+
config.add_custom_check 'pass' do
|
16
|
+
''
|
17
|
+
end
|
18
|
+
end
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Bundler.setup
|
4
|
+
require 'rails'
|
5
|
+
require 'rails/all'
|
6
|
+
require 'health_check_rb'
|
7
|
+
Bundler.require
|
8
|
+
|
9
|
+
FakeApp = Class.new Rails::Application
|
10
|
+
ENV['RAILS_ENV'] ||= 'test'
|
11
|
+
FakeApp.config.eager_load = false
|
12
|
+
FakeApp.config.session_store :cookie_store, key: '_myapp_session'
|
13
|
+
FakeApp.config.root = File.dirname __FILE__
|
14
|
+
FakeApp.config.action_mailer.delivery_method = :smtp
|
15
|
+
FakeApp.config.action_mailer.smtp_settings = { address: 'localhost', port: 3555, openssl_verify_mode: OpenSSL::SSL::VERIFY_NONE,
|
16
|
+
enable_starttls_auto: true }
|
17
|
+
FakeApp.config.secret_key_base = SecureRandom.hex 64
|
18
|
+
FakeApp.initialize!
|
File without changes
|