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.
@@ -0,0 +1,58 @@
1
+ module Deadpool
2
+ module Monitor
3
+ class Base
4
+ attr_accessor :logger
5
+
6
+ def initialize(config, monitor_config, logger)
7
+ @config, @monitor_config, @logger = config, monitor_config, logger
8
+ end
9
+
10
+ def primary_ok?
11
+ raise NotImplementedError, "primary_ok? is not implemented"
12
+ end
13
+
14
+ def secondary_ok?
15
+ raise NotImplementedError, "secondary_ok? is not implemented"
16
+ end
17
+
18
+ def system_check
19
+ update_state
20
+ take_snapshot
21
+ end
22
+
23
+ def state
24
+ @state ||= Deadpool::State.new name, self.class
25
+ end
26
+
27
+ protected
28
+
29
+ def update_state
30
+ primary_okay, secondary_okay = primary_ok?, secondary_ok?
31
+ logger.debug "PrimaryOkay? #{primary_okay}, SecondaryOkay? #{secondary_okay}"
32
+
33
+ args = case [ primary_okay, secondary_okay ]
34
+ when [true, true]
35
+ [ OK, "Primary and Secondary are up." ]
36
+ when [false, true]
37
+ [ WARNING, "Primary is down. Secondary is up." ]
38
+ when [true, false]
39
+ [ WARNING, "Primary is up. Secondary is down." ]
40
+ when [false, false]
41
+ [ CRITICAL, "Primary and Secondary are down." ]
42
+ else
43
+ [ CRITICAL, "Implementation Error." ]
44
+ end
45
+
46
+ self.state.set_state(*args)
47
+ end
48
+
49
+ def take_snapshot
50
+ StateSnapshot.new(self.state)
51
+ end
52
+
53
+ def name
54
+ @monitor_config[:name].nil? ? '' : @monitor_config[:name]
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,47 @@
1
+ # Assumes at a minimum the following config:
2
+ # --
3
+ # primary_host: '127.0.0.1'
4
+ # secondary_host: '127.0.0.1'
5
+ # monitor_config:
6
+ # nagios_plugin_path: '/usr/lib/nagios/plugins/check_something'
7
+
8
+ module Deadpool
9
+
10
+ module Monitor
11
+
12
+ class GenericNagios < Base
13
+
14
+ def primary_ok?
15
+ check_host(@config[:primary_host])
16
+ end
17
+
18
+ def secondary_ok?
19
+ check_host(@config[:secondary_host])
20
+ end
21
+
22
+ protected
23
+
24
+ def check_host(host)
25
+ check_command = "#{nagios_plugin_path} -H #{host} #{nagios_options}"
26
+ logger.debug check_command
27
+ status_message = `#{check_command}`
28
+ exit_status = $?
29
+ logger.debug "Generic Nagios Check Status Message: #{status_message}"
30
+ logger.debug "Generic Nagios Check Exit Status: #{exit_status}"
31
+
32
+ return exit_status == 0
33
+ end
34
+
35
+ def nagios_plugin_path
36
+ @config[:monitor_config][:nagios_plugin_path]
37
+ end
38
+
39
+ def nagios_options
40
+ @config[:monitor_config][:nagios_options]
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,62 @@
1
+ # Assumes at a minimum the following config:
2
+ # --
3
+ # primary_host: '127.0.0.1'
4
+ # secondary_host: '127.0.0.1'
5
+ # monitor_config:
6
+ # nagios_plugin_path: '/usr/lib/nagios/plugins/check_mysql'
7
+
8
+ module Deadpool
9
+
10
+ module Monitor
11
+
12
+ class Mysql < Base
13
+
14
+ def primary_ok?
15
+ return check_mysql(@config[:primary_host])
16
+ end
17
+
18
+ def secondary_ok?
19
+ return check_mysql(@config[:secondary_host])
20
+ # && check_mysql_slave(@config[:secondary_host])
21
+ end
22
+
23
+ protected
24
+
25
+ def check_mysql(host)
26
+ check_command = "#{nagios_plugin_path} -H #{host} -u '#{username}' -p '#{password}'"
27
+ logger.debug check_command
28
+ status_message = `#{check_command}`
29
+ exit_status = $?
30
+ logger.debug "MySQL Check Status Message: #{status_message}"
31
+ logger.debug "MySQL Check Exit Status: #{exit_status}"
32
+
33
+ return exit_status == 0
34
+ end
35
+
36
+ def check_mysql_slave(host)
37
+ check_command = "#{nagios_plugin_path} -H #{host} -u '#{username}' -p '#{password}' --check-slave"
38
+ logger.debug check_command
39
+ status_message = `#{check_command}`
40
+ exit_status = $?
41
+ logger.debug "MySQL Check Status Message: #{status_message}"
42
+ logger.debug "MySQL Check Exit Status: #{exit_status}"
43
+
44
+ return exit_status == 0
45
+ end
46
+
47
+ def nagios_plugin_path
48
+ @config[:monitor_config][:nagios_plugin_path]
49
+ end
50
+
51
+ def username
52
+ @config[:monitor_config][:username]
53
+ end
54
+
55
+ def password
56
+ @config[:monitor_config][:password]
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,21 @@
1
+ # Assumes at a minimum the following config:
2
+ # --
3
+ # primary_host: '127.0.0.1'
4
+ # secondary_host: '127.0.0.1'
5
+ # monitor_config:
6
+ # redis_args: '[-h host] [-p port] [-a authpw] [-r repeat_times] [-n db_num]'
7
+
8
+ module Deadpool
9
+ module Monitor
10
+ class Redis < Base
11
+
12
+ def primary_ok?
13
+ false
14
+ end
15
+
16
+ def secondary_ok?
17
+ false
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,62 @@
1
+
2
+ require 'optparse'
3
+ require 'ostruct'
4
+ require 'strscan'
5
+
6
+
7
+ module Deadpool
8
+
9
+ module Options
10
+
11
+ def parse_options(argv)
12
+ @options = self.parse_command_line(argv)
13
+ end
14
+
15
+ def parse_command_line(argv)
16
+ options = {}
17
+ options[:config_path] = '/etc/deadpool'
18
+ options[:daemonize] = nil
19
+
20
+ @option_parser = OptionParser.new do |opts|
21
+ opts.banner = "Usage: deadpool_hosts {help|full_report|nagios_report} [options]"
22
+
23
+ opts.separator "Commands:"
24
+ opts.on("-h", "--help", "Print this help message.") do |help|
25
+ options[:help] = true
26
+ end
27
+
28
+ opts.on("-d", "--daemon", "Background the server.") do |daemon|
29
+ options[:daemonize] = true
30
+ end
31
+
32
+ opts.separator "Options:"
33
+ opts.on("--config_path=PATH", String,
34
+ "Path to configs and custom plugins. #{options[:config_path]} by default.") do |config_path|
35
+ options[:config_path] = config_path
36
+ end
37
+ end
38
+
39
+ remaining_arguments = @option_parser.parse! argv
40
+
41
+ unless remaining_arguments.empty?
42
+ help "[#{remaining_arguments.join(' ')}] is not understood."
43
+ end
44
+
45
+ return options
46
+ end
47
+
48
+ def help(message=nil)
49
+ unless message.nil?
50
+ puts message
51
+ end
52
+ puts @option_parser.help
53
+ exit 4
54
+ end
55
+
56
+ def config_path
57
+ return @options[:config_path]
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,101 @@
1
+
2
+
3
+ module Deadpool
4
+
5
+ class Server
6
+
7
+ # include Deadpool::Options
8
+ include Deadpool::Daemonizer
9
+
10
+ attr_accessor :logger
11
+ attr_reader :config
12
+
13
+ def initialize(options)
14
+ @options = options
15
+ @state = Deadpool::State.new self.class.to_s
16
+ @config = Deadpool::Helper.configure(@options)
17
+ @logger = Deadpool::Helper.setup_logger(@config)
18
+
19
+ # if @options[:daemonize]
20
+ # options = @options[:pid_file].nil? ? {} : {:pid => @options[:pid_file]}
21
+ # self.daemonize options
22
+ # end
23
+ #
24
+ # load_handlers
25
+ # start_deadpool_handlers
26
+ # start_command_server
27
+ # schedule_system_check
28
+ end
29
+
30
+ def run(daemonize)
31
+ EventMachine::run {
32
+ if daemonize
33
+ options = @options[:pid_file].nil? ? {} : {:pid => @options[:pid_file]}
34
+ self.daemonize options
35
+ end
36
+
37
+ load_handlers
38
+ start_deadpool_handlers
39
+ start_command_server
40
+ schedule_system_check
41
+ }
42
+ end
43
+
44
+ def load_handlers
45
+ @handlers = {}
46
+ @state.set_state(OK, 'Loading Handlers.')
47
+
48
+ Dir[@options[:config_path] + '/config/pools/*.yml'].each do |pool_yml|
49
+ pool_config = Deadpool::Helper.symbolize_keys YAML.load(File.read(pool_yml))
50
+ @handlers[pool_config[:pool_name]] = Deadpool::Handler.new(pool_config, logger)
51
+ end
52
+
53
+ @state.set_state(OK, 'Handlers loaded.')
54
+ end
55
+
56
+ def start_deadpool_handlers
57
+ @handlers.each_value do |handler|
58
+ timer = EventMachine::PeriodicTimer.new(handler.check_interval) do
59
+ handler.monitor_pool(timer)
60
+ end
61
+ end
62
+ end
63
+
64
+ def schedule_system_check
65
+ timer = EventMachine::PeriodicTimer.new(@config[:system_check_interval]) do
66
+ system_check(true)
67
+ end
68
+ end
69
+
70
+ def start_command_server
71
+ EventMachine::start_server @config[:admin_hostname], @config[:admin_port], Deadpool::AdminServer do |connection|
72
+ connection.deadpool_server = self
73
+ end
74
+ end
75
+
76
+ def system_check(force=false)
77
+ if force || @cached_state_snapshot.nil?
78
+ @state.reset!
79
+ @cached_state_snapshot = Deadpool::StateSnapshot.new @state
80
+
81
+ @handlers.each_value do |handler|
82
+ @cached_state_snapshot.add_child handler.system_check
83
+ end
84
+ end
85
+
86
+ return @cached_state_snapshot
87
+ end
88
+
89
+ def promote_server(pool_name, server)
90
+ unless @handlers[pool_name].nil?
91
+ # logger.debug "Pool Name: #{pool_name}, Server: #{server}"
92
+ return @handlers[pool_name].promote_server server
93
+ else
94
+ logger.error "'#{pool_name}' pool not found."
95
+ return false
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,78 @@
1
+
2
+
3
+
4
+ module Deadpool
5
+
6
+ class State
7
+
8
+ attr_reader :name, :timestamp, :status_code, :error_messages, :all_messages
9
+
10
+ def initialize(name, klass='')
11
+ names = []
12
+ names << name unless (name.nil? and name.blank?)
13
+ names << klass.to_s unless (klass.nil? and klass.blank?)
14
+ @name = names.join " - "
15
+ @locked = false
16
+ reset!
17
+ end
18
+
19
+ def lock
20
+ @locked = true
21
+ end
22
+
23
+ def unlock
24
+ @locked = false
25
+ end
26
+
27
+ def set_state(code, message)
28
+ unless @locked
29
+ if code == OK
30
+ @timestamp = Time.now
31
+ @status_code = OK
32
+ @error_messages = []
33
+ @all_messages = [message]
34
+ else
35
+ @timestamp = Time.now
36
+ @status_code = code
37
+ @error_messages = [message]
38
+ @all_messages = []
39
+ end
40
+ end
41
+ end
42
+
43
+ def reset!(message=nil)
44
+ unless @locked
45
+ @timestamp = Time.now
46
+ @status_code = OK
47
+ @error_messages = []
48
+ @all_messages = message.nil? ? [] : [message]
49
+ end
50
+ end
51
+
52
+ def escalate_status_code(code)
53
+ unless @locked
54
+ @timestamp = Time.now
55
+
56
+ if code >= @status_code
57
+ @status_code = code
58
+ end
59
+ end
60
+ end
61
+
62
+ def add_message(message)
63
+ unless @locked
64
+ @timestamp = Time.now
65
+ @all_messages << message
66
+ end
67
+ end
68
+
69
+ def add_error_message(message)
70
+ unless @locked
71
+ @timestamp = Time.now
72
+ @error_messages << message
73
+ # @all_messages << message
74
+ end
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,81 @@
1
+
2
+
3
+
4
+ module Deadpool
5
+
6
+ class StateSnapshot
7
+
8
+ def initialize(state)
9
+ @name = state.name
10
+ @timestamp = state.timestamp
11
+ @status_code = state.status_code
12
+ @all_messages = state.all_messages
13
+ @error_messages = state.error_messages
14
+ @children = []
15
+ end
16
+
17
+ def add_child(child)
18
+ @children << child
19
+ end
20
+
21
+ def overall_status
22
+ @children.map { |child| child.overall_status }.push(@status_code).max
23
+ end
24
+
25
+ def all_error_messages
26
+ @children.inject(@error_messages) do |arr, child|
27
+ arr + child.all_error_messages
28
+ end
29
+ end
30
+
31
+ def nagios_report
32
+ message = ''
33
+ if overall_status != OK
34
+ message += all_error_messages.join(' | ')
35
+ end
36
+
37
+ message += " last checked #{(Time.now - @timestamp).round} seconds ago."
38
+
39
+ "#{status_code_to_s(overall_status)} - #{message}\n"
40
+ end
41
+
42
+ def full_report
43
+ output = "System Status: #{status_code_to_s(overall_status)}\n\n"
44
+ output += self.to_s
45
+
46
+ return output
47
+ end
48
+
49
+ def to_s(indent=0)
50
+ indent_space = ' ' * indent
51
+
52
+ output = "#{indent_space}#{@name}\n"
53
+ output += "#{indent_space}#{status_code_to_s(@status_code)} - checked #{(Time.now - @timestamp).round} seconds ago.\n"
54
+ unless @error_messages.empty?
55
+ output += "#{indent_space}!!! #{@error_messages.join("\n#{indent_space}!!! ")}\n"
56
+ end
57
+ unless @all_messages.empty?
58
+ output += "#{indent_space}#{@all_messages.join("\n#{indent_space}")}\n"
59
+ end
60
+ output += "\n"
61
+
62
+ @children.each do |child|
63
+ output += child.to_s(indent+1)
64
+ end
65
+
66
+ return output
67
+ end
68
+
69
+ def status_code_to_s(code)
70
+ case code
71
+ when OK then 'OK'
72
+ when WARNING then 'WARNING'
73
+ when CRITICAL then 'CRITICAL'
74
+ else
75
+ 'UNKNOWN'
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ end