Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'rubygems'
- require 'mailfactory'
- require 'term/ansicolor'
- class String
- include Term::ANSIColor
- end
- class Abyss
- attr_accessor :daemons, :daemons_alive, :daemons_dead, :interval
- DAEMON_PATH = '/etc/rc.d'
- STATUS_PATH = '/var/run'
- def initialize all_daemons = {}
- @daemons = []
- @interval = 60 * 15 # 15 minutes
- special_cases = {
- 'courier-imap' => ['imapd', 'imapd-ssl', 'courier', 'pop3d', 'pop3d-ssl']
- }
- if all_daemons.empty?
- # fetch the list of started daemons from rc.conf
- daemons = File.readlines('/etc/rc.conf').find{|l| l =~ /^DAEMONS/}.chomp
- # get the daemons out of there
- daemons = daemons.scan(/DAEMONS=\((.*?)\)/).first.first
- # get all the daemons and split them into dead and alive ones
- # remove @ if it's there - background-started-processes
- dead, alive = daemons.split.map{|d| d.gsub('@', '')}.partition{|d| d =~ /!/}
- alive = alive.map { |d| special_cases[d].nil? ? d : special_cases[d] }.flatten
- all_daemons = {:alive => alive, :dead => dead}
- end
- all_daemons.each do |state, daemons|
- status = state.to_s.send(state == :dead ? :red : :green)
- daemons.each do |daemon|
- puts "adding daemon [#{status}] #{daemon.inspect}"
- add daemon, state
- end
- end
- puts "#{@daemons.size} Daemons registered:"
- puts "Starting up - Interval every #{@interval} seconds"
- startup
- end
- def startup
- loop do
- Thread.new do
- @daemons.each do |daemon|
- case daemon.should_be
- when :alive
- # puts "#{daemon.name} is #{daemon.is} and should be #{daemon.should_be} [#{daemon.alive?}]"
- daemon.start if daemon.dead?
- when :dead
- daemon.stop if daemon.alive?
- end
- end
- failures = @daemons.find_all { |d| d.failures >= 1 }
- p failures unless failures.empty?
- failures.each do |daemon|
- puts "Found #{daemon} erronous..."
- sendmail daemon
- end
- end
- sleep @interval
- end
- end
- def [](daemon)
- @daemons.find{|d| d.name == daemon.to_sym} || @daemons[daemon]
- end
- def add daemon, state = :alive
- remove daemon
- @daemons << Daemon.new(daemon, state)
- end
- def remove daemon
- @daemons.delete_if{|d| d.name == daemon.to_sym}
- end
- def sendmail daemon
- daemon_inspect = %{
- }
- mail = MailFactory.new
- mail.to = 'm.fellinger@gmail.com'
- mail.from = 'abyss@weez-int.com'
- mail.subject = "[Abyss] Failure - #{daemon.name} - #{daemon.failures} failures"
- mail.text = %{
- Houston, we've got a problem
- #{daemon.name} is #{daemon.is} and should be #{daemon.should_be} [#{daemon.should_be daemon.should_be}]
- The Daemon:
- Name: #{daemon.name}
- is: #{daemon.is}
- should be: #{daemon.should_be}
- failures: #{daemon.failures}
- command: #{daemon.error[:cmd]}
- the error: #{daemon.error[:returned]}
- }
- sendmail = IO.popen "sendmail #{mail.to}", 'w+'
- sendmail.puts mail.to_s
- sendmail.close
- end
- end
- class Daemon
- attr_accessor :name, :should_be, :failures, :error
- def initialize name, state = :alive
- @name = name.to_sym
- @should_be = state
- @failures = 0
- @error = nil
- end
- def is
- alive? ? :alive : :dead
- end
- def should_be sym = nil
- sym ? (@should_be == sym) : @should_be
- end
- def alive?
- File.exist? "#{Abyss::STATUS_PATH}/daemons/#{name}"
- end
- def should_be_alive?
- should_be :alive
- end
- def dead?
- !alive?
- end
- def should_be_dead?
- should_be :dead
- end
- def pid
- File.read("#{Abyss::STATUS_PATH}/#{name}.pid").to_i
- end
- def start
- handle :start
- end
- def stop
- handle :stop
- end
- def restart
- handle :restart
- end
- def handle demand
- if [:start, :stop, :restart].include? demand
- puts "#{demand} #{name}"
- cmd = "sudo #{Abyss::DAEMON_PATH}/#{name} #{demand}"
- action = `#{cmd}`.uncolored
- demand_fulfilled = lambda{ demand == :stop ? dead? : alive? }
- if demand_fulfilled.call
- @failures = 0
- else
- @failures += 1
- @error = {:cmd => cmd, :returned => action}
- unless @failures > 3
- puts "#{demand} failed, trying to restart"
- handle :restart
- end
- end
- else
- puts "unknown demand '#{demand}'"
- end
- demand_fulfilled.call
- end
- end
- Abyss.new
Add Comment
Please, Sign In to add comment