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
data/bin/deadpool_admin
ADDED
data/bin/deadpool_hosts
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'strscan'
|
6
|
+
|
7
|
+
class DeadpoolHosts
|
8
|
+
|
9
|
+
def run
|
10
|
+
@options = self.parse_command_line
|
11
|
+
self.execute_command(@options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_command_line
|
15
|
+
options = OpenStruct.new
|
16
|
+
options.command_count = 0
|
17
|
+
|
18
|
+
@option_parser = OptionParser.new do |opts|
|
19
|
+
opts.banner = "Usage: deadpool_hosts {help|test|verify|switch} [options]"
|
20
|
+
|
21
|
+
opts.separator "Commands:"
|
22
|
+
opts.on("-h", "--help", "Print this help message.") do |h|
|
23
|
+
options.help = h
|
24
|
+
options.command_count += 1
|
25
|
+
options.command = :help
|
26
|
+
end
|
27
|
+
opts.on("--test", "Test that /etc/hosts can be touched.") do |t|
|
28
|
+
options.test = t
|
29
|
+
options.command_count += 1
|
30
|
+
options.command = :test
|
31
|
+
end
|
32
|
+
opts.on("--verify", "Verify that /etc/hosts hast the IP address that you think it should.") do |v|
|
33
|
+
options.verify = v
|
34
|
+
options.command_count += 1
|
35
|
+
options.command = :verify
|
36
|
+
end
|
37
|
+
opts.on("--switch", "Change the IP address in /etc/hosts") do |s|
|
38
|
+
options.switch = s
|
39
|
+
options.command_count += 1
|
40
|
+
options.command = :switch
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.separator "Options:"
|
44
|
+
opts.on("--host_name=HOSTNAME", String, "Hostname to regex on in /etc/hosts") do |h|
|
45
|
+
options.host_name = h
|
46
|
+
end
|
47
|
+
opts.on("--ip_address=IP_ADDRESS", String, "IP Address") do |ip|
|
48
|
+
options.ip_address = ip
|
49
|
+
end
|
50
|
+
opts.on("--hosts_file=HOST_FILE_PATH", String, "Alternate Path for the Hosts file") do |hosts|
|
51
|
+
options.hosts_file = hosts
|
52
|
+
end
|
53
|
+
opts.on("--verbose", "Verbose Messages.") do |v|
|
54
|
+
options.verbose = v
|
55
|
+
end
|
56
|
+
opts.on("--debug", "Creates a dummy hosts file at /tmp/hosts and operates on that. Overrides the alternate hosts file option.") do |d|
|
57
|
+
options.debug = d
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Parse and verify
|
62
|
+
remaining_arguments = @option_parser.parse!
|
63
|
+
|
64
|
+
unless remaining_arguments.empty?
|
65
|
+
help "[#{remaining_arguments.join(' ')}] is not understood."
|
66
|
+
end
|
67
|
+
|
68
|
+
if options.command_count == 0
|
69
|
+
help "You must specify a command."
|
70
|
+
end
|
71
|
+
|
72
|
+
option_sum = (options.help ? 1 : 0) + (options.test ? 1 : 0) + (options.verify ? 1 : 0) + (options.switch ? 1 : 0)
|
73
|
+
if option_sum > 1
|
74
|
+
help "Only one command can be specified."
|
75
|
+
end
|
76
|
+
|
77
|
+
if options.verify
|
78
|
+
options_valid = true
|
79
|
+
|
80
|
+
if options.ip_address.nil?
|
81
|
+
puts "The verify command requires an ip_address argument."
|
82
|
+
options_valid = false
|
83
|
+
elsif ! options.ip_address.match(/\d+\.\d+\.\d+\.\d+/)
|
84
|
+
puts "ip_address doesn't look valid."
|
85
|
+
options_valid = false
|
86
|
+
end
|
87
|
+
|
88
|
+
if options.host_name.nil?
|
89
|
+
puts "The verify command requires a host_name argument."
|
90
|
+
options_valid = false
|
91
|
+
elsif options.host_name.size < 4
|
92
|
+
puts "The host_name parameter must be longer than 4 characters."
|
93
|
+
options_valid = false
|
94
|
+
end
|
95
|
+
|
96
|
+
unless options_valid
|
97
|
+
help
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
return options
|
103
|
+
end
|
104
|
+
|
105
|
+
def execute_command(options)
|
106
|
+
case options.command
|
107
|
+
when :help
|
108
|
+
help
|
109
|
+
when :test
|
110
|
+
test options
|
111
|
+
when :verify
|
112
|
+
verify options
|
113
|
+
when :switch
|
114
|
+
switch options
|
115
|
+
else
|
116
|
+
help
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def help(message=nil)
|
121
|
+
unless message.nil?
|
122
|
+
puts message
|
123
|
+
end
|
124
|
+
puts @option_parser.help
|
125
|
+
exit 4
|
126
|
+
end
|
127
|
+
|
128
|
+
def test(options)
|
129
|
+
path = host_file_path(options)
|
130
|
+
out = `touch #{path} 2> /dev/null`
|
131
|
+
|
132
|
+
if $? == 0
|
133
|
+
puts "OK - #{path} is writable"
|
134
|
+
exit 0
|
135
|
+
else
|
136
|
+
puts "ERROR - #{path} is NOT writable"
|
137
|
+
exit 1
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def verify(options)
|
142
|
+
scanner = StringScanner.new File.read(host_file_path(options))
|
143
|
+
verified = scanner.exist?(/#{options.ip_address}\s+#{options.host_name}\s+/)
|
144
|
+
|
145
|
+
if verified
|
146
|
+
puts "OK - #{options.host_name} was verified to point at #{options.ip_address}"
|
147
|
+
exit 0
|
148
|
+
else
|
149
|
+
puts "ERROR - #{options.host_name} does not point at #{options.ip_address}"
|
150
|
+
exit 1
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def switch(options)
|
155
|
+
path = host_file_path(options)
|
156
|
+
scanner = StringScanner.new File.read(path)
|
157
|
+
host_exists = scanner.exist?(/\s+#{options.host_name}\s+/)
|
158
|
+
|
159
|
+
if host_exists
|
160
|
+
scanner.reset
|
161
|
+
scanner.scan_until(/\n.+#{options.host_name}\s*\n/)
|
162
|
+
pre_match = scanner.pre_match
|
163
|
+
matched = scanner.matched
|
164
|
+
post_match = scanner.post_match
|
165
|
+
verbose_message "\nPreceding lines: \n#{pre_match}"
|
166
|
+
verbose_message "\nMatched host definition: \n#{matched}"
|
167
|
+
verbose_message "\nFollowing lines: \n#{post_match}"
|
168
|
+
replacement_file = pre_match
|
169
|
+
replacement_file += "\n#{options.ip_address} #{options.host_name}\n"
|
170
|
+
replacement_file += post_match
|
171
|
+
verbose_message "Replacement hosts file:\n#{replacement_file}"
|
172
|
+
verbose_message "Writing hosts file..."
|
173
|
+
hosts_file = File.open path, 'w'
|
174
|
+
hosts_file.write replacement_file
|
175
|
+
hosts_file.close
|
176
|
+
puts "OK - Host definition replaced successfully."
|
177
|
+
exit 0
|
178
|
+
else
|
179
|
+
replacement_file = File.read(path)
|
180
|
+
replacement_file += "\n#{options.ip_address} #{options.host_name}\n"
|
181
|
+
verbose_message "Replacement hosts file:\n#{replacement_file}"
|
182
|
+
verbose_message "Writing hosts file..."
|
183
|
+
hosts_file = File.open path, 'w'
|
184
|
+
hosts_file.write replacement_file
|
185
|
+
hosts_file.close
|
186
|
+
puts "OK - Host definition added successfully."
|
187
|
+
exit 0
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def host_file_path(options)
|
192
|
+
if options.debug
|
193
|
+
file = File.open '/tmp/hosts', 'w'
|
194
|
+
file.write DATA.read
|
195
|
+
file.close
|
196
|
+
return '/tmp/hosts'
|
197
|
+
elsif options.hosts_file
|
198
|
+
return options.hosts_file
|
199
|
+
else
|
200
|
+
return '/etc/hosts'
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def verbose_message(message)
|
205
|
+
if @options.verbose
|
206
|
+
puts message
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
EtcHostsSwitch.new.run
|
213
|
+
|
214
|
+
__END__
|
215
|
+
127.0.0.1 localhost localhost.localdomain
|
216
|
+
184.106.205.117 web-01
|
217
|
+
|
218
|
+
123.456.78.9 test_host_name
|
219
|
+
123.456.78.9 other_service_that_shouldnt_be.touched
|
220
|
+
123.456.78.9 test_host_name.similar
|
221
|
+
|
222
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Deadpool Service
|
2
|
+
|
3
|
+
description "Deadpool Server"
|
4
|
+
author "Kirt Fitzpatrick <kirt.fitzpatrick@akqa.com>"
|
5
|
+
|
6
|
+
start on (net-device-up
|
7
|
+
and local-filesystems)
|
8
|
+
|
9
|
+
stop on runlevel [016]
|
10
|
+
|
11
|
+
respawn
|
12
|
+
|
13
|
+
# env HOME=/usr/local/bin/deadpool
|
14
|
+
env RUBY=/usr/local/bin/ruby
|
15
|
+
umask 007
|
16
|
+
|
17
|
+
exec $RUBY $HOME/bin/deadpool_admin --start
|
data/lib/deadpool.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'logger'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
$:.unshift File.dirname(__FILE__)
|
8
|
+
|
9
|
+
|
10
|
+
module Deadpool
|
11
|
+
OK = 0
|
12
|
+
WARNING = 1
|
13
|
+
CRITICAL = 2
|
14
|
+
UNKNOWN = 3
|
15
|
+
|
16
|
+
autoload :Admin, 'deadpool/admin'
|
17
|
+
autoload :AdminServer, 'deadpool/admin_server'
|
18
|
+
autoload :CommandLineServer, 'deadpool/command_line_server'
|
19
|
+
autoload :Daemonizer, 'deadpool/daemonizer'
|
20
|
+
autoload :Generator, 'deadpool/generator'
|
21
|
+
autoload :Handler, 'deadpool/handler'
|
22
|
+
autoload :Helper, 'deadpool/helper'
|
23
|
+
autoload :Options, 'deadpool/options'
|
24
|
+
autoload :State, 'deadpool/state'
|
25
|
+
autoload :StateSnapshot, 'deadpool/state_snapshot'
|
26
|
+
autoload :Server, 'deadpool/server'
|
27
|
+
|
28
|
+
|
29
|
+
module FailoverProtocol
|
30
|
+
autoload :Base, 'deadpool/failover_protocol'
|
31
|
+
end
|
32
|
+
|
33
|
+
module Monitor
|
34
|
+
autoload :Base, 'deadpool/monitor/base'
|
35
|
+
autoload :Mysql, 'deadpool/monitor/mysql'
|
36
|
+
autoload :GenericNagios, 'deadpool/monitor/generic_nagios'
|
37
|
+
end
|
38
|
+
|
39
|
+
module FailoverProtocol
|
40
|
+
autoload :EtcHosts, 'deadpool/failover_protocol/etc_hosts'
|
41
|
+
autoload :ExecRemoteCommand, 'deadpool/failover_protocol/exec_remote_command'
|
42
|
+
end
|
43
|
+
|
44
|
+
class DeadpoolError < StandardError; end
|
45
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
|
2
|
+
require 'optparse'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'strscan'
|
5
|
+
require 'socket'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
|
9
|
+
module Deadpool
|
10
|
+
|
11
|
+
class Admin
|
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 --command [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
|
+
opts.on("--start", "Start the server in the background.") do |stop|
|
54
|
+
options[:command_count] += 1
|
55
|
+
options[:command] = :start
|
56
|
+
end
|
57
|
+
opts.on("--foreground", "Start the server in the foreground.") do |stop|
|
58
|
+
options[:command_count] += 1
|
59
|
+
options[:command] = :foreground
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.separator "Options:"
|
63
|
+
opts.on("--server=SERVER_LABEL", String, "primary_host or secondary_host.") do |server|
|
64
|
+
options[:server] = server
|
65
|
+
end
|
66
|
+
opts.on("--pool=POOL_NAME", String, "Deadpool name to operate on.") do |pool|
|
67
|
+
options[:pool] = pool
|
68
|
+
end
|
69
|
+
opts.on("--config_path=PATH", String,
|
70
|
+
"Path to configs and custom plugins. #{options[:config_path]} by default.") do |config_path|
|
71
|
+
options[:config_path] = config_path
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
remaining_arguments = @option_parser.parse! @argv
|
76
|
+
|
77
|
+
unless remaining_arguments.empty?
|
78
|
+
help "[#{remaining_arguments.join(' ')}] is not understood."
|
79
|
+
end
|
80
|
+
|
81
|
+
if options[:command_count] == 0
|
82
|
+
help "You must specify a command."
|
83
|
+
end
|
84
|
+
|
85
|
+
return options
|
86
|
+
end
|
87
|
+
|
88
|
+
def execute_command(options)
|
89
|
+
case options[:command]
|
90
|
+
when :help
|
91
|
+
help
|
92
|
+
when :full_report
|
93
|
+
full_report options
|
94
|
+
when :nagios_report
|
95
|
+
nagios_report options
|
96
|
+
when :promote_server
|
97
|
+
promote_server options
|
98
|
+
when :stop
|
99
|
+
stop options
|
100
|
+
when :start
|
101
|
+
start options
|
102
|
+
when :foreground
|
103
|
+
foreground options
|
104
|
+
else
|
105
|
+
help
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def help(message=nil)
|
110
|
+
unless message.nil?
|
111
|
+
puts message
|
112
|
+
end
|
113
|
+
puts @option_parser.help
|
114
|
+
exit 4
|
115
|
+
end
|
116
|
+
|
117
|
+
def full_report(options)
|
118
|
+
puts send_command_to_deadpool_server :command => 'full_report'
|
119
|
+
end
|
120
|
+
|
121
|
+
def nagios_report(options)
|
122
|
+
response = send_command_to_deadpool_server :command => 'nagios_report'
|
123
|
+
|
124
|
+
if (response.to_s =~ /^OK/) != nil
|
125
|
+
puts response.to_s
|
126
|
+
exit OK
|
127
|
+
elsif (response.to_s =~ /^WARNING/) != nil
|
128
|
+
puts response.to_s
|
129
|
+
exit WARNING
|
130
|
+
elsif (response.to_s =~ /^CRITICAL/) != nil
|
131
|
+
puts response.to_s
|
132
|
+
exit CRITICAL
|
133
|
+
elsif (response.to_s =~ /^UNKNOWN/) != nil
|
134
|
+
puts response.to_s
|
135
|
+
exit UNKNOWN
|
136
|
+
else
|
137
|
+
puts "UNKNOWN - #{response.to_s}"
|
138
|
+
exit UNKNOWN
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def promote_server(options)
|
143
|
+
error_messages = []
|
144
|
+
|
145
|
+
if options[:pool].nil?
|
146
|
+
error_messages << "Promoting server requires --pool argument."
|
147
|
+
end
|
148
|
+
|
149
|
+
if options[:server].nil?
|
150
|
+
error_messages << "Promoting server requires --server argument."
|
151
|
+
end
|
152
|
+
|
153
|
+
unless error_messages.empty?
|
154
|
+
help error_messages.join "\n"
|
155
|
+
end
|
156
|
+
|
157
|
+
puts send_command_to_deadpool_server :command => 'promote_server', :pool => options[:pool], :server => options[:server]
|
158
|
+
end
|
159
|
+
|
160
|
+
def stop(options)
|
161
|
+
puts send_command_to_deadpool_server :command => 'stop'
|
162
|
+
end
|
163
|
+
|
164
|
+
def start(options)
|
165
|
+
puts Deadpool::Server.new(options).run(true)
|
166
|
+
end
|
167
|
+
|
168
|
+
def foreground(options)
|
169
|
+
puts Deadpool::Server.new(options).run(false)
|
170
|
+
end
|
171
|
+
|
172
|
+
def send_command_to_deadpool_server(options)
|
173
|
+
output = ''
|
174
|
+
|
175
|
+
begin
|
176
|
+
socket = TCPSocket.open(@config[:admin_hostname], @config[:admin_port])
|
177
|
+
rescue
|
178
|
+
return "Couldn't connect to deadpool server. Is it running?"
|
179
|
+
end
|
180
|
+
|
181
|
+
if socket
|
182
|
+
socket.puts JSON.dump(options)
|
183
|
+
while line = socket.gets
|
184
|
+
output += line
|
185
|
+
end
|
186
|
+
socket.close
|
187
|
+
else
|
188
|
+
return "Couldn't connect to deadpool server."
|
189
|
+
end
|
190
|
+
|
191
|
+
return output
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|