lib/chef_metal/transport/ssh.rb in chef-metal-0.10.2 vs lib/chef_metal/transport/ssh.rb in chef-metal-0.11.beta
- old
+ new
@@ -1,26 +1,29 @@
require 'chef_metal/transport'
require 'uri'
require 'socket'
require 'timeout'
+require 'net/ssh'
+require 'net/scp'
+require 'net/ssh/gateway'
module ChefMetal
class Transport
class SSH < ChefMetal::Transport
- def initialize(host, username, ssh_options, options)
- require 'net/ssh'
- require 'net/scp'
+ def initialize(host, username, ssh_options, options, global_config)
@host = host
@username = username
@ssh_options = ssh_options
@options = options
+ @config = global_config
end
attr_reader :host
attr_reader :username
attr_reader :ssh_options
attr_reader :options
+ attr_reader :config
def execute(command, execute_options = {})
Chef::Log.info("Executing #{options[:prefix]}#{command} on #{username}@#{host}")
stdout = ''
stderr = ''
@@ -56,12 +59,12 @@
channel.wait
end
Chef::Log.info("Completed #{command} on #{username}@#{host}: exit status #{exitstatus}")
- Chef::Log.debug("Stdout was:\n#{stdout}") if stdout != '' && !options[:stream] && !options[:stream_stdout] && Chef::Config.log_level != :debug
- Chef::Log.info("Stderr was:\n#{stderr}") if stderr != '' && !options[:stream] && !options[:stream_stderr] && Chef::Config.log_level != :debug
+ Chef::Log.debug("Stdout was:\n#{stdout}") if stdout != '' && !options[:stream] && !options[:stream_stdout] && config[:log_level] != :debug
+ Chef::Log.info("Stderr was:\n#{stderr}") if stderr != '' && !options[:stream] && !options[:stream_stderr] && config[:log_level] != :debug
SSHResult.new(command, execute_options, stdout, stderr, exitstatus)
end
def read_file(path)
Chef::Log.debug("Reading file #{path} from #{username}@#{host}")
@@ -129,23 +132,53 @@
def available?
# If you can't pwd within 10 seconds, you can't pwd
execute('pwd', :timeout => 10)
true
- rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET, Net::SSH::AuthenticationFailed, Net::SSH::Disconnect, Net::SSH::HostKeyMismatch
- Chef::Log.debug("#{username}@#{host} unavailable: could not execute 'pwd' on #{host}: #{$!.inspect}")
+ rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET, Net::SSH::Disconnect
+ Chef::Log.debug("#{username}@#{host} unavailable: network connection failed or broke: #{$!.inspect}")
false
+ rescue Net::SSH::AuthenticationFailed, Net::SSH::HostKeyMismatch
+ Chef::Log.debug("#{username}@#{host} unavailable: SSH authentication error: #{$!.inspect} ")
+ false
end
protected
+ def gateway?
+ options.key?(:ssh_gateway) and ! options[:ssh_gateway].nil?
+ end
+
+ def gateway
+ @gateway ||= begin
+ gw_host, gw_user = options[:ssh_gateway].split('@').reverse
+ gw_host, gw_port = gw_host.split(':')
+ gw_user = ssh_options[:ssh_username] unless gw_user
+
+ ssh_start_opts = { timeout:10 }.merge(ssh_options)
+ ssh_start_opts[:port] = gw_port || 22
+
+ Chef::Log.debug("Opening SSH gateway to #{gw_user}@#{gw_host} with options #{ssh_start_opts.inspect}")
+ begin
+ Net::SSH::Gateway.new(gw_host, gw_user)
+ rescue Errno::ETIMEDOUT
+ Chef::Log.debug("Timed out connecting to gateway: #{$!}")
+ raise InitialConnectTimeout.new($!)
+ end
+ end
+ end
+
def session
@session ||= begin
- Chef::Log.debug("Opening SSH connection to #{username}@#{host} with options #{ssh_options.inspect}")
+ ssh_start_opts = { timeout:10 }.merge(ssh_options)
+ Chef::Log.debug("Opening SSH connection to #{username}@#{host} with options #{ssh_start_opts.inspect}")
# Small initial connection timeout (10s) to help us fail faster when server is just dead
begin
- Net::SSH.start(host, username, { :timeout => 10 }.merge(ssh_options))
+ if gateway? then gateway.ssh(host, username, ssh_start_opts)
+ else Net::SSH.start(host, username, ssh_start_opts)
+ end
rescue Timeout::Error
+ Chef::Log.debug("Timed out connecting to SSH: #{$!}")
raise InitialConnectTimeout.new($!)
end
end
end