lib/kitchen/transport/ssh.rb in test-kitchen-1.19.2 vs lib/kitchen/transport/ssh.rb in test-kitchen-1.20.0

- old
+ new

@@ -16,12 +16,14 @@ # See the License for the specific language governing permissions and # limitations under the License. require "kitchen" +require "fileutils" require "net/ssh" require "net/ssh/gateway" +require "net/ssh/proxy/http" require "net/scp" require "timeout" require "benchmark" module Kitchen @@ -52,10 +54,15 @@ default_config :max_wait_until_ready, 600 default_config :ssh_gateway, nil default_config :ssh_gateway_username, nil + default_config :ssh_http_proxy, nil + default_config :ssh_http_proxy_port, nil + default_config :ssh_http_proxy_user, nil + default_config :ssh_http_proxy_password, nil + default_config :ssh_key, nil expand_path_for :ssh_key # compression disabled by default for speed default_config :compression, false @@ -179,10 +186,34 @@ logger.debug("TIMING: scp async upload (Kitchen::Transport::Ssh) took #{delta}") rescue Net::SSH::Exception => ex raise SshFailed, "SCP upload failed (#{ex.message})" end + # (see Base::Connection#download) + def download(remotes, local) + # ensure the parent dir of the local target exists + FileUtils.mkdir_p(File.dirname(local)) + + Array(remotes).each do |file| + begin + logger.debug("Attempting to download '#{file}' as file") + session.scp.download!(file, local) + rescue Net::SCP::Error + begin + logger.debug("Attempting to download '#{file}' as directory") + session.scp.download!(file, local, recursive: true) + rescue Net::SCP::Error + logger.warn( + "SCP download failed for file or directory '#{file}', perhaps it does not exist?" + ) + end + end + end + rescue Net::SSH::Exception => ex + raise SshFailed, "SCP download failed (#{ex.message})" + end + # (see Base::Connection#wait_until_ready) def wait_until_ready delay = 3 session( retries: max_wait_until_ready / delay, @@ -244,10 +275,30 @@ # @return [String] The username to use when using an ssh gateway # @api private attr_reader :ssh_gateway_username + # @return [String] The kitchen ssh proxy to use when connecting to the + # remote SSH host via http proxy + # @api private + attr_reader :ssh_http_proxy + + # @return [Integer] The port to use when using an kitchen ssh proxy + # remote SSH host via http proxy + # @api private + attr_reader :ssh_http_proxy_port + + # @return [String] The username to use when using an kitchen ssh proxy + # remote SSH host via http proxy + # @api private + attr_reader :ssh_http_proxy_user + + # @return [String] The password to use when using an kitchen ssh proxy + # remote SSH host via http proxy + # @api private + attr_reader :ssh_http_proxy_password + # Establish an SSH session on the remote host using a gateway host. # # @param opts [Hash] retry options # @option opts [Integer] :retries the number of times to retry before # failing @@ -344,19 +395,23 @@ end # (see Base::Connection#init_options) def init_options(options) super - @username = @options.delete(:username) - @hostname = @options.delete(:hostname) - @port = @options[:port] # don't delete from options - @connection_retries = @options.delete(:connection_retries) - @connection_retry_sleep = @options.delete(:connection_retry_sleep) - @max_ssh_sessions = @options.delete(:max_ssh_sessions) - @max_wait_until_ready = @options.delete(:max_wait_until_ready) - @ssh_gateway = @options.delete(:ssh_gateway) - @ssh_gateway_username = @options.delete(:ssh_gateway_username) + @username = @options.delete(:username) + @hostname = @options.delete(:hostname) + @port = @options[:port] # don't delete from options + @connection_retries = @options.delete(:connection_retries) + @connection_retry_sleep = @options.delete(:connection_retry_sleep) + @max_ssh_sessions = @options.delete(:max_ssh_sessions) + @max_wait_until_ready = @options.delete(:max_wait_until_ready) + @ssh_gateway = @options.delete(:ssh_gateway) + @ssh_gateway_username = @options.delete(:ssh_gateway_username) + @ssh_http_proxy = @options.delete(:ssh_http_proxy) + @ssh_http_proxy_user = @options.delete(:ssh_http_proxy_user) + @ssh_http_proxy_password = @options.delete(:ssh_http_proxy_password) + @ssh_http_proxy_port = @options.delete(:ssh_http_proxy_port) end # Returns a connection session, or establishes one when invoked the # first time. # @@ -417,9 +472,16 @@ if data[:ssh_key] && !data[:password] opts[:keys_only] = true opts[:keys] = Array(data[:ssh_key]) opts[:auth_methods] = ["publickey"] + end + + if data[:ssh_http_proxy] + options_http_proxy = {} + options_http_proxy[:user] = data[:ssh_http_proxy_user] + options_http_proxy[:password] = data[:ssh_http_proxy_password] + opts[:proxy] = Net::SSH::Proxy::HTTP.new(data[:ssh_http_proxy], data[:ssh_http_proxy_port], options_http_proxy) end if data[:ssh_key_only] opts[:auth_methods] = ["publickey"] end