2015-09-08 22:28:06 +00:00
|
|
|
# encoding: utf-8
|
|
|
|
|
|
|
|
module Vulcano::Backends
|
|
|
|
class SSH < Vulcano.backend(1)
|
|
|
|
name 'ssh'
|
|
|
|
|
|
|
|
def initialize(conf)
|
|
|
|
@conf = conf
|
|
|
|
@files = {}
|
|
|
|
@conf['host'] ||
|
|
|
|
fail("You must specify a SSH host.")
|
|
|
|
@ssh = start_ssh
|
|
|
|
end
|
|
|
|
|
|
|
|
def file(path)
|
|
|
|
@files[path] ||= LinuxFile.new(self, path)
|
|
|
|
end
|
|
|
|
|
|
|
|
def run_command(cmd)
|
2015-09-08 22:45:33 +00:00
|
|
|
stdout = stderr = ''
|
|
|
|
exit_status = nil
|
2015-09-09 06:52:55 +00:00
|
|
|
cmd.force_encoding('binary') if cmd.respond_to?(:force_encoding)
|
2015-09-08 22:45:33 +00:00
|
|
|
|
|
|
|
@ssh.open_channel do |channel|
|
2015-09-09 06:52:55 +00:00
|
|
|
channel.request_pty do |ch, success|
|
|
|
|
abort 'Could not obtain pty on SSH channel ' if !success
|
|
|
|
end
|
2015-09-08 22:45:33 +00:00
|
|
|
channel.exec(cmd) do |ch, success|
|
|
|
|
unless success
|
2015-09-09 06:52:55 +00:00
|
|
|
abort 'Couldn\'t execute command on SSH.'
|
2015-09-08 22:45:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
channel.on_data do |ch,data|
|
|
|
|
stdout += data
|
|
|
|
end
|
|
|
|
|
|
|
|
channel.on_extended_data do |ch,type,data|
|
|
|
|
stderr += data
|
|
|
|
end
|
|
|
|
|
|
|
|
channel.on_request("exit-status") do |ch,data|
|
|
|
|
exit_status = data.read_long
|
|
|
|
end
|
|
|
|
|
|
|
|
channel.on_request("exit-signal") do |ch, data|
|
|
|
|
exit_status = data.read_long
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
@ssh.loop
|
|
|
|
|
|
|
|
CommandResult.new(stdout, stderr, exit_status)
|
2015-09-08 22:28:06 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def start_ssh
|
|
|
|
host = @conf['host']
|
|
|
|
ssh_config = Net::SSH.configuration_for(host)
|
|
|
|
|
|
|
|
user = @conf['user'] || ssh_config[:user]
|
|
|
|
keys = [ @conf['key_file'], ssh_config[:keys] ].flatten.compact
|
|
|
|
options = {
|
|
|
|
port: @conf['port'] || ssh_config[:port] || 22,
|
|
|
|
auth_methods: ['none'],
|
|
|
|
user_known_hosts_file: '/dev/null',
|
|
|
|
global_known_hosts_file: '/dev/null',
|
|
|
|
number_of_password_prompts: 0,
|
|
|
|
password: @conf['password'] || ssh_config[:password],
|
|
|
|
keys: keys,
|
|
|
|
}
|
|
|
|
|
|
|
|
unless options[:keys].empty?
|
|
|
|
options[:auth_methods].push('publickey')
|
|
|
|
options[:keys_only] = true if options[:password].nil?
|
|
|
|
end
|
|
|
|
|
|
|
|
unless options[:password].nil?
|
|
|
|
options[:auth_methods].push('password')
|
|
|
|
end
|
|
|
|
|
|
|
|
if options[:keys].empty? and options[:password].nil?
|
|
|
|
fail('You must configure at least one authentication method for SSH:' +
|
|
|
|
' Password or key.')
|
|
|
|
end
|
|
|
|
|
|
|
|
Net::SSH.start( host, user, options )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|