health_check-3.0.0/0000755000175000017510000000000013411314717013517 5ustar avronravronrhealth_check-3.0.0/.gitignore0000644000175000017510000000055513411314717015514 0ustar avronravronr# Suggested by bundler *.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp .ruby-version ## PROJECT::SPECIFIC bin/ test/bin/ railsapps/ test/*.gemfile.lock ,* # See: https://gist.github.com/ianheggie/9327010 # for Global git ignore for OS/IDE/temp/backup files health_check-3.0.0/.document0000644000175000017510000000007413411314717015337 0ustar avronravronrREADME.rdoc lib/**/*.rb bin/* features/**/*.feature LICENSE health_check-3.0.0/init.rb0000644000175000017510000000003013411314717015000 0ustar avronravronrrequire 'health_check' health_check-3.0.0/CHANGELOG0000644000175000017510000001120013411314717014723 0ustar avronravronr= Change Log = * 3.0.0 * First release on rails5 branch * Depends on railties rather than rails so it can be used with trimmed down stacks * Corrected ruby version required to match rails * Cleaned up README * redis_url now defaults to nil (url determined by redis gem) * Cleaned out rails 4.0 dependent code * Cleaned up test code and updated to rails 5 standards, uses smarter_bundler to handle gem ruby version isssues * Added rails 5.1 test * Split all releases to this rails* branchs - master is only for edge development * 2.7.0 * Add ability to check health of redis when url is non-standard redis url * 2.6.0 * Add named custom checks * 2.5.0 * Added whitelist for IP# (Thanks Fernando Alvarez) * reworked whitelist PR * Expanded tests for whitelist and basic authentication * reworked middleware, simplified error codes, added whitelist and basic authentication into middleware * Removed unit tests as they where aonly applicable under rails 2.3 when installed in vendor/plugins * #55 by mnoack - correct binstubs arg in test * #54 by gkop - Lograge config snippet works with Rails 4.2.7.1, lograge 0.4.1 * Used ideas from #52 - use middleware to catch Rails stack exceptions * #51 by tokenshift - Fixing NameError on `basic_auth_username`. * Changes to address #50 by fillphafftek - allow standard check to be run from middleware if configured to do so, removed requirement for "middleware" to be passed in url for middleware tests * 2.4.0 * Added tests for middleware * Changed contributed middleware code to conform to existing url scheme * Allow both GET and POST calls * Prefer config.uri for changing route prefix * 2.3.0 * Fix route reload issue * Various fixes to get tests working with bundle/jruby and other gem issues * Document additional branches * Fix route reload issue (auto routing previosuly conflicted with devise) * Removed ref to rails 2.3, 3.* * 2.2.1 * Adjust private/public cache-control based on max_age set * 2.2.0 * Add max_age so we can control the caching of responses, don't run tests if Last-modified still matches * Added basic auth - Thanks omadahealth * A few macinations due to gem changes and avoidning triggering deprecation notices * Add single quote to README to make the configuration file valid - Thanks Ryan Selk * Fixed README formatting * 2.1.0 * Updated contributed tests so there is both the forced check and a *-if-present check which tests if the gem's class is loaded * Added resque-redis check - Thanks filiphaftek * In addition to adding a test file to S3, we will also try to delete it to confirm that delete operations are possible - Thanks Anton Dimitrov * Added redis, sidekiq-redis and s3 health-checks - Thanks Filip * Fix render options - Thanks Yuji Hanamura * Fix to always return a 200 status code on success rather than 304 (adds Last-Modified) - Thanks macgregordennis * Added Rails 5.0 tests * 2.0.0 - Removed silence - recommend to use a log filtering gem instead * 1.4.1 - Rails 4 and route changes * Now handles routes being generated multiple times by some gem / rails / ruby combinations - Previously multiple calls to health_check_routes where ignored, now explicit calls to health_check_route always adds the route but flags that it doesn't have to be added again on the end of the list * Uses ActiveRecord::Migration.check_pending! if available and returns the message if an exception is raised (Rails 4.0+) * Simplified routing rules down to one rule for Rails 3.0+ * Includes some changes for rails 4.1 (edge) - but still a work in progress * 1.3.1 - Include changes from contributers: * Migrations with dots are now handled * the list of checks for "full" / "all" can be configured * 1.2.0 - The gem can now be configured, including timeouts, status codes and text returned on success - Customn checks can be added via initializer like config.add_custom_check { CustomCheckClass.a_custom_check } - You can now request the response to be json or xml (via url or Content-accepted header) - reduced tests to the versions of ruby recomended for the different versions of rails * 1.1.2 - Change to bundler support for building gems, as jeweler gem was broken by v2.0.0 of rubygems * 1.1.0 - Include cache check (Thanks to https://github.com/mgomes1 ) and some changes to test setup to workaround and diagnose test failures under rvm * 1.0.2 - Included travis config and gemfiles used in travis tests in gem and changes to test setup so that gem test * 1.x - Includes Rails 3.x suppprt as an Engine * 0.x - Rails 2.3 health_check-3.0.0/Gemfile0000644000175000017510000000100613411314717015007 0ustar avronravronrsource 'https://rubygems.org' # Specify your gem's dependencies in health_check.gemspec gemspec group :development, :test do if defined?(JRUBY_VERSION) gem 'jruby-openssl' gem 'activerecord-jdbcsqlite3-adapter' else gem 'sqlite3', '~> 1.3.7' end # run travis-lint to check .travis.yml gem 'travis-lint' # mime-types 2.0 requires Ruby version >= 1.9.2 # mime-types 3.0 requires Ruby version >= 2.0 gem 'mime-types', defined?(JRUBY_VERSION) || RUBY_VERSION < '2.0' ? '< 3' : '>= 3.0' end health_check-3.0.0/config/0000755000175000017510000000000013411314717014764 5ustar avronravronrhealth_check-3.0.0/config/routes.rb0000644000175000017510000000020013411314717016622 0ustar avronravronrunless HealthCheck::Engine.routes_explicitly_defined Rails.application.routes.draw do add_health_check_routes() end end health_check-3.0.0/MIT-LICENSE0000644000175000017510000000206013411314717015151 0ustar avronravronrCopyright (c) 2010-2013 Ian Heggie MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. health_check-3.0.0/test/0000755000175000017510000000000013411314717014476 5ustar avronravronrhealth_check-3.0.0/test/init_variables0000644000175000017510000000257313411314717017423 0ustar avronravronr#!/bin/bash # Any failure causes exit set -e echo Setting RAILS_ENV=test RACK_ENV=test export RAILS_ENV=test RACK_ENV=test base_dir=$PWD tmp_dir=$base_dir/tmp railsapp=$tmp_dir/railsapp custom_file="$railsapp/tmp/custom_check.ok" catchall_file="$railsapp/tmp/catchall_route.enabled" success=successful rehash='' rbenv_which='which' if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then echo "Detected user installed rvm" elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then echo "Detected root installed rvm" elif [[ -d "$HOME/.rbenv" ]] ; then echo "Detected rbenv: `rbenv version`" rehash='rbenv rehash' rbenv_which='rbenv which' else printf "Note: Neither rvm nor rbenv was not found.\n" fi echo "Checking required commands exist:" for cmd in bash gem egrep ls tail kill find cpio do echo -n " " which $cmd || ( echo "Aborting setup_railsapp: Missing $cmd command!" && exit 2 ) done for cmd in ruby gem do echo -n " " $rbenv_which $cmd || ( echo "Aborting setup_railsapp: Missing $cmd command!" && exit 2 ) done rails="rails" rake="rake" if [ -x $base_dir/test/bin/rails ] then rails="$base_dir/test/bin/rails" rake="$base_dir/test/bin/rake" export PATH="$base_dir/test/bin:$PATH" fi if [ -x $railsapp/bin/rails ] then rails="$railsapp/bin/rails" rake="$railsapp/bin/rake" export PATH="$railsapp/bin:$PATH" fi echo "Using rails=$rails, rake=$rake" health_check-3.0.0/test/test_with_railsapp0000755000175000017510000005116213411314717020336 0ustar avronravronr#!/bin/bash route_prefix=medical_check err_report() { echo "$0: Error on line $1 - aborted" exit 1 } trap 'err_report $LINENO' ERR # Any failure causes exit set -e export DISABLE_SPRING=1 cleanup_db() { echo Dropping database ... $rake db:drop echo Removing migrations ... rm -f db/migrate/* db/schema.rb case `ruby -e 'puts JRUBY_VERSION' 2> /dev/null` in [0-9]*) echo 'Jruby requires the database to be created before the server is started: running rake db:migrate' $rake db:migrate ;; esac } case "$1" in redo) . test/init_variables cd $railsapp cleanup_db actual_rails_version=`$rails -v` ;; *) . test/setup_railsapp $1 ;; esac run_test=$2 cd $railsapp date > $custom_file rm -f $catchall_file case `egrep '^[^#]*MiddlewareHealthcheck' config/application.rb` in '') export has_middleware=false ;; ?*) export has_middleware=true ;; esac testurl="$base_dir/test/testurl" fake_smtp_server="$base_dir/test/fake_smtp_server" server_pid='' fake_smtp_pid='' pick_a_port() { while : do port=`expr 10000 + $RANDOM` # Check Tcp ports in Listen mode with No address resolution if (netstat -tln | egrep ":${port} .*:"); then echo "(Skipping used port)" else break fi done } start_server() { # restart migration list rm -rf db/migrate db/schema.rb mkdir -p db/migrate # Increment port each time to make sure we have not trouble with address/port already allocated pick_a_port host=http://127.0.0.1:${port} bundle_prefix='' if [ -f Gemfile ] then bundle_prefix='bundle exec' fi server_arg=${RAILS_SERVER:-webrick} echo "start_server called using: `env | egrep '^RAILS|^RACK|^PATH='` $bundle_prefix $server_arg" case "$server_arg" in puma) $bundle_prefix puma -b tcp://127.0.0.1:$port & ;; passenger) $bundle_prefix passenger start -p $port & ;; thin) $bundle_prefix thin start -p $port & ;; unicorn) $bundle_prefix unicorn_rails -l 127.0.0.1:$port & ;; *) if [ -x script/server ] then echo Starting server on port $port using $bundle_prefix ./script/server ... $bundle_prefix ./script/server $server_arg -p $port & else echo Starting server on port $port using $rails s ... $bundle_prefix $rails server $server_arg -p $port & fi ;; esac server_pid=$! echo Server pid: $server_pid sleep 3 echo echo 'Checking server is up ...' for i in 1 2 3 4 5 6 do if $testurl ${host}/static.txt ; then break fi if kill -0 $server_pid ; then echo "waiting ${i} ..." else echo "ERROR: Server has died!!" exit 3 fi done } stop_server() { case "$server_pid" in [0-9]*) echo ======================================================== echo "Killing rails server [pid: $server_pid]" kill -QUIT $server_pid || echo server has already exited .. if [ -x bin/spring ] ; then echo Stopping spring ... bin/spring stop || echo spring had already exited .. fi sleep 1 kill -9 $server_pid || echo server had already exited ... sleep 1 # needed for unicorn - it doesn't die when it is supposed to killall "$server_arg" || echo server and child processes had already stopped ... ;; esac case "$fake_smtp_pid" in [0-9]*) echo ======================================================== echo "Killing fake smtp server [pid: $fake_smtp_pid]" kill -QUIT $fake_smtp_pid || echo fake_smtp had already exited .. sleep 2 kill -9 $fake_smtp_pid || echo fake_smtp had already exited .. ;; 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 } finish() { set +e echo ======================================================== echo TEST ${1:-FAILED} echo ======================================================== echo Result of: ls -lR $railsapp/log $railsapp/db ls -lR $railsapp/log $railsapp/db if [ -s $railsapp/log/test.log ] then echo ======================================================== echo Last 50 lines of test log tail -50 $railsapp/log/test.log fi if [ -s $railsapp/log/production.log ] then echo ======================================================== echo Last 50 lines of production log tail -50 $railsapp/log/production.log fi stop_server trap "" 0 echo ======================================================== ps uxf || echo ps failed echo ======================================================== echo TEST ${1:-FAILED}, exiting with status ${2:-2} echo ======================================================== exit ${2:-2} } trap "finish FAILED 1" 0 common_tests() { test_no=$1 if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: CHECKING routes exist..." $rake routes | tee /tmp/t$$ echo case `egrep ${route_prefix} /tmp/t$$ || true` in '') echo WARNING - routes for ${route_prefix} not listed! ;; esac echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING can get a static file ..." case "$RAILS_ENV=`egrep '^\s*config.serve_static_[asetfil]* *= *false' config/environments/${RAILS_ENV}.rb`" in production*static*false*) echo " SKIPPED (disabled in production)" ;; *) grep serve_static_files config/environments/${RAILS_ENV}.rb config/[a-z]*.rb || echo no serve_static_files entry $testurl ${host}/static.txt 200 text/plain STATIC-FILE ;; esac echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING can get an example controller ..." $testurl ${host}/example 200 text/plain 'example page' echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING direct call to catchall method on example controller ..." $testurl ${host}/example/catchall 200 text/plain 'catch all route' echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/migration should pass with no database migrations ..." ls db/migrate $testurl ${host}/${route_prefix}/migration 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/migration should fail without initial database migration ..." cp $base_dir/test/migrate/nine/* db/migrate ls db/migrate $testurl ${host}/${route_prefix}/migration 550 text/plain failed echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/database should pass without initial database migration (since it ignores the difference) ..." $testurl ${host}/${route_prefix}/database 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/site should pass ..." $testurl ${host}/${route_prefix}/site 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/migration should pass after initial database migration ..." $rake db:migrate $testurl ${host}/${route_prefix}/migration 200 text/plain $success echo fi #test with coruppted DB rm -rf db.bak cp -R db db.bak for f in db/*.sqlite3 do echo CORRUPTED > $f done test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/database should fail if the database has been corrupted ..." $testurl ${host}/${route_prefix}/database 550 text/plain failed echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/site should pass ..." $testurl ${host}/${route_prefix}/site 200 text/plain $success if $has_middleware; then echo "${test_no}: TESTING ${route_prefix}/middleware_site should pass ..." $testurl ${host}/${route_prefix}/middleware_site 200 text/plain $success fi echo fi # Restore database cp -f db.bak/*.sqlite3 db/ test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/migration should fail without all migrations ..." cp $base_dir/test/migrate/twelve/* db/migrate ls db/migrate $testurl ${host}/${route_prefix}/migration 550 text/plain failed echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/migration should pass after both database migrations ..." $rake db:migrate $testurl ${host}/${route_prefix}/migration 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/migration should pass after both database migrations ..." $rake db:migrate $testurl ${host}/${route_prefix}/migration 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/email should fail without smtp available ..." $testurl ${host}/${route_prefix}/email 550 text/plain failed echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/email should pass with smtp available ..." $fake_smtp_server & fake_smtp_pid=$! sleep 5 $testurl ${host}/${route_prefix}/email 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix} (all) should fail without smtp available ..." $testurl ${host}/${route_prefix} 550 text/plain failed echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/all should fail without smtp available ..." $testurl ${host}/${route_prefix} 550 text/plain failed echo fi kill -9 $fake_smtp_pid || echo fake_smtp_server had finished as expected test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix} (all) should pass with smtp available ..." $fake_smtp_server & fake_smtp_pid=$! sleep 5 $testurl ${host}/${route_prefix} 200 text/plain $success echo fi kill -9 $fake_smtp_pid || echo fake_smtp_server had finished as expected test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/all should pass with smtp available ..." $fake_smtp_server & fake_smtp_pid=$! sleep 5 $testurl ${host}/${route_prefix}/all 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/pass should pass ..." $testurl ${host}/${route_prefix}/pass 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/custom should pass ..." $testurl ${host}/${route_prefix}/custom 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/custom.html should pass (returning plain text) ..." $testurl ${host}/${route_prefix}/custom.html 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/custom.json should pass ..." $testurl ${host}/${route_prefix}/custom.json 200 application/json '"healthy":true' $testurl ${host}/${route_prefix}/custom.json 200 application/json "\"message\":\"$success\"" echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/custom.xml should pass ..." $testurl ${host}/${route_prefix}/custom.xml 200 application/xml 'true' $testurl ${host}/${route_prefix}/custom.xml 200 application/xml "$success" echo fi test_no=`expr 1 + $test_no` rm -f $custom_file if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/custom should fail when custom returns string ..." $testurl ${host}/${route_prefix}/custom 550 text/plain failed echo fi if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}/pass should pass even if other custom test returns string ..." $testurl ${host}/${route_prefix}/pass 200 text/plain $success echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix} (all) should fail when custom check fails ..." $testurl ${host}/${route_prefix} 550 text/plain "$custom_file is missing!" echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}.json (all) should fail when custom check fails ..." $testurl ${host}/${route_prefix}.json 555 application/json '"healthy":false' $testurl ${host}/${route_prefix}.json 555 application/json "$custom_file is missing!" echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING ${route_prefix}.xml (all) should fail when custom check fails ..." $testurl ${host}/${route_prefix}.xml 555 application/xml 'false' echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then if $has_middleware; then echo "${test_no}: TESTING ${route_prefix}/middleware_site should pass ..." $testurl ${host}/${route_prefix}/middleware_site 200 text/plain $success else echo "${test_no}: TESTING ${route_prefix}/middleware_site should fail ..." $testurl ${host}/${route_prefix}/middleware_site 550 text/plain failed fi echo fi test_no=`expr 1 + $test_no` if [ -z "$run_test" ] || [ $test_no == "$run_test" ]; then echo "${test_no}: TESTING log files to check for deprecation warnings ..." if egrep ' is deprecated|DEPRECATION WARNING' $railsapp/log/[tp][er][so][td]*.log then echo Found deprecation warnings - failed test exit 99 fi fi date > $custom_file } # required for rails 4.1+ in production mode export SECRET_KEY_BASE=cf2f49c38a3fe67416ddf680f4f3187c0fce7dd1b9b117b34d195df75b274e08a04877e23803b2fdf1aa9a655269d94bc4888aa325cf7e721cc47368cfe56a80 # required for rails 5 to server static files export RAILS_SERVE_STATIC_FILES=on export IP_WHITELIST='123.123.123.123' unset AUTH_USER unset AUTH_PASSWORD case "$run_test" in ''|[12]) echo ======================================================== echo TESTING whitelist ban WITHOUT CATCHALL in test env echo ======================================================== export RAILS_ENV=test RACK_ENV=test start_server echo '1: TESTING controller prohibited by ip...' expected_status=403 $testurl ${host}/${route_prefix}/site $expected_status if $has_middleware; then echo echo '2: TESTING middleware prohibited by ip...' expected_status=403 $testurl ${host}/${route_prefix}/middleware $expected_status fi ;; esac export IP_WHITELIST='' export AUTH_USER='someone' export AUTH_PASSWORD='secret' case "$run_test" in ''|[3456789]|10) echo ======================================================== echo TESTING basic auth, no whitelist WITHOUT CATCHALL in test env echo ======================================================== export RAILS_ENV=test RACK_ENV=test case "$run_trest" in '') stop_server cleanup_db ;; esac start_server expected_status=401 echo '3: TESTING controller without authentication insists on authentication ...' AUTH_USER= $testurl ${host}/${route_prefix}/site $expected_status echo '4: TESTING controller with wrong password insists on authentication ...' AUTH_PASSWORD=wrong $testurl ${host}/${route_prefix}/site $expected_status echo '5: TESTING controller with wrong user insists on authentication ...' AUTH_USER=wrong $testurl ${host}/${route_prefix}/site $expected_status echo '6: TESTING controller with authentication works ...' expected_status=200 $testurl ${host}/${route_prefix}/site $expected_status if $has_middleware; then echo echo '7: TESTING middleware without authentication insists on authentication ...' expected_status=401 AUTH_USER= $testurl ${host}/${route_prefix}/middleware $expected_status echo echo '8: TESTING middleware with wrong password insists on authentication ...' AUTH_PASSWORD=wrong $testurl ${host}/${route_prefix}/middleware $expected_status echo echo '9: TESTING middleware with wrong user insists on authentication ...' AUTH_USER=wrong $testurl ${host}/${route_prefix}/middleware $expected_status echo echo '10: TESTING middleware with authentication works ...' expected_status=200 $testurl ${host}/${route_prefix}/middleware $expected_status else echo echo "Skipped middleware tests as it is not configured..." fi ;; esac unset AUTH_USER unset AUTH_PASSWORD case "$run_test" in ''|1??) echo ======================================================== echo TESTING WITHOUT CATCHALL, no whitelist or user in test env echo ======================================================== export RAILS_ENV=test RACK_ENV=test case "$run_trest" in '') stop_server cleanup_db ;; esac start_server # get a static file echo echo 'TESTING no catchall route active ...' expected_status=404,500,502 $testurl ${host}/another/url $expected_status echo 'TESTING default route has been overriden ...' expected_status=404,500,502 $testurl ${host}/health_check/site $expected_status common_tests 100 ;; esac export IP_WHITELIST='127.0.0.1' export AUTH_USER='someone' export AUTH_PASSWORD='secret' case "$run_test" in ''|2??) echo ======================================================== echo TESTING WITH CATCHALL with whitelist and user in ${RAILS_ENV2:-production} env echo ======================================================== export RAILS_ENV=${RAILS_ENV2:-production} RACK_ENV=${RAILS_ENV2:-production} case "$run_trest" in '') stop_server cleanup_db ;; esac date > $catchall_file start_server echo echo 'TESTING catchall route active ...' $testurl ${host}/another/url 200 text/plain 'catch all route' echo common_tests 200 ;; esac rm -f $catchall_file finish PASSED 0 exit 0 # vi: sw=4 ai sm: health_check-3.0.0/test/rails_5.0.gemfile0000644000175000017510000000117713411314717017532 0ustar avronravronr# Gemfile for health_test testing source 'https://rubygems.org' ruby RUBY_VERSION < '2.2.2' ? '2.2.2' : RUBY_VERSION gem 'rails', '~> 5.0.0' gem 'rake', '>= 0.8.7' gem 'listen', '<3.1.2' # REQUIRED group :development, :test do if defined?(JRUBY_VERSION) gem 'jruby-openssl' gem 'activerecord-jdbcsqlite3-adapter' else gem 'sqlite3', "~> 1.3.7" end gem 'shoulda' # redis based checks gem 'sidekiq', :require => !ENV['SIDEKIQ'].nil? gem 'redis', :require => !ENV['REDIS_URL'].nil? gem 'resque', :require => !ENV['RESQUE'].nil? # s3 check gem 'aws-sdk', :require => !ENV['AWS_ACCESS_KEY_ID'].nil? end health_check-3.0.0/test/fake_smtp_server0000755000175000017510000000135713411314717017771 0ustar avronravronr#!/usr/bin/env ruby require 'socket' port = 3555 server = TCPServer.new port puts "fake_smtp_server: Waiting for one connection to port #{port} ..." def send(client, line) client.puts line puts "> #{line}" end def receive(client) line = client.gets puts "< #{line}" line end client = server.accept # Wait for a client to connect send(client, "220 dummy-smtp.example.com SMTP") cmd = receive(client) while cmd !~ /^QUIT\r/ if cmd =~ /^HELO(.*)\r/ send(client, "250 Welcome to a dummy smtp server") else send(client, "502 I am so dumb I only understand HELO and QUIT") end cmd = receive(client) end send(client, "221 Bye Bye") client.close puts "fake_smtp_server: Exiting now the conversation has finished." exit 0 health_check-3.0.0/test/rails_5.1.gemfile0000644000175000017510000000153513411314717017531 0ustar avronravronr# Gemfile for health_test testing source 'https://rubygems.org' ruby RUBY_VERSION < '2.2.2' ? '2.2.2' : RUBY_VERSION gem 'rails', '~> 5.1.0' gem 'rake', '>= 0.8.7' # spring-watcher-listen was resolved to 2.0.1, which depends on # listen was resolved to 3.1.5, which depends on # ruby_dep # and ruby_dep 1.5 requires 2.2.3 or later gem 'ruby_dep', '~> 1.3.0' # REQUIRED gem 'listen', '<3.1.2' # REQUIRED group :development, :test do if defined?(JRUBY_VERSION) gem 'jruby-openssl' gem 'activerecord-jdbcsqlite3-adapter' else gem 'sqlite3', "~> 1.3.7" end gem 'shoulda' # redis based checks gem 'sidekiq', :require => !ENV['SIDEKIQ'].nil? gem 'redis', :require => !ENV['REDIS_URL'].nil? gem 'resque', :require => !ENV['RESQUE'].nil? # s3 check gem 'aws-sdk', :require => !ENV['AWS_ACCESS_KEY_ID'].nil? end health_check-3.0.0/test/migrate/0000755000175000017510000000000013411314717016126 5ustar avronravronrhealth_check-3.0.0/test/migrate/twelve/0000755000175000017510000000000013411314717017434 5ustar avronravronrhealth_check-3.0.0/test/migrate/twelve/011_create_roles.roles.rb0000644000175000017510000000027313411314717024136 0ustar avronravronrclass CreateRoles < ActiveRecord::Migration[5.0] def self.up create_table :roles do |t| t.column :name, :string end end def self.down drop_table :roles end end health_check-3.0.0/test/migrate/twelve/012_create_users.rb0000644000175000017510000000031413411314717023025 0ustar avronravronrclass CreateUsers < ActiveRecord::Migration[5.0] def self.up create_table "users", :force => true do |t| t.column :name, :string end end def self.down drop_table :users end end health_check-3.0.0/test/migrate/twelve/9_create_countries.rb0000644000175000017510000000030713411314717023547 0ustar avronravronrclass CreateCountries < ActiveRecord::Migration[5.0] def self.up create_table :countries do |t| t.column :name, :string end end def self.down drop_table :countries end end health_check-3.0.0/test/migrate/empty/0000755000175000017510000000000013411314717017264 5ustar avronravronrhealth_check-3.0.0/test/migrate/empty/do_not_remove.txt0000644000175000017510000000001413411314717022657 0ustar avronravronrDon't removehealth_check-3.0.0/test/migrate/nine/0000755000175000017510000000000013411314717017057 5ustar avronravronrhealth_check-3.0.0/test/migrate/nine/9_create_countries.rb0000644000175000017510000000030713411314717023172 0ustar avronravronrclass CreateCountries < ActiveRecord::Migration[5.0] def self.up create_table :countries do |t| t.column :name, :string end end def self.down drop_table :countries end end health_check-3.0.0/test/setup_railsapp0000755000175000017510000003344413411314717017467 0ustar avronravronr#!/bin/bash route_prefix=medical_check err_report() { echo "$0: Error on line $1 - aborted" exit 1 } trap 'err_report $LINENO' ERR # Any failure causes exit set -e case "$1" in [0-9]*) export BUNDLE_GEMFILE=$PWD/test/rails_$1.gemfile ;; esac while : do case "$BUNDLE_GEMFILE" in */test/rails_[Qq].gemfile) echo "Aborting..." exit 2 ;; */test/rails_edge.gemfile|*/test/rails_[0-9].[0-9]*.gemfile) if [ -f "$BUNDLE_GEMFILE" ]; then break fi ;; esac echo "== SELECT GEMFILE ==" echo echo "Please select the gemfile for the required rails series:" (cd test ; ls rails*gemfile | ruby -p -e '$_.sub!(/rails_(.*).gemfile/, " \\1")' ) echo echo -n "Enter choice (or q to quit): " read x export BUNDLE_GEMFILE=$PWD/test/rails_$x.gemfile done if [ -z "$MIDDLEWARE" ]; then echo -n "Add as middleware [N/y] : " read MIDDLEWARE export MIDDLEWARE fi rm -rf tmp/Gemfile* tmp/railsapp tmp/bin tmp/gems test/bin test/rails*.gemfile.lock mkdir -p tmp/gems . test/init_variables if $rbenv_which bundle ; then echo Bundler is installed else gem install bundler $rehash fi echo "Running bundle with BUNDLE_GEMFILE=$BUNDLE_GEMFILE ..." if ! smarter_bundle ; then echo "Test aborted (missing required gems)" exit 2 fi $rehash rails="$base_dir/test/bin/rails" rake="$base_dir/test/bin/rake" echo Checking $rails is present ... [ -f $rails -a -f $rake ] || bundle exec rake rails:update:bin || echo '(ignored rake rails:update:bin exit status)' [ -f $rails ] || bundle binstubs railties || echo '(ignored bundle exit status)' [ -f $rails ] || bundle binstubs rails || echo '(ignored bundle exit status)' if [ ! -f $rails ]; then echo "Test aborted (unable to create $rails)" exit 2 fi if [ ! -f $rake ]; then echo "Running bundle binstubs rake ..." if ! bundle binstubs rake || [ ! -f $rake ]; then echo "Test aborted (unable to create $rake)" exit 2 fi fi actual_rails_version=`$rails -v` [ -d lib/health_check ] || exec echo setup_railsapp MUST be executed in the base of the health_check gem/clone of git repository export GEM_PATH="$tmp_dir/gems:`gem environment gempath`" echo Set GEM_PATH=$GEM_PATH echo Installing health_check as a gem into $tmp_dir/gems rm -f pkg/health_check-*.gem if env GEM_HOME=$tmp_dir/gems $rake install then echo rake install passed else echo rake install failed! running gem install pkg/health_check-*.gem manually to see error message: env GEM_HOME=$tmp_dir/gems gem install pkg/health_check-*.gem echo gem install worked, but flagging it as a FAIL anyway since rake install failed! exit 2 fi echo Gems in tmp/gems: ls tmp/gems echo Environment: env | egrep 'TRAVIS|RAILS|RUBY|_ENV|GEM|BUNDLE' || echo "No relevant variables set" cd $tmp_dir case `ruby -e 'puts JRUBY_VERSION' 2> /dev/null` in [0-9]*) db=jdbcsqlite3 # Appears to need a bit extra time ;; *) db=sqlite3 ;; esac echo "Creating $actual_rails_version app in $tmp_dir/railsapp using adapter $db" case "$actual_rails_version" in *' '[12].*) $rails railsapp -d $db ;; *' '[345].*) case "$BUNDLE_GEMFILE" in *rails_edge.gemfile) $rails new railsapp --skip-bundle -d $db --edge ;; *) $rails new railsapp --skip-bundle -d $db ;; esac ;; *) echo "Unknown rails version" ;; esac cd $railsapp [ -z "$rehash" ] || rbenv local `rbenv version-name` echo "Changed current directory to railsapp root: $railsapp" echo "Fixing rdoc require in Rakefile if needed" ruby -p -i.bak -e '$_.gsub!(/rake.rdoctask/, "rdoc/task")' Rakefile echo "Configuring mailer to point to fake_smtp_server port 3555" cat >> config/environment.rb <<'!EOF!' ActionMailer::Base.delivery_method = :smtp ActionMailer::Base.smtp_settings = { :address => "localhost", :port => 3555 } !EOF! echo Adding an initializer for health_check gem ... mkdir -p config/initializers tee config/initializers/health_check.rb < '$base_dir'" >> Gemfile case "$RAILS_SERVER" in webrick|'') echo "Using default webrick server" ;; *) echo "Adding $RAILS_SERVER gem to Gemfile (for use as server)" echo "gem '$RAILS_SERVER'" >> Gemfile ;; esac sed -i.bak -e '/listen/s/^/#Earlier version required # /' Gemfile egrep REQUIRED < ${INITIAL_BUNDLE_GEMFILE} >> Gemfile || echo No required gems found... echo echo ================= Gemfile =================== cat Gemfile echo echo running bundle install smarter_bundle ${BUNDLER_VERSION:+_${BUNDLER_VERSION}_} install $rehash echo "Using binstubs in $railsapp/bin for rails and rake commands" rails="$railsapp/bin/rails" rake="$railsapp/bin/rake" echo Checking $rails is present ... [ -f $rails -a -f $rake ] || bundle exec rake rails:update:bin || echo '(ignored rake rails:update:bin exit status)' [ -f $rails ] || bundle binstubs railties || echo '(ignored bundle exit status)' [ -f $rails ] || bundle binstubs rails || echo '(ignored bundle exit status)' if [ ! -f $rails ]; then echo "Test aborted (unable to create $rails)" exit 2 fi echo Checking $rake is present ... [ -f $rake ] || bundle binstubs rake || echo '(ignored bundle exit status)' if [ ! -f $rake ]; then echo "Test aborted (unable to create $rake)" exit 2 fi $rehash # Fix for rvm, otherwise bundle run from rails create fails export PATH="`pwd`/bin:$PATH" echo ================= Gemfile.lock =================== cat Gemfile.lock echo for e in test ${RAILS_ENV2:-production} do if [ -f config/environments/$e.rb ]; then echo ======== config/environments/$e.rb ================ sed -i.bak -e 's/config.serve_static_assets = false/config.serve_static_assets = true # NOTE: health_check test: changed to true/' \ -e 's/config.active_record.migration_error = :page_load/# & # NOTE: health_check test: commented out/' \ config/environments/$e.rb cat config/environments/$e.rb || true echo fi done echo "============== config/environment.rb =============" cat config/environment.rb echo echo ======================== case $db in jdbcsqlite3) for e in test ${RAILS_ENV2:-production} do echo export RAILS_ENV=$e RACK_ENV=$e echo "Jruby requires the database to be created before the server is started: running RAILS_ENV=$e rake db:migrate" $rake db:migrate echo done ;; esac echo STATIC-FILE > public/static.txt cat > public/ajax_example.html <<'EOF' Example static and dynamic calls to health_check

