mirror of
https://github.com/inspec/inspec
synced 2024-12-21 02:23:13 +00:00
6d7a46a589
PTY will effectively disable stderr output, so avoid it for now. It will come up very soon when we get back to sudo; see if fifo or other solutions might be used. Stderr is important for accurate command execution... For reference see this wonderful explanation: http://unix.stackexchange.com/a/134169 Signed-off-by: Dominik Richter <dominik.richter@gmail.com>
105 lines
2.6 KiB
Ruby
105 lines
2.6 KiB
Ruby
# encoding: utf-8
|
|
|
|
module Vulcano::Backends
|
|
class SSH < Vulcano.backend(1)
|
|
name 'ssh'
|
|
|
|
attr_reader :os
|
|
def initialize(conf)
|
|
@conf = conf
|
|
@files = {}
|
|
@conf['host'] ||
|
|
fail('You must specify a SSH host.')
|
|
@ssh = start_ssh
|
|
@os = OS.new(self)
|
|
end
|
|
|
|
def file(path)
|
|
@files[path] ||= LinuxFile.new(self, path)
|
|
end
|
|
|
|
def run_command(cmd)
|
|
stdout = stderr = ''
|
|
exit_status = nil
|
|
cmd.force_encoding('binary') if cmd.respond_to?(:force_encoding)
|
|
|
|
@ssh.open_channel do |channel|
|
|
channel.exec(cmd) do |_, success|
|
|
unless success
|
|
abort 'Couldn\'t execute command on SSH.'
|
|
end
|
|
|
|
channel.on_data do |_, data|
|
|
stdout += data
|
|
end
|
|
|
|
channel.on_extended_data do |_, _type, data|
|
|
stderr += data
|
|
end
|
|
|
|
channel.on_request('exit-status') do |_, data|
|
|
exit_status = data.read_long
|
|
end
|
|
|
|
channel.on_request('exit-signal') do |_, data|
|
|
exit_status = data.read_long
|
|
end
|
|
end
|
|
end
|
|
@ssh.loop
|
|
|
|
CommandResult.new(stdout, stderr, exit_status)
|
|
end
|
|
|
|
private
|
|
|
|
def validate_options(options)
|
|
if options[:keys].empty? and options[:password].nil?
|
|
fail 'You must configure at least one authentication method for SSH:'\
|
|
' Password or key.'
|
|
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
|
|
|
|
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,
|
|
keepalive: true,
|
|
keepalive_interval: 60,
|
|
compression: true,
|
|
compression_level: 6,
|
|
password: @conf['password'] || ssh_config[:password],
|
|
keys: keys,
|
|
}
|
|
|
|
validate_options(options)
|
|
Net::SSH.start(host, user, options)
|
|
end
|
|
|
|
class OS < OSCommon
|
|
def initialize(backend)
|
|
super(backend, { family: 'unix' })
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|