deadpool 0.1.1
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.
- data/bin/deadpool_admin +8 -0
 - data/bin/deadpool_generator +8 -0
 - data/bin/deadpool_hosts +222 -0
 - data/config/default_environment.yml +7 -0
 - data/doc/init/deadpool.conf +17 -0
 - data/lib/deadpool.rb +45 -0
 - data/lib/deadpool/admin.rb +197 -0
 - data/lib/deadpool/admin_server.rb +65 -0
 - data/lib/deadpool/command_line_server.rb +169 -0
 - data/lib/deadpool/daemonizer.rb +82 -0
 - data/lib/deadpool/failover_protocol.rb +91 -0
 - data/lib/deadpool/failover_protocol/etc_hosts.rb +157 -0
 - data/lib/deadpool/failover_protocol/exec_remote_command.rb +106 -0
 - data/lib/deadpool/generator.rb +220 -0
 - data/lib/deadpool/handler.rb +100 -0
 - data/lib/deadpool/helper.rb +39 -0
 - data/lib/deadpool/monitor/base.rb +58 -0
 - data/lib/deadpool/monitor/generic_nagios.rb +47 -0
 - data/lib/deadpool/monitor/mysql.rb +62 -0
 - data/lib/deadpool/monitor/redis.rb +21 -0
 - data/lib/deadpool/options.rb +62 -0
 - data/lib/deadpool/server.rb +101 -0
 - data/lib/deadpool/state.rb +78 -0
 - data/lib/deadpool/state_snapshot.rb +81 -0
 - metadata +125 -0
 
| 
         @@ -0,0 +1,65 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Deadpool
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              module AdminServer
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                attr_accessor :deadpool_server
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                # data should be a JSON encoded hash.  It must have a command key.
         
     | 
| 
      
 11 
     | 
    
         
            +
                # {
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   'command' => 'command', 
         
     | 
| 
      
 13 
     | 
    
         
            +
                #   'pool'    => 'pool_name', 
         
     | 
| 
      
 14 
     | 
    
         
            +
                #   'server'  => 'server_label'
         
     | 
| 
      
 15 
     | 
    
         
            +
                # }
         
     | 
| 
      
 16 
     | 
    
         
            +
                def receive_data(data)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  if data.to_s =~ /command/        
         
     | 
| 
      
 18 
     | 
    
         
            +
                    deadpool_server.logger.debug "Received instruction: #{data}"
         
     | 
| 
      
 19 
     | 
    
         
            +
                    options = JSON.parse(data.to_s)
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    case options['command']
         
     | 
| 
      
 22 
     | 
    
         
            +
                    when 'full_report'
         
     | 
| 
      
 23 
     | 
    
         
            +
                      send_data full_report
         
     | 
| 
      
 24 
     | 
    
         
            +
                    when 'nagios_report'
         
     | 
| 
      
 25 
     | 
    
         
            +
                      send_data nagios_report
         
     | 
| 
      
 26 
     | 
    
         
            +
                    when 'promote_server'
         
     | 
| 
      
 27 
     | 
    
         
            +
                      send_data promote_server options
         
     | 
| 
      
 28 
     | 
    
         
            +
                    when 'stop'
         
     | 
| 
      
 29 
     | 
    
         
            +
                      send_data stop
         
     | 
| 
      
 30 
     | 
    
         
            +
                    else
         
     | 
| 
      
 31 
     | 
    
         
            +
                      send_data "Server did not understand the command."
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  close_connection_after_writing
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                protected
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                def full_report
         
     | 
| 
      
 41 
     | 
    
         
            +
                  return deadpool_server.system_check(true).full_report
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def nagios_report
         
     | 
| 
      
 45 
     | 
    
         
            +
                  return deadpool_server.system_check.nagios_report
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                def promote_server(options)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  if deadpool_server.promote_server(options['pool'], options['server'].to_sym)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    return "Success.\n"
         
     | 
| 
      
 51 
     | 
    
         
            +
                  else
         
     | 
