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
|