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