| 
      
 52 
     | 
    
         
            +
                    return "Failed!\n"
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def stop
         
     | 
| 
      
 57 
     | 
    
         
            +
                  close_connection
         
     | 
| 
      
 58 
     | 
    
         
            +
                  deadpool_server.kill
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,169 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            require 'optparse'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'ostruct'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'strscan'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            module Deadpool
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              class CommandLineServer
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize(argv)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @argv     = argv
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def run
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @options = self.parse_command_line
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @config  = Deadpool::Helper.configure @options
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  self.execute_command(@options)
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def parse_command_line
         
     | 
| 
      
 25 
     | 
    
         
            +
                  options               = Hash.new
         
     | 
| 
      
 26 
     | 
    
         
            +
                  options[:command_count] = 0
         
     | 
| 
      
 27 
     | 
    
         
            +
                  options[:config_path]     = '/etc/deadpool'
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  @option_parser = OptionParser.new do |opts|
         
     | 
| 
      
 30 
     | 
    
         
            +
                    opts.banner = "Usage: deadpool_hosts {help|full_report|nagios_report} [options]"
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    opts.separator "Commands:"
         
     | 
| 
      
 33 
     | 
    
         
            +
                    opts.on("-h", "--help", "Print this help message.") do |help|
         
     | 
| 
      
 34 
     | 
    
         
            +
                      options[:command_count] += 1
         
     | 
| 
      
 35 
     | 
    
         
            +
                      options[:command]        = :help
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
                    opts.on("--full_report", "Give the full system report.") do |full_report|
         
     | 
| 
      
 38 
     | 
    
         
            +
                      options[:command_count] += 1
         
     | 
| 
      
 39 
     | 
    
         
            +
                      options[:command]        = :full_report
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    opts.on("--nagios_report", "Report system state in Nagios plugin format.") do |nagios_report|
         
     | 
| 
      
 42 
     | 
    
         
            +
                      options[:command_count] += 1
         
     | 
| 
      
 43 
     | 
    
         
            +
                      options[:command]        = :nagios_report
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                    opts.on("--promote_server", "Promote specified server to the master.") do |nagios_report|
         
     | 
| 
      
 46 
     | 
    
         
            +
                      options[:command_count] += 1
         
     | 
| 
      
 47 
     | 
    
         
            +
                      options[:command]        = :promote_server
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                    opts.on("--stop", "Stop the server.") do |stop|
         
     | 
| 
      
 50 
     | 
    
         
            +
                      options[:command_count] += 1
         
     | 
| 
      
 51 
     | 
    
         
            +
                      options[:command]        = :stop
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    opts.separator "Options:"
         
     | 
| 
      
 55 
     | 
    
         
            +
                    opts.on("--server=SERVER_LABEL", String, "primary_host or secondary_host.") do |server|
         
     | 
| 
      
 56 
     | 
    
         
            +
                      options[:server] = server
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
                    opts.on("--pool=POOL_NAME", String, "Deadpool name to operate on.") do |pool|
         
     | 
| 
      
 59 
     | 
    
         
            +
                      options[:pool] = pool
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
                    opts.on("--config_path=PATH", String, 
         
     | 
| 
      
 62 
     | 
    
         
            +
                        "Path to configs and custom plugins. #{options[:config_path]} by default.") do |config_path|
         
     | 
| 
      
 63 
     | 
    
         
            +
                      options[:config_path] = config_path
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  remaining_arguments = @option_parser.parse! @argv
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  unless remaining_arguments.empty?
         
     | 
| 
      
 70 
     | 
    
         
            +
                    help "[#{remaining_arguments.join(' ')}] is not understood."
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  if options[:command_count] == 0
         
     | 
| 
      
 74 
     | 
    
         
            +
                    help "You must specify a command."
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  return options
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def execute_command(options)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  case options[:command]
         
     | 
| 
      
 82 
     | 
    
         
            +
                  when :help
         
     | 
