Skip to content

Instantly share code, notes, and snippets.

@plukevdh
Created December 15, 2009 04:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plukevdh/256702 to your computer and use it in GitHub Desktop.
Save plukevdh/256702 to your computer and use it in GitHub Desktop.
Quick and to the point IP Failover
#!/usr/local/bin/ruby
#
# File: failoverd.rb
# Description: Daemon to handle failover and restart
# Date: 12-14-2009 - Luke van der Hoeven
#
# Credit: Based on Patrick Hennessy's ipfaild.pl script
# (http://git.pathennessy.com/cgi-bin/gitweb.cgi?p=linux-scripts.git;a=blob;f=ipfaild.pl;hb=HEAD)
#
require 'rubygems'
require 'daemons'
require 'syslog'
require 'ping'
require 'action_mailer'
## For email notifications ##
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:address => "ptvlmail2.hargray.org",
:port => 25
}
class Emailer < ActionMailer::Base
def failover
subject "Primary Production Server Down!!"
from "the.machine@htc.hargray.com"
recipients "luke.vanderhoeven@htc.hargray.com"
body "ITWEBPUB1 is down. Failing over to ITWEBPUB2.\nPlease inspect the primary server and restore order to the galaxy."
end
end
## File IO Paths ##
@program_name = "failoverd"
@daemon_lock_file = "/var/run/#{@program_name}/#{@program_name}.lock"
## Executable paths ##
@ifconfig = '/sbin/ifconfig'
@send_arp = '/usr/sbin/send_arp'
@apache2ctl = '/usr/sbin/apachectl'
## Configuration params ##
@ping_timeout = 1
@sleep_time = 2
@fail_threshold
@missed = 0
@is_live = false
@active = true
## Server config ##
@other_server = "itwebpub1"
@this_mac = "00:1E:C9:5C:A7:9B"
@ip_records = [
{:name => "foobar", :ip => "192.168.120.57", :dev => "eth0:0", :mask => "255.255.255.0" }
]
#function for loading the VIP
def ifconfig_down
for record in @ip_records
Syslog.info("Running: #{@ifconfig} #{record[:dev]} down")
unless system("#{@ifconfig} #{record[:dev]} down")
Syslog.info("Error: #{$!} \"#{@ifconfig} #{record[:dev]} down\" failed.")
end
end
end
Daemons.run_proc('failoverd.rb') do
f = File.new(@daemon_lock_file, 'w+')
if(f == 0)
warn "#{@program_name}: Couldn't open #{@daemon_lock_file}"
exit(0)
end
#put the process id into a the pid file
f.write Process.pid
#open the system log
Syslog.open(@program_name, Syslog::LOG_PID, Syslog::LOG_DAEMON)
#handle all termination signals
Signal.trap("HUP") do
Syslog.info("#{@program_name} caught SIGHUP")
@active = false
end
Signal.trap("INT") do
Syslog.info("#{@program_name} caught SIGINT")
@active = false
end
Signal.trap("QUIT") do
Syslog.info("#{@program_name} caught SIGQUIT")
@active = false
end
Signal.trap("TERM") do
Syslog.info("#{@program_name} caught SIGTERM")
@active = false
end
#initialize by releasing the VIP
ifconfig_down
#main loop
while @active
unless Ping.pingecho(@other_server, @ping_timeout) #no response
@missed += 1
else
if @missed > @fail_threshold
ifconfig_down #primary is back, release VIP
@is_live = false
@missed = 0
end
end
if @missed == @fail_threshold and !@is_live
@is_live = true #primary is down, load VIP
for record in @ip_records
Syslog.info("Running: #{@ifconfig} #{record[:dev]} #{record[:ip]} netmask #{record[:mask]}")
unless system("#{@ifconfig} #{record[:dev]} #{record[:ip]} netmask #{record[:mask]}")
Syslog.info("Error: #{$!} \"#{@ifconfig} #{record[:dev]} #{record[:ip]} netmask #{record[:mask]}")
end
#notify IP tables
Syslog.info("Running: #{@send_arp} #{record[:ip]} #{@this_mac} #{record[:ip]} ff:ff:ff:ff:ff:ff")
unless system("#{@send_arp} #{record[:ip]} #{@this_mac} #{record[:ip]} ff:ff:ff:ff:ff:ff")
Syslog.info("Error: #{$!} \"#{@send_arp} #{record[:ip]} #{@this_mac} #{record[:ip]} ff:ff:ff:ff:ff:ff\"")
end
end
#restart apache
Syslog.info("Running: #{@apache2ctl} -k restart")
unless system("#{@apache2ctl} -k restart")
Syslog.info("Error: #{$!} \"#{@apache2ctl} -k restart\"")
end
#send email notification of server down
Emailer.deliver_failover
end
sleep @sleep_time
end
#release VIP if shutting down failover
ifconfig_down
Syslog.close
f.close
exit(0)
end
#run with the command
#only needs to be run on the backup server
[ruby |./]failoverd.rb start|stop|restart|run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment