health_check_rb 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.
- 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
|