| 
      
 83 
     | 
    
         
            +
                    help
         
     | 
| 
      
 84 
     | 
    
         
            +
                  when :full_report
         
     | 
| 
      
 85 
     | 
    
         
            +
                    full_report options
         
     | 
| 
      
 86 
     | 
    
         
            +
                  when :nagios_report
         
     | 
| 
      
 87 
     | 
    
         
            +
                    nagios_report options
         
     | 
| 
      
 88 
     | 
    
         
            +
                  when :promote_server
         
     | 
| 
      
 89 
     | 
    
         
            +
                    promote_server options
         
     | 
| 
      
 90 
     | 
    
         
            +
                  when :stop
         
     | 
| 
      
 91 
     | 
    
         
            +
                    stop options
         
     | 
| 
      
 92 
     | 
    
         
            +
                  else
         
     | 
| 
      
 93 
     | 
    
         
            +
                    help
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                def help(message=nil)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  unless message.nil?
         
     | 
| 
      
 99 
     | 
    
         
            +
                    puts message
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                  puts @option_parser.help
         
     | 
| 
      
 102 
     | 
    
         
            +
                  exit 4
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                def full_report(options)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  puts send_command_to_deadpool_server :command => 'full_report'
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                def nagios_report(options)
         
     | 
| 
      
 110 
     | 
    
         
            +
                  response = send_command_to_deadpool_server :command => 'nagios_report'
         
     | 
| 
      
 111 
     | 
    
         
            +
                  puts response
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  if (response.to_s =~ /^OK/) != nil
         
     | 
| 
      
 114 
     | 
    
         
            +
                    exit 0
         
     | 
| 
      
 115 
     | 
    
         
            +
                  elsif (response.to_s =~ /^WARNING/) != nil
         
     | 
| 
      
 116 
     | 
    
         
            +
                    exit 1
         
     | 
| 
      
 117 
     | 
    
         
            +
                  elsif (response.to_s =~ /^CRITICAL/) != nil
         
     | 
| 
      
 118 
     | 
    
         
            +
                    exit 2
         
     | 
| 
      
 119 
     | 
    
         
            +
                  elsif (response.to_s =~ /^UNKNOWN/) != nil
         
     | 
| 
      
 120 
     | 
    
         
            +
                    exit 3
         
     | 
| 
      
 121 
     | 
    
         
            +
                  else
         
     | 
| 
      
 122 
     | 
    
         
            +
                    exit 4
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                def promote_server(options)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  error_messages = []
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  if options[:pool].nil?
         
     | 
| 
      
 130 
     | 
    
         
            +
                    error_messages << "Promoting server requires --pool argument."
         
     | 
| 
      
 131 
     | 
    
         
            +
                  end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  if options[:server].nil?
         
     | 
| 
      
 134 
     | 
    
         
            +
                    error_messages << "Promoting server requires --server argument."
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
                  
         
     | 
| 
      
 137 
     | 
    
         
            +
                  unless error_messages.empty?
         
     | 
| 
      
 138 
     | 
    
         
            +
                    help error_messages.join "\n"
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                  puts send_command_to_deadpool_server :command => 'promote_server', :pool => options[:pool], :server => options[:server]
         
     | 
| 
      
 142 
     | 
    
         
            +
                end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                def stop(options)
         
     | 
| 
      
 145 
     | 
    
         
            +
                  puts send_command_to_deadpool_server :command => 'stop'
         
     | 
| 
      
 146 
     | 
    
         
            +
                end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                def send_command_to_deadpool_server(options)
         
     | 
| 
      
 149 
     | 
    
         
            +
                  output = ''
         
     | 
| 
      
 150 
     | 
    
         
            +
                  socket = TCPSocket.open(@config[:admin_hostname], @config[:admin_port])
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  if socket
         
     | 
| 
      
 153 
     | 
    
         
            +
                    socket.puts JSON.dump(options)
         
     | 
| 
      
 154 
     | 
    
         
            +
                    while line = socket.gets
         
     | 
| 
      
 155 
     | 
    
         
            +
                      output += line
         
     | 
| 
      
 156 
     | 
    
         
            +
                    end
         
     | 
| 
      
 157 
     | 
    
         
            +
                    socket.close
         
     | 
| 
      
 158 
     | 
    
         
            +
                  else
         
     | 
| 
      
 159 
     | 
    
         
            +
                    puts "Couldn't connect to deadpool server."
         
     | 
| 
      
 160 
     | 
    
         
            +
                    exit 4
         
     | 
| 
      
 161 
     | 
    
         
            +
                  end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                  return output
         
     | 
| 
      
 164 
     | 
    
         
            +
                end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
              end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
            end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,82 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Blatanly stolen from Ben Marini
         
     | 
| 
      
 4 
     | 
    
         
            +
            # https://gist.github.com/517442/9ed5c4bd66bd8afc6a379286d8be1d8fb8a33925
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Deadpool
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              module Daemonizer
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def daemonize(opts={})
         
     | 
| 
      
 12 
     | 
    
         
            +
                  opts = { :log => '/dev/null', :pid => "/var/run/#{File.basename($0)}.pid" }.merge(opts)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  $stdout.sync = $stderr.sync = true
         
     | 
| 
      
 15 
     | 
    
         
            +
                  $stdin.reopen("/dev/null")
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  exit if fork
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  Process.setsid
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  exit if fork
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  Dir.chdir("/") if opts[:chdir]
         
     | 
| 
      
 24 
     | 
    
         
            +
                  File.umask(0000) if opts[:umask]
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  if File.exist?(opts[:pid])
         
     | 
| 
      
 27 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 28 
     | 
    
         
            +
                      existing_pid = File.read(opts[:pid]).to_i
         
     | 
| 
      
 29 
     | 
    
         
            +
                      Process.kill(0, existing_pid) # See if proc exists
         
     | 
| 
      
 30 
     | 
    
         
            +
                      abort "error: existing process #{existing_pid} using this pidfile, exiting"
         
     | 
| 
      
 31 
     | 
    
         
            +
                    rescue Errno::ESRCH
         
     | 
| 
      
 32 
     | 
    
         
            +
                      puts "warning: removing stale pidfile with pid #{existing_pid}"
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  File.open(opts[:pid], 'w') { |f| f.write($$) }
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  at_exit do
         
     | 
| 
      
 39 
     | 
    
         
            +
                    ( File.read(opts[:pid]).to_i == $$ and File.unlink(opts[:pid]) ) rescue nil
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  puts "forked process is #{$$}"
         
     | 
| 
      
 43 
     | 
    
         
            +
                  puts "output redirected to #{opts[:log]}"
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  $stdout.reopen(opts[:log], 'a')
         
     | 
| 
      
 46 
     | 
    
         
            +
                  $stderr.reopen(opts[:log], 'a')
         
     | 
| 
      
 47 
     | 
    
         
            +
                  $stdout.sync = $stderr.sync = true
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def kill(opts={})
         
     | 
| 
      
 51 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 52 
     | 
    
         
            +
                    opts = { :log => "/dev/null", :pid => "/var/run/#{File.basename($0)}.pid" }.merge(opts)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    pid = File.read(opts[:pid]).to_i
         
     | 
| 
      
 54 
     | 
    
         
            +
                    sec = 60 # Seconds to wait before force killing
         
     | 
| 
      
 55 
     | 
    
         
            +
                    Process.kill("TERM", pid)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 58 
     | 
    
         
            +
                      SystemTimer.timeout(sec) do
         
     | 
| 
      
 59 
     | 
    
         
            +
                        loop do
         
     | 
| 
      
 60 
     | 
    
         
            +
                          puts "waiting #{sec} seconds for #{pid} before sending KILL"
         
     | 
| 
      
 61 
     | 
    
         
            +
                          Process.kill(0, pid) # See if proc exists
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                          sec -= 1
         
     | 
