2015-09-08 22:28:06 +00:00
|
|
|
# encoding: utf-8
|
2015-10-06 16:55:44 +00:00
|
|
|
# author: Dominik Richter
|
|
|
|
# author: Christoph Hartmann
|
2015-09-08 22:28:06 +00:00
|
|
|
|
|
|
|
module Vulcano::Backends
|
|
|
|
class SSH < Vulcano.backend(1)
|
|
|
|
name 'ssh'
|
|
|
|
|
2015-09-25 10:31:51 +00:00
|
|
|
attr_reader :os
|
2015-09-08 22:28:06 +00:00
|
|
|
def initialize(conf)
|
|
|
|
@conf = conf
|
|
|
|
@files = {}
|
|
|
|
@conf['host'] ||
|
2015-09-09 07:03:43 +00:00
|
|
|
fail('You must specify a SSH host.')
|
2015-09-08 22:28:06 +00:00
|
|
|
@ssh = start_ssh
|
2015-09-25 10:31:51 +00:00
|
|
|
@os = OS.new(self)
|
2015-09-08 22:28:06 +00:00
|
|
|
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 07:03:43 +00:00
|
|
|
channel.exec(cmd) do |_, success|
|
2015-09-08 22:45:33 +00:00
|
|
|
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
|
|
|
|
|
2015-09-09 07:03:43 +00:00
|
|
|
channel.on_data do |_, data|
|
2015-09-08 22:45:33 +00:00
|
|
|
stdout += data
|
|
|
|
end
|
|
|
|
|
2015-09-09 07:03:43 +00:00
|
|
|
channel.on_extended_data do |_, _type, data|
|
2015-09-08 22:45:33 +00:00
|
|
|
stderr += data
|
|
|
|
end
|
|
|
|
|
2015-09-09 07:03:43 +00:00
|
|
|
channel.on_request('exit-status') do |_, data|
|
2015-09-08 22:45:33 +00:00
|
|
|
exit_status = data.read_long
|
|
|
|
end
|
|
|
|
|
2015-09-09 07:03:43 +00:00
|
|
|
channel.on_request('exit-signal') do |_, data|
|
2015-09-08 22:45:33 +00:00
|
|
|
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
|
|
|
|
|
2015-09-09 07:03:43 +00:00
|
|
|
def validate_options(options)
|
|
|
|
if options[:keys].empty? and options[:password].nil?
|
2015-09-09 08:08:54 +00:00
|
|
|
fail 'You must configure at least one authentication method for SSH:'\
|
|
|
|
' Password or key.'
|
2015-09-09 07:03:43 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
unless options[:keys].empty?
|
|
|
|
options[:auth_methods].push('publickey')
|
|
|
|
options[:keys_only] = true if options[:password].nil?
|
|
|
|
end
|
|
|
|
|
|
|
|
# rubocop:disable Style/GuardClause
|
|
|
|
unless options[:password].nil?
|
|
|
|
options[:auth_methods].push('password')
|
|
|
|
end
|
|
|
|
# rubocop:enable Style/GuardClause
|
|
|
|
end
|
|
|
|
|
2015-09-08 22:28:06 +00:00
|
|
|
def start_ssh
|
|
|
|
host = @conf['host']
|
|
|
|
ssh_config = Net::SSH.configuration_for(host)
|
|
|
|
|
|
|
|
user = @conf['user'] || ssh_config[:user]
|
2015-09-09 07:03:43 +00:00
|
|
|
keys = [@conf['key_file'], ssh_config[:keys]].flatten.compact
|
2015-09-08 22:28:06 +00:00
|
|
|
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,
|
2015-09-25 10:30:59 +00:00
|
|
|
keepalive: true,
|
|
|
|
keepalive_interval: 60,
|
|
|
|
compression: true,
|
|
|
|
compression_level: 6,
|
2015-09-08 22:28:06 +00:00
|
|
|
password: @conf['password'] || ssh_config[:password],
|
|
|
|
keys: keys,
|
|
|
|
}
|
|
|
|
|
2015-09-09 07:03:43 +00:00
|
|
|
validate_options(options)
|
|
|
|
Net::SSH.start(host, user, options)
|
2015-09-08 22:28:06 +00:00
|
|
|
end
|
2015-09-25 10:31:51 +00:00
|
|
|
|
|
|
|
class OS < OSCommon
|
|
|
|
def initialize(backend)
|
|
|
|
super(backend, { family: 'unix' })
|
|
|
|
end
|
|
|
|
end
|
2015-09-08 22:28:06 +00:00
|
|
|
end
|
|
|
|
end
|