Static calls

Dynamic calls

EOF cat > app/controllers/example_controller.rb <<'EOF' class ExampleController < ApplicationController def index render :plain => 'example page' end def catchall render :plain => 'catch all route' end end EOF echo ======================================= case "$MIDDLEWARE" in [Yy]*) if [ -s config/application.rb ]; then mv -f config/application.rb config/application.rb-old ( ruby -n -e 'print if not /^ *end/..9999' config/application.rb-old | tee /tmp/t$$ if [ ! -s /tmp/t$$ ]; then echo "WARNING: ruby -n -e failed silently - using sed instead!! (rbx-19mode has that problem)" >&3 sed -e '/^ *end/,$d' config/application.rb-old fi echo " # -----------------------------------------" echo " # START OF SECTION FOR TESTING HEALTH_CHECK" echo " config.middleware.insert_after Rails::Rack::Logger, HealthCheck::MiddlewareHealthcheck" echo " # END OF SECTION FOR TESTING HEALTH_CHECK" echo " # ---------------------------------------" ruby -n -e 'print if /^ *end/..9999' config/application.rb-old | tee /tmp/t$$ if [ ! -s /tmp/t$$ ]; then echo "WARNING: ruby -n -e failed silently - using sed instead!! (rbx-19mode has that problem)" >&3 sed -n -e '/^ *end/,$p' config/application.rb-old fi ) 3>&1 > config/application.rb #echo =============== config/application.rb-old ======================== #cat config/application.rb-old echo =============== config/application.rb ======================== cat config/application.rb else echo FAILED: NO config/application.rb file!! exit 2 fi echo ======================================= ;; esac if [ -s config/routes.rb ]; then mv -f config/routes.rb config/routes.rb-old ( ruby -n -e 'print if not /^end/..9999' config/routes.rb-old | tee /tmp/t$$ if [ ! -s /tmp/t$$ ]; then echo "WARNING: ruby -n -e failed silently - using sed instead!! (rbx-19mode has that problem)" >&3 sed -e '/^end/,$d' config/routes.rb-old fi # rails 3.0+ echo " # -----------------------------------------" echo " # START OF SECTION FOR TESTING HEALTH_CHECK" echo " get 'example(/:action(/:id))(.:format)' => 'example'" echo " if File.exists?('$catchall_file')" echo " health_check_routes" echo " # CATCH ALL ROUTE" echo " get '*path', :to => 'example#catchall'" echo " end" echo " # END OF SECTION FOR TESTING HEALTH_CHECK" echo " # ---------------------------------------" ruby -n -e 'print if /^end/..9999' config/routes.rb-old | tee /tmp/t$$ if [ ! -s /tmp/t$$ ]; then echo "WARNING: ruby -n -e failed silently - using sed instead!! (rbx-19mode has that problem)" >&3 sed -n -e '/^end/,$p' config/routes.rb-old fi ) 3>&1 > config/routes.rb #echo =============== config/routes.rb-old ======================== #cat config/routes.rb-old echo =============== config/routes.rb ======================== cat config/routes.rb else echo FAILED: NO config/routes.rb file!! exit 2 fi echo ======================================= echo echo "Created $actual_rails_version app in $railsapp using adapter $db" echo -n "Using " ruby --version health_check-3.0.0/test/provision_vagrant0000644000175000017510000000272513411314717020201 0ustar avronravronr#!/bin/bash case `id` in *root*) ;; *) exec echo Must be run as root ;; esac set -xe id pwd export DEBIAN_FRONTEND=noninteractive find /tmp/got-apt-update -mtime -1 || ( apt-get update && touch /tmp/got-apt-update ) apt install --yes --force-yes -q build-essential ruby ruby-dev sqlite3 libsqlite3-dev nodejs ( echo Install chruby [ -s chruby-0.3.9.tar.gz ] || wget -q -O chruby-0.3.9.tar.gz https://github.com/postmodern/chruby/archive/v0.3.9.tar.gz [ chruby-0.3.9 ] || tar -xzf chruby-0.3.9.tar.gz cd chruby-0.3.9/ ./scripts/setup.sh cat > /etc/profile.d/chruby.sh <<'EOF' if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then source /usr/local/share/chruby/chruby.sh fi EOF chmod a+r /etc/profile.d/chruby.sh ) ( [ -d ruby-build ] || git clone https://github.com/rbenv/ruby-build.git which ruby-build || PREFIX=/usr/local ./ruby-build/install.sh mkdir -p /opt/rubies [ -x /opt/rubies/1.9.3-p551/bin/bundle ] || ( ruby-build 1.9.3-p551 /opt/rubies/1.9.3-p551 && /opt/rubies/1.9.3-p551/bin/gem install bundler ) for v in 2.2.0 do [ -x /opt/rubies/$v/bin/bundle ] || ( ruby-build $v /opt/rubies/$v && /opt/rubies/$v/bin/gem install bundler ) done ) echo Setup system ruby which bundle || gem install bundler bundle --version set +x cat < e create_error 'resque-redis', e.message end end end health_check-3.0.0/lib/health_check/sidekiq_health_check.rb0000644000175000017510000000066313411314717023334 0ustar avronravronrmodule HealthCheck class SidekiqHealthCheck extend BaseHealthCheck def self.check unless defined?(::Sidekiq) raise "Wrong configuration. Missing 'sidekiq' gem" end ::Sidekiq.redis do |r| res = r.ping res == 'PONG' ? '' : "Sidekiq.redis.ping returned #{res.inspect} instead of PONG" end rescue Exception => e create_error 'sidekiq-redis', e.message end end end health_check-3.0.0/lib/health_check/health_check_controller.rb0000644000175000017510000000547613411314717024075 0ustar avronravronr# Copyright (c) 2010-2013 Ian Heggie, released under the MIT license. # See MIT-LICENSE for details. module HealthCheck class HealthCheckController < ActionController::Base layout false if self.respond_to? :layout before_action :check_origin_ip before_action :authenticate def index last_modified = Time.now.utc max_age = HealthCheck.max_age if max_age > 1 last_modified = Time.at((last_modified.to_f / max_age).floor * max_age).utc end public = (max_age > 1) && ! HealthCheck.basic_auth_username if stale?(:last_modified => last_modified, :public => public) 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? send_response nil, :ok, :ok else msg = "health_check failed: #{errors}" 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 end end 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 => 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 => 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('Health Check') do |username, password| username == HealthCheck.basic_auth_username && password == HealthCheck.basic_auth_password end end def check_origin_ip unless HealthCheck.origin_ip_whitelist.blank? || HealthCheck.origin_ip_whitelist.include?(request.ip) render :plain => 'Health check is not allowed for the requesting IP', :status => HealthCheck.http_status_for_ip_whitelist_error, :content_type => 'text/plain' end end # turn cookies for CSRF off def protect_against_forgery? false end end end health_check-3.0.0/lib/health_check/redis_health_check.rb0000644000175000017510000000063013411314717023003 0ustar avronravronrmodule HealthCheck class RedisHealthCheck extend BaseHealthCheck def self.check unless defined?(::Redis) raise "Wrong configuration. Missing 'redis' gem" end res = ::Redis.new(url: HealthCheck.redis_url).ping res == 'PONG' ? '' : "Redis.ping returned #{res.inspect} instead of PONG" rescue Exception => e create_error 'redis', e.message end end end health_check-3.0.0/lib/health_check/utils.rb0000644000175000017510000001412513411314717020357 0ustar avronravronr# Copyright (c) 2010-2013 Ian Heggie, released under the MIT license. # See MIT-LICENSE for details. module HealthCheck class Utils @@default_smtp_settings = { :address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true, } cattr_accessor :default_smtp_settings # process an array containing a list of checks def self.process_checks(checks, called_from_middleware = false) errors = '' checks.each do |check| case check when 'and', 'site' # do nothing when "database" HealthCheck::Utils.get_database_version when "email" errors << HealthCheck::Utils.check_email when "emailconf" errors << HealthCheck::Utils.check_email if HealthCheck::Utils.mailer_configured? when "migrations", "migration" if defined?(ActiveRecord::Migration) and ActiveRecord::Migration.respond_to?(:check_pending!) # Rails 4+ begin ActiveRecord::Migration.check_pending! rescue ActiveRecord::PendingMigrationError => ex errors << ex.message end else database_version = HealthCheck::Utils.get_database_version migration_version = HealthCheck::Utils.get_migration_version if database_version.to_i != migration_version.to_i errors << "Current database version (#{database_version}) does not match latest migration (#{migration_version}). " end end when 'cache' errors << HealthCheck::Utils.check_cache when 'resque-redis-if-present' errors << HealthCheck::ResqueHealthCheck.check if defined?(::Resque) when 'sidekiq-redis-if-present' errors << HealthCheck::SidekiqHealthCheck.check if defined?(::Sidekiq) when 'redis-if-present' errors << HealthCheck::RedisHealthCheck.check if defined?(::Redis) when 's3-if-present' errors << HealthCheck::S3HealthCheck.check if defined?(::Aws) when 'resque-redis' errors << HealthCheck::ResqueHealthCheck.check when 'sidekiq-redis' errors << HealthCheck::SidekiqHealthCheck.check when 'redis' errors << HealthCheck::RedisHealthCheck.check when 's3' errors << HealthCheck::S3HealthCheck.check when "standard" 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 |name, list| list.each do |custom_check| errors << custom_check.call(self) end end when "all", "full" errors << HealthCheck::Utils.process_checks(HealthCheck.full_checks, called_from_middleware) else if HealthCheck.custom_checks.include? check HealthCheck.custom_checks[check].each do |custom_check| errors << custom_check.call(self) end else return "invalid argument to health_test." end end end return errors rescue => e return e.message end def self.db_migrate_path # Lazy initialisation so Rails.root will be defined @@db_migrate_path ||= File.join(Rails.root, 'db', 'migrate') end def self.db_migrate_path=(value) @@db_migrate_path = value end def self.mailer_configured? defined?(ActionMailer::Base) && (ActionMailer::Base.delivery_method != :smtp || HealthCheck::Utils.default_smtp_settings != ActionMailer::Base.smtp_settings) end def self.get_database_version ActiveRecord::Migrator.current_version if defined?(ActiveRecord) end def self.get_migration_version(dir = self.db_migrate_path) latest_migration = nil Dir[File.join(dir, "[0-9]*_*.rb")].each do |f| l = f.scan(/0*([0-9]+)_[_.a-zA-Z0-9]*.rb/).first.first rescue -1 latest_migration = l if !latest_migration || l.to_i > latest_migration.to_i end latest_migration end def self.check_email case ActionMailer::Base.delivery_method when :smtp HealthCheck::Utils.check_smtp(ActionMailer::Base.smtp_settings, HealthCheck.smtp_timeout) when :sendmail HealthCheck::Utils.check_sendmail(ActionMailer::Base.sendmail_settings) else '' end end def self.check_sendmail(settings) File.executable?(settings[:location]) ? '' : 'no sendmail executable found. ' end def self.check_smtp(settings, timeout) status = '' begin if @skip_external_checks status = '221' else Timeout::timeout(timeout) do |timeout_length| t = TCPSocket.new(settings[:address], settings[:port]) begin status = t.gets while status != nil && status !~ /^2/ status = t.gets end t.puts "HELO #{settings[:domain]}\r" while status != nil && status !~ /^250/ status = t.gets end t.puts "QUIT\r" status = t.gets ensure t.close end end end rescue Errno::EBADF => ex status = "Unable to connect to service" rescue Exception => ex status = ex.to_s end (status =~ /^221/) ? '' : "SMTP: #{status || 'unexpected EOF on socket'}. " end def self.check_cache Rails.cache.write('__health_check_cache_test__', 'ok', :expires_in => 1.second) ? '' : 'Unable to write to cache. ' end end end health_check-3.0.0/lib/health_check/base_health_check.rb0000644000175000017510000000017113411314717022607 0ustar avronravronrmodule BaseHealthCheck def create_error(check_type, error_message) "[#{check_type} - #{error_message}] " end end health_check-3.0.0/lib/health_check/health_check_routes.rb0000644000175000017510000000070313411314717023217 0ustar avronravronrmodule ActionDispatch::Routing class Mapper def health_check_routes(prefix = nil) HealthCheck::Engine.routes_explicitly_defined = true add_health_check_routes(prefix) end def add_health_check_routes(prefix = nil) HealthCheck.uri = prefix if prefix match "#{HealthCheck.uri}(/:checks)(.:format)", :to => 'health_check/health_check#index', via: [:get, :post], :defaults => { :format => 'txt' } end end end health_check-3.0.0/lib/health_check/s3_health_check.rb0000644000175000017510000000345513411314717022232 0ustar avronravronrmodule HealthCheck class S3HealthCheck extend BaseHealthCheck class << self def check unless defined?(::Aws) raise "Wrong configuration. Missing 'aws-sdk' gem" end return create_error 's3', 'Could not connect to aws' if aws_s3_client.nil? HealthCheck.buckets.each do |bucket_name, permissions| if permissions.nil? # backward compatible permissions = [:R, :W, :D] end permissions.each do |permision| begin send(permision, bucket_name) rescue Exception => e raise "bucket:#{bucket_name}, permission:#{permision} - #{e.message}" end end end '' rescue Exception => e create_error 's3', e.message end private def configure_client return unless defined?(Rails) aws_configuration = { region: Rails.application.secrets.aws_default_region, credentials: ::Aws::Credentials.new( Rails.application.secrets.aws_access_key_id, Rails.application.secrets.aws_secret_access_key ), force_path_style: true } ::Aws::S3::Client.new aws_configuration end def aws_s3_client @aws_s3_client ||= configure_client end def R(bucket) aws_s3_client.list_objects(bucket: bucket) end def W(bucket) aws_s3_client.put_object(bucket: bucket, key: "healthcheck_#{Rails.application.class.parent_name}", body: Time.new.to_s) end def D(bucket) aws_s3_client.delete_object(bucket: bucket, key: "healthcheck_#{Rails.application.class.parent_name}") end end end end health_check-3.0.0/lib/health_check/version.rb0000644000175000017510000000005313411314717020677 0ustar avronravronrmodule HealthCheck VERSION = "3.0.0" end health_check-3.0.0/lib/health_check/middleware_health_check.rb0000644000175000017510000000644013411314717024017 0ustar avronravronrmodule HealthCheck class MiddlewareHealthcheck def initialize(app) @app = app end def call(env) (response_type, middleware_checks, full_stack_checks) = parse_env(env) if response_type if error_response = (ip_blocked(env) || not_authenticated(env)) return error_response end HealthCheck.installed_as_middleware = true errors = '' begin # 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 healthy = errors.blank? msg = healthy ? HealthCheck.success : "health_check failed: #{errors}" if response_type == 'xml' content_type = 'text/xml' msg = { healthy: healthy, message: msg }.to_xml error_code = HealthCheck.http_status_for_error_object elsif response_type == 'json' content_type = 'application/json' msg = { healthy: healthy, message: msg }.to_json error_code = HealthCheck.http_status_for_error_object else content_type = 'text/plain' error_code = HealthCheck.http_status_for_error_text end [ (healthy ? 200 : error_code), { 'Content-Type' => content_type }, [msg] ] else @app.call(env) end end protected def parse_env(env) uri = env['PATH_INFO'] if uri =~ /^\/#{Regexp.escape HealthCheck.uri}(\/([-_0-9a-zA-Z]*))?(\.(\w*))?$/ checks = $2.to_s == '' ? ['standard'] : $2.split('_') response_type = $4.to_s middleware_checks = checks & HealthCheck.middleware_checks full_stack_checks = (checks - HealthCheck.middleware_checks) - ['and'] [response_type, middleware_checks, full_stack_checks ] end end def ip_blocked(env) return false if HealthCheck.origin_ip_whitelist.blank? req = Rack::Request.new(env) unless HealthCheck.origin_ip_whitelist.include?(req.ip) [ HealthCheck.http_status_for_ip_whitelist_error, { 'Content-Type' => 'text/plain' }, [ 'Health check is not allowed for the requesting IP' ] ] end end def not_authenticated(env) return false unless HealthCheck.basic_auth_username && HealthCheck.basic_auth_password auth = MiddlewareHealthcheck::Request.new(env) if auth.provided? && auth.basic? && Rack::Utils.secure_compare(HealthCheck.basic_auth_username, auth.username) && Rack::Utils.secure_compare(HealthCheck.basic_auth_password, auth.password) env['REMOTE_USER'] = auth.username return false end [ 401, { 'Content-Type' => 'text/plain', 'WWW-Authenticate' => 'Basic realm="Health Check"' }, [ ] ] end class Request < Rack::Auth::AbstractRequest def basic? "basic" == scheme end def credentials @credentials ||= params.unpack("m*").first.split(/:/, 2) end def username credentials.first end def password credentials.last end end end end health_check-3.0.0/lib/health_check.rb0000644000175000017510000000516513411314717017223 0ustar avronravronr# Copyright (c) 2010-2013 Ian Heggie, released under the MIT license. # See MIT-LICENSE for details. module HealthCheck class Engine < Rails::Engine cattr_accessor :routes_explicitly_defined end # Text output upon success mattr_accessor :success self.success = "success" # Timeout in seconds used when checking smtp server mattr_accessor :smtp_timeout self.smtp_timeout = 30.0 # http status code used when plain text error message is output mattr_accessor :http_status_for_error_text self.http_status_for_error_text = 500 # http status code used when an error object is output (json or xml) mattr_accessor :http_status_for_error_object self.http_status_for_error_object = 500 # http status code used when the ip is not allowed for the request mattr_accessor :http_status_for_ip_whitelist_error self.http_status_for_ip_whitelist_error = 403 # ips allowed to perform requests mattr_accessor :origin_ip_whitelist self.origin_ip_whitelist = [] # max-age of response in seconds # cache-control is public when max_age > 1 and basic authentication is used mattr_accessor :max_age self.max_age = 1 # s3 buckets mattr_accessor :buckets self.buckets = {} # health check uri path mattr_accessor :uri self.uri = 'health_check' # Basic Authentication mattr_accessor :basic_auth_username, :basic_auth_password self.basic_auth_username = nil self.basic_auth_password = nil # Array of custom check blocks mattr_accessor :custom_checks mattr_accessor :full_checks mattr_accessor :standard_checks self.custom_checks = { } 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 # Allow non-standard redis url mattr_accessor :redis_url self.redis_url = nil def self.add_custom_check(name = 'custom', &block) custom_checks[name] ||= [ ] custom_checks[name] << block end def self.setup yield self end end require 'health_check/version' require 'health_check/base_health_check' require 'health_check/resque_health_check' require 'health_check/s3_health_check' require 'health_check/redis_health_check' require 'health_check/sidekiq_health_check' require 'health_check/utils' require 'health_check/health_check_controller' require 'health_check/health_check_routes' require 'health_check/middleware_health_check' # vi: sw=2 sm ai: health_check-3.0.0/Vagrantfile0000644000175000017510000000106613411314717015707 0ustar avronravronr# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. config.vm.box = "ubuntu/xenial64" # set auto_update to false, if you do NOT want to check the correct # additions version when booting this machine config.vbguest.auto_update = false # do NOT download the iso file from a webserver config.vbguest.no_remote = true # provision with a shell script. config.vm.provision "shell", path: "./test/provision_vagrant" end health_check-3.0.0/README.rdoc0000644000175000017510000003205713411314717015334 0ustar avronravronr= health_check gem Simple health check of Rails 5.x apps for use with Pingdom, NewRelic, EngineYard or uptime.openacs.org etc. The basic goal is to quickly check that rails is up and running and that it has access to correctly configured resources (database, email gateway) Check the latest README {master}[https://github.com/ianheggie/health_check/tree/master] for other versions health_check provides various monitoring URIs, for example: curl localhost:3000/health_check success curl localhost:3000/health_check/all.json {"healthy":true,"message":"success"} curl localhost:3000/health_check/database_cache_migration.xml true success You may also issue POST calls instead of GET to these urls. On failure (detected by health_check) a 500 http status is returned with a simple explanation of the failure curl localhost:3000/health_check/fail health_check failed: invalid argument to health_test. The health_check controller disables sessions for versions that eagerly load sessions. == Checks * standard (default) - site, database and migrations checks are run plus email if ActionMailer is defined and it is not using the default configuration * all / full - all checks are run (can be overriden in config block) * cache - checks that a value can be written to the cache * custom - runs checks added via config.add_custom_check * database - checks that the current migration level can be read from the database * email - basic check of email - :test returns true, :sendmail checks file is present and executable, :smtp sends HELO command to server and checks response * migration - checks that the database migration level matches that in db/migrations * redis / redis-if-present - checks Redis connectivity * resque-redis / resque-redis-if-present - checks Resque connectivity to Redis * s3 / s3-if-present - checks proper permissions to s3 buckets * sidekiq-redis / sidekiq-redis-if-present - checks Sidekiq connectivity to Redis * site - checks rails is running sufficiently to render text Some checks have a *-if-present form, which only runs the check if the corresponding library has been required. The email gateway is not checked unless the smtp settings have been changed. Specify full or include email in the list of checks to verify the smtp settings (eg use 127.0.0.1 instead of localhost). Note: rails also checks migrations by default in development mode and throws an ActiveRecord::PendingMigrationError exception (http error 500) if there is an error == Installation Add the following line to Gemfile gem "health_check" And then execute bundle Or install it yourself as: gem install health_check == Configuration To change the configuration of health_check, create a file `config/initializers/health_check.rb` and add a configuration block like: HealthCheck.setup do |config| # uri prefix (no leading slash) config.uri = 'health_check' # Text output upon success config.success = 'success' # Timeout in seconds used when checking smtp server config.smtp_timeout = 30.0 # http status code used when plain text error message is output # Set to 200 if you want your want to distinguish between partial (text does not include success) and # total failure of rails application (http status of 500 etc) config.http_status_for_error_text = 500 # http status code used when an error object is output (json or xml) # Set to 200 if you want your want to distinguish between partial (healthy property == false) and # total failure of rails application (http status of 500 etc) config.http_status_for_error_object = 500 # bucket names to test connectivity - required only if s3 check used, access permissions can be mixed config.buckets = {'bucket_name' => [:R, :W, :D]} # You can customize which checks happen on a standard health check, eg to set an explicit list use: config.standard_checks = [ 'database', 'migrations', 'custom' ] # Or to exclude one check: config.standard_checks -= [ 'emailconf' ] # You can set what tests are run with the 'full' or 'all' parameter config.full_checks = ['database', 'migrations', 'custom', 'email', 'cache', 'redis', 'resque-redis', 'sidekiq-redis', 's3'] # Add one or more custom checks that return a blank string if ok, or an error message if there is an error config.add_custom_check do CustomHealthCheck.perform_check # any code that returns blank on success and non blank string upon failure end # Add another custom check with a name, so you can call just specific custom checks. This can also be run using # the standard 'custom' check. # You can define multiple tests under the same name - they will be run one after the other. config.add_custom_check('sometest') do CustomHealthCheck.perform_another_check # any code that returns blank on success and non blank string upon failure end # max-age of response in seconds # cache-control is public when max_age > 1 and basic_auth_username is not set # You can force private without authentication for longer max_age by # setting basic_auth_username but not basic_auth_password config.max_age = 1 # Protect health endpoints with basic auth # These default to nil and the endpoint is not protected config.basic_auth_username = 'my_username' config.basic_auth_password = 'my_password' # Whitelist requesting IPs # Defaults to blank and allows any IP 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 = 403 # When redis url is non-standard config.redis_url = 'redis_url' end You may call add_custom_check multiple times with different tests. These tests will be included in the default list ("standard"). If you have a catchall route then add the following line above the catch all route (in `config/routes.rb`): health_check_routes === Installing 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 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. When installed as middleware, exceptions thrown when running the full stack tests are formatted in the standard way. == Uptime Monitoring Use a website monitoring service to check the url regularly for the word "success" (without the quotes) rather than just a 200 http status so that any substitution of a different server or generic information page should also be reported as an error. If an error is encounted, the text "health_check failed: some error message/s" will be returned and the http status will be 500. See * Pingdom Website Monitoring - https://www.pingdom.com * NewRelic Availability Monitoring - http://newrelic.com/docs/features/availability-monitoring-faq * Uptime by OpenACS - http://uptime.openacs.org/uptime/ * Engine Yard's guide - https://support.cloud.engineyard.com/entries/20996821-monitor-application-uptime (although the guide is based on fitter_happier plugin it will also work with this gem) * Nagios check_http (with -s success) - https://www.nagios-plugins.org/doc/man/check_http.html * Any other montoring service that can be set to check for the word success in the text returned from a url === Requesting Json and XML responses Health_check will respond with an encoded hash object if json or xml is requested. Either set the HTTP Accept header or append .json or .xml to the url. The hash contains two keys: * healthy - true if requested checks pass (boolean) * message - text message ("success" or error message) The following commands curl -v localhost:3000/health_check.json curl -v localhost:3000/health_check/email.json curl -v -H "Accept: application/json" localhost:3000/health_check Will return a result with Content-Type: application/json and body like: {"healthy":true,"message":"success"} These following commands curl -v localhost:3000/health_check.xml curl -v localhost:3000/health_check/migration_cache.xml curl -v -H "Accept: text/xml" localhost:3000/health_check/cache Will return a result with Content-Type: application/xml and body like: true success See https://github.com/ianheggie/health_check/wiki/Ajax-Example for an Ajax example == Silencing log output It is recomended that you use silencer, lograge or one of the other log filtering gems. For example, with lograge use the following to exclude health_check from being logged: config.lograge.ignore_actions = ["HealthCheck::HealthCheckController#index"] Likewise you will probably want to exclude health_check from monitoring systems like newrelic. == Caching Cache-control is set with * public if max_age is > 1 and basic_auth_username is not set (otherwise private) * no-cache * must-revalidate * max-age (default 1) Last-modified is set to the current time (rounded down to a multiple of max_age when max_age > 1) == Known Issues * No inline documentation for methods * rvm gemsets breaks the test - specifically rvm use 1.9.3 works but rvm gemset use ruby-1.9.3-p385@health_check --create triggers a "Could not find gem 'coffee-rails (~> 3.2.1) ruby' in the gems available on this machine." error in the last call to bundle (installing health_check as a gem via a path into the temp railsapp) == Similar projects * fitter_happier plugin by atmos - plugin with similar goals, but not compatible with uptime, and does not check email gateway == Testing === Automated testing and other checks * {}[https://travis-ci.org/ianheggie/health_check.svg?branch=rails5] - Travis CI === Manual testing The instructions have been changed to using a vagrant virtual box for consistant results. Install vagrant 1.9.7 or later and virtual_box or other local virtual machine providor. Create a temp directory for throw away testing, and clone the health_check gem into it mkdir -p ~/tmp cd ~/tmp git clone https://github.com/ianheggie/health_check.git ~/tmp/health_check The Vagrantfile includes provisioning rules to install chruby (ruby version control), ruby-build will also be installed and run to build various rubies under /opt/rubies. Use vagrant ssh to connect to the virtual box and run tests. The test script will package up and install the gem under a temporary path, create a dummy rails app configured for sqlite, install the gem, and then run up tests against the server. This will require TCP port 3456 to be free. Cd to the checked out health_check directory and then run the test as follows: cd ~/tmp/health_check vagrant up # this will also run vagrant provision and take some time # chruby and various ruby versions will be installed vagrant ssh cd /vagrant # the current directory on your host is mounted here on the virtual machine chruby 2.2.2 # or some other ruby version test/test_with_railsapp exit # from viretual machine when finished The script will first call `test/setup_railsapp` to setup a rails app with health_check installed and then run up the rails server and perform veraious tests. The script `test/setup_railsapp` will prompt you for which gemfile under test you wish to use to install the appropriate rails version, and then setup tmp/railsapp accordingly. The command `rake test` will also launch these tests, except it cannot install the bundler and rake gems if they are missing first (unlike test/test_with_railsapp) == Copyright Copyright (c) 2010-2017 Ian Heggie, released under the MIT license. See MIT-LICENSE for details. == Contributors Thanks go to the various people who have given feedback and suggestions via the issues list and pull requests. === Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request (Code with BDD tests are favoured) Feedback welcome! Especially with suggested replacement code and corresponding tests health_check-3.0.0/health_check.gemspec0000644000175000017510000000260313411314717017467 0ustar avronravronr# -*- encoding: utf-8 -*- lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'health_check/version' Gem::Specification.new do |gem| gem.name = "health_check" gem.version = HealthCheck::VERSION gem.required_rubygems_version = Gem::Requirement.new(">= 0") if gem.respond_to? :required_rubygems_version= gem.authors = ["Ian Heggie"] gem.email = ["ian@heggie.biz"] gem.summary = %q{Simple health check of Rails app for uptime monitoring with Pingdom, NewRelic, EngineYard or uptime.openacs.org etc.} gem.description = <<-EOF Simple health check of Rails app for uptime monitoring with Pingdom, NewRelic, EngineYard or uptime.openacs.org etc. EOF gem.homepage = "https://github.com/ianheggie/health_check" gem.files = `git ls-files`.split($/) gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.extra_rdoc_files = [ "README.rdoc" ] gem.require_paths = ["lib"] gem.required_ruby_version = '>= 2.2.2' gem.add_dependency(%q, [">= 5.0"]) gem.add_development_dependency(%q, [">= 0.1.0"]) gem.add_development_dependency(%q, [">= 0.8.3"]) gem.add_development_dependency(%q, ["~> 2.11.0"]) gem.add_development_dependency(%q, ["~> 1.2"]) end health_check-3.0.0/Rakefile0000644000175000017510000000116413411314717015166 0ustar avronravronrrequire "bundler/gem_tasks" #require 'rubygems' require 'rake' #tests as gem task :test do exec '/bin/bash', './test/test_with_railsapp' end task :default => :test begin gem 'rdoc' require 'rdoc/task' Rake::RDocTask.new do |rdoc| version = HealthCheck::VERSION rdoc.rdoc_dir = 'rdoc' rdoc.title = "health_check #{version}" rdoc.rdoc_files.include('README*') rdoc.rdoc_files.include('CHANGELOG') rdoc.rdoc_files.include('MIT-LICENSE') rdoc.rdoc_files.include('lib/**/*.rb') end rescue Gem::LoadError puts "rdoc (or a dependency) not available. Install it with: gem install rdoc" end