| 
      
 64 
     | 
    
         
            +
                          sleep 1
         
     | 
| 
      
 65 
     | 
    
         
            +
                        end
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    rescue Errno::ESRCH
         
     | 
| 
      
 68 
     | 
    
         
            +
                      puts "killed process #{pid}"
         
     | 
| 
      
 69 
     | 
    
         
            +
                    rescue Timeout::Error
         
     | 
| 
      
 70 
     | 
    
         
            +
                      Process.kill("KILL", pid)
         
     | 
| 
      
 71 
     | 
    
         
            +
                      puts "force killed process #{pid}"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  rescue Errno::ENOENT
         
     | 
| 
      
 75 
     | 
    
         
            +
                    puts "warning: pidfile #{opts[:pid]} does not exist"
         
     | 
| 
      
 76 
     | 
    
         
            +
                  rescue Errno::ESRCH
         
     | 
| 
      
 77 
     | 
    
         
            +
                    puts "warning: process #{pid} does not exist"
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,91 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Deadpool
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              module FailoverProtocol
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                class Base
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  attr_accessor :logger
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attr_reader :config
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def initialize(config, failover_config, logger)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @name            = failover_config[:name].nil? ? '' : failover_config[:name]
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @state           = Deadpool::State.new @name, self.class
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @config          = config
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @logger          = logger
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @primary_host    = @config[:primary_host]
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @secondary_host  = @config[:secondary_host]
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @failover_config = failover_config
         
     | 
| 
      
 21 
     | 
    
         
            +
                    setup
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  # Implementation specific initialization should be placed here.
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def setup
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  # Overwrite this if you need to.
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # Update state to reflect that failover has been initiated.
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # State must be updated to no less than WARNING.
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # State must be CRITICAL if any step of the protocol fails.
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # Lock the state at whatever stage the failover reached.
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # return true or false on success or failure.
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # 
         
     | 
| 
      
 35 
     | 
    
         
            +
                  def initiate_failover_protocol!
         
     | 
| 
      
 36 
     | 
    
         
            +
                    logger.info "Performing Preflight Check"
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @state.set_state WARNING, "Failover Protocol Initiated."
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    if preflight_check
         
     | 
| 
      
 40 
     | 
    
         
            +
                      logger.info "Preflight Check Passed."
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @state.add_message "Preflight Check Passed."
         
     | 
| 
      
 42 
     | 
    
         
            +
                    else
         
     | 
| 
      
 43 
     | 
    
         
            +
                      logger.error "Preflight Check Failed!  Aborting Failover Protocol."
         
     | 
| 
      
 44 
     | 
    
         
            +
                      @state.escalate_status_code CRITICAL
         
     | 
| 
      
 45 
     | 
    
         
            +
                      @state.add_error_message "Preflight Check Failed! Failover Protocol Aborted!"
         
     | 
| 
      
 46 
     | 
    
         
            +
                      @state.lock
         
     | 
| 
      
 47 
     | 
    
         
            +
                      return false
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    if promote_to_primary(@secondary_host)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      logger.info "#{@secondary_host} successfully promoted to primary"
         
     | 
| 
      
 52 
     | 
    
         
            +
                      @state.add_message "Failover Protocol Successful."
         
     | 
| 
      
 53 
     | 
    
         
            +
                      @state.lock
         
     | 
| 
      
 54 
     | 
    
         
            +
                      return true
         
     | 
| 
      
 55 
     | 
    
         
            +
                    else
         
     | 
| 
      
 56 
     | 
    
         
            +
                      logger.info "#{@secondary_host} promotion failed."
         
     | 
| 
      
 57 
     | 
    
         
            +
                      @state.escalate_status_code CRITICAL
         
     | 
| 
      
 58 
     | 
    
         
            +
                      @state.add_error_message "Failover Protocol Failed!"
         
     | 
| 
      
 59 
     | 
    
         
            +
                      @state.lock
         
     | 
| 
      
 60 
     | 
    
         
            +
                      return false
         
     | 
| 
      
 61 
     | 
    
         
            +
                    end
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  # Return true or false
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # Don't update system state.
         
     | 
| 
      
 66 
     | 
    
         
            +
                  # return true or false success or failure
         
     | 
| 
      
 67 
     | 
    
         
            +
                  def preflight_check
         
     | 
| 
      
 68 
     | 
    
         
            +
                    return false
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  # Promote the host to primary.  This is used by initiate_failover_protocol!
         
     | 
| 
      
 72 
     | 
    
         
            +
                  # and for manual promotion by an administrator.
         
     | 
| 
      
 73 
     | 
    
         
            +
                  # new_primary is an IP address
         
     | 
| 
      
 74 
     | 
    
         
            +
                  # TODO: change new_primary to be a config label.
         
     | 
| 
      
 75 
     | 
    
         
            +
                  # return true or false success or failure
         
     | 
| 
      
 76 
     | 
    
         
            +
                  def promote_to_primary(new_primary)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    return false
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  # Perform checks against anything that could cause a failover protocol to fail
         
     | 
| 
      
 81 
     | 
    
         
            +
                  # Perform checks on system state.
         
     | 
| 
      
 82 
     | 
    
         
            +
                  # return New Deadpool::StateSnapshot
         
     | 
| 
      
 83 
     | 
    
         
            +
                  def system_check
         
     | 
| 
      
 84 
     | 
    
         
            +
                    return Deadpool::StateSnapshot.new @state
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
              end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,157 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            require 'net/ssh'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Deadpool
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              module FailoverProtocol
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                class EtcHosts < Base
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def setup
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @script_path        = @failover_config[:script_path]
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @service_host_name  = @failover_config[:service_host_name]
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @service_hosts_file = @failover_config[:service_hosts_file]
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @client_hosts       = @failover_config[:client_hosts]
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @username           = @failover_config[:username]
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @password           = @failover_config[:password]
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @use_sudo           = @failover_config[:use_sudo]
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @sudo_path          = @failover_config[:sudo_path].nil? ? 'sudo' : @failover_config[:sudo_path]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def preflight_check
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @client_hosts.map { |h| test_client(h) && verify_client(h) }.all?
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def test_client(client_host)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    logger.debug "Testing Client #{client_host}"
         
     | 
| 
      
 27 
     | 
    
         
            +
                    output = run_script_command(client_host, '--test')
         
     | 
| 
      
 28 
     | 
    
         
            +
                    logger.debug "Output recieved From Client: #{output}"
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    if output.class == String
         
     | 
| 
      
 31 
     | 
    
         
            +
                      okay = (output =~ /^OK/) != nil
         
     | 
| 
      
 32 
     | 
    
         
            +
                      okay ? logger.info("#{client_host}: " + output.strip) : logger.error("#{client_host}: " + output.strip)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    else
         
     | 
| 
      
 34 
     | 
    
         
            +
                      logger.error "Test Client had a critical failure on '#{client_host}'"
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    return okay
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def verify_client(client_host, primary_host=nil)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    logger.debug "Verifying Client #{client_host}"
         
     | 
| 
      
 42 
     | 
    
         
            +
                    primary_host      = primary_host.nil? ? @primary_host : primary_host
         
     | 
| 
      
 43 
     | 
    
         
            +
                    command_arguments = "--verify --host_name='#{@service_host_name}' --ip_address='#{primary_host}'"
         
     | 
| 
      
 44 
     | 
    
         
            +
                    command_arguments += " --host_file='#{@service_hosts_file}'" if @service_hosts_file
         
     | 
| 
      
 45 
     | 
    
         
            +
                    output            = run_script_command(client_host, command_arguments)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    logger.debug "Output recieved From Client: #{output}"
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    if output.class == String
         
     | 
| 
      
 49 
     | 
    
         
            +
                      okay = (output =~ /^OK/) != nil
         
     | 
| 
      
 50 
     | 
    
         
            +
                      okay ? logger.info("#{client_host}: " + output.strip) : logger.error("#{client_host}: " + output.strip)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    else
         
     | 
| 
      
 52 
     | 
    
         
            +
                      logger.error "Verify Client had a critical failure on '#{client_host}'"
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    return okay
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  def promote_to_primary(new_primary)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    @client_hosts.map do |client_host|
         
     | 
| 
      
 60 
     | 
    
         
            +
                      # logger.debug "client_host: #{client_host}, New Primary: #{new_primary}"
         
     | 
| 
      
 61 
     | 
    
         
            +
                      promote_to_primary_on_client(client_host, new_primary)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end.all?
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def promote_to_primary_on_client(client_host, new_primary)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    # logger.debug "Assigning #{new_primary} as new primary on #{client_host}"
         
     | 
| 
      
 67 
     | 
    
         
            +
                    command_arguments = "--switch --host_name='#{@service_host_name}' --ip_address='#{new_primary}'"
         
     | 
| 
      
 68 
     | 
    
         
            +
                    command_arguments += " --host_file='#{@service_hosts_file}'" if @service_hosts_file
         
     | 
| 
      
 69 
     | 
    
         
            +
                    output            = run_script_command(client_host, command_arguments)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    logger.debug "Output received From Client: #{output}"
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    if output.class == String
         
     | 
| 
      
 73 
     | 
    
         
            +
                      okay = (output =~ /^OK/) != nil
         
     | 
| 
      
 74 
     | 
    
         
            +
                      okay ? logger.info("#{client_host}: " + output.strip) : logger.error("#{client_host}: " + output.strip)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    else
         
     | 
| 
      
 76 
     | 
    
         
            +
                      logger.error "Promote to Primary on Client had a critical failure on '#{client_host}'"
         
     | 
| 
      
 77 
     | 
    
         
            +
                    end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    return okay
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
              
         
     | 
| 
      
 82 
     | 
    
         
            +
                  def system_check
         
     | 
| 
      
 83 
     | 
    
         
            +
                    writable             = []
         
     | 
| 
      
 84 
     | 
    
         
            +
                    not_writable         = []
         
     | 
| 
      
 85 
     | 
    
         
            +
                    pointed_at_primary   = []
         
     | 
| 
      
 86 
     | 
    
         
            +
                    pointed_at_secondary = []
         
     | 
| 
      
 87 
     | 
    
         
            +
                    pointed_at_neither   = []
         
     | 
| 
      
 88 
     | 
    
         
            +
                
         
     | 
| 
      
 89 
     | 
    
         
            +
                    # Collect check data
         
     | 
| 
      
 90 
     | 
    
         
            +
                    @client_hosts.each do |client_host|
         
     | 
| 
      
 91 
     | 
    
         
            +
                      if test_client(client_host)
         
     | 
| 
      
 92 
     | 
    
         
            +
                        writable << client_host
         
     | 
| 
      
 93 
     | 
    
         
            +
                      else
         
     | 
| 
      
 94 
     | 
    
         
            +
                        not_writable << client_host
         
     | 
| 
      
 95 
     | 
    
         
            +
                      end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                      if verify_client(client_host, @primary_host)
         
     | 
| 
      
 98 
     | 
    
         
            +
                        pointed_at_primary << client_host
         
     | 
| 
      
 99 
     | 
    
         
            +
                      else
         
     | 
| 
      
 100 
     | 
    
         
            +
                        if verify_client(client_host, @secondary_host)
         
     | 
| 
      
 101 
     | 
    
         
            +
                          pointed_at_secondary << client_host
         
     | 
| 
      
 102 
     | 
    
         
            +
                        else
         
     | 
| 
      
 103 
     | 
    
         
            +
                          pointed_at_neither << client_host
         
     | 
| 
      
 104 
     | 
    
         
            +
                        end
         
     | 
| 
      
 105 
     | 
    
         
            +
                      end
         
     | 
| 
      
 106 
     | 
    
         
            +
                    end
         
     | 
| 
      
 107 
     | 
    
         
            +
                
         
     | 
| 
      
 108 
     | 
    
         
            +
                    # Compile write check data.
         
     | 
| 
      
 109 
     | 
    
         
            +
                    if !writable.empty? && not_writable.empty?
         
     | 
| 
      
 110 
     | 
    
         
            +
                      @state.set_state OK, "Write check passed all servers: #{writable.join(', ')}"
         
     | 
| 
      
 111 
     | 
    
         
            +
                    elsif !writable.empty? && !not_writable.empty?
         
     | 
| 
      
 112 
     | 
    
         
            +
                      @state.set_state WARNING, "Write check passed on: #{writable.join(', ')}"
         
     | 
| 
      
 113 
     | 
    
         
            +
                      @state.add_error_message "Write check failed on #{not_writable.join(', ')}"
         
     | 
| 
      
 114 
     | 
    
         
            +
                    elsif writable.empty?
         
     | 
| 
      
 115 
     | 
    
         
            +
                      @state.set_state WARNING, "Write check failed all servers: #{not_writable.join(', ')}"
         
     | 
| 
      
 116 
     | 
    
         
            +
                    end
         
     | 
| 
      
 117 
     | 
    
         
            +
                
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                    # Compile verification data
         
     | 
| 
      
 120 
     | 
    
         
            +
                    if !pointed_at_primary.empty? && pointed_at_secondary.empty? && pointed_at_neither.empty?
         
     | 
| 
      
 121 
     | 
    
         
            +
                      @state.add_message "All client hosts are pointed at the primary."
         
     | 
| 
      
 122 
     | 
    
         
            +
                    elsif pointed_at_primary.empty? && !pointed_at_secondary.empty? && pointed_at_neither.empty?
         
     | 
| 
      
 123 
     | 
    
         
            +
                      @state.escalate_status_code WARNING
         
     | 
| 
      
 124 
     | 
    
         
            +
                      @state.add_error_message "All client hosts are pointed at the secondary."
         
     | 
| 
      
 125 
     | 
    
         
            +
                    else
         
     | 
| 
      
 126 
     | 
    
         
            +
                      @state.escalate_status_code CRITICAL
         
     | 
| 
      
 127 
     | 
    
         
            +
                      @state.add_error_message "Client hosts are pointing in different directions."
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    return Deadpool::StateSnapshot.new @state
         
     | 
| 
      
 131 
     | 
    
         
            +
                  end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  def run_script_command(host, command_arguments)
         
     | 
| 
      
 137 
     | 
    
         
            +
                    options = @password.nil? ? {} : {:password => @password}
         
     | 
| 
      
 138 
     | 
    
         
            +
                    command = "#{@script_path} #{command_arguments}"
         
     | 
| 
      
 139 
     | 
    
         
            +
                    command = "#{@sudo_path} #{command}" if @use_sudo
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                    logger.debug "executing #{command} on #{host}"
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 144 
     | 
    
         
            +
                      Net::SSH.start(host, @username, options) do |ssh|
         
     | 
| 
      
 145 
     | 
    
         
            +
                        return ssh.exec!(command)
         
     | 
| 
      
 146 
     | 
    
         
            +
                      end
         
     | 
| 
      
 147 
     | 
    
         
            +
                    rescue
         
     | 
| 
      
 148 
     | 
    
         
            +
                      logger.error "Couldn't execute #{command} on #{host}"
         
     | 
| 
      
 149 
     | 
    
         
            +
                      return false
         
     | 
| 
      
 150 
     | 
    
         
            +
                    end
         
     | 
| 
      
 151 
     | 
    
         
            +
                  end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                end
         
     | 
| 
      
 154 
     | 
    
         
            +
                
         
     | 
| 
      
 155 
     | 
    
         
            +
              end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
            end
         
     |