class SSHake::Session
Attributes
host[R]
Return the host to connect to
@return [String]
session[R]
The underlying net/ssh session
@return [Net::SSH::Session]
Public Class Methods
create(*args)
click to toggle source
# File lib/sshake/session.rb, line 195 def create(*args) session = new(*args) if recorder = Thread.current[:sshake_recorder] return RecordedSession.new(recorder, session) end session end
new(host, username_or_options = {}, options_with_username = {})
click to toggle source
Create a new SSH session
@return [Sshake::Session]
Calls superclass method
SSHake::BaseSession::new
# File lib/sshake/session.rb, line 26 def initialize(host, username_or_options = {}, options_with_username = {}) super @host = host if username_or_options.is_a?(String) @user = username_or_options @session_options = options_with_username else @user = username_or_options.delete(:user) @session_options = username_or_options end end
Public Instance Methods
connect()
click to toggle source
Connect to the SSH server
@return [void]
# File lib/sshake/session.rb, line 55 def connect log :debug, "Creating connection to #{@host}" log :debug, "Session options: #{@session_options.inspect}" @session = Net::SSH.start(@host, user, @session_options) true end
connected?()
click to toggle source
Is there an established SSH connection
@return [Boolean]
# File lib/sshake/session.rb, line 65 def connected? !@session.nil? end
disconnect()
click to toggle source
Disconnect the underlying SSH connection
@return [void]
# File lib/sshake/session.rb, line 72 def disconnect return false if @session.nil? begin log :debug, 'Closing connectiong' @session.close log :debug, 'Connection closed successfully' rescue StandardError => e log :debug, "Connection not closed: #{e.message} (#{e.class})" nil end @session = nil true end
execute(commands, options = nil, &block)
click to toggle source
# File lib/sshake/session.rb, line 95 def execute(commands, options = nil, &block) options = create_options(options, block) command_to_execute = prepare_commands(commands, options) # Execute the command response = Response.new response.command = command_to_execute connect unless connected? # Log the command log :info, "Executing: #{command_to_execute}" log :debug, "Timeout: #{options.timeout}" begin channel = nil Timeout.timeout(options.timeout) do channel = @session.open_channel do |ch| response.start_time = Time.now channel.exec(command_to_execute) do |_, success| raise "Command \"#{command_to_execute}\" was unable to execute" unless success ch.send_data(options.stdin) if options.stdin if options.file_to_stream.nil? && options.sudo_password.nil? log :debug, 'Sending EOF to channel' ch.eof! end ch.on_data do |_, data| response.stdout += data options.stdout&.call(data) log :debug, data.gsub(/\r/, '') end ch.on_extended_data do |_, _, data| response.stderr += data.delete("\r") options.stderr&.call(data) log :debug, data if options.sudo_password && data =~ /^\[sshake-sudo-password\]:\s\z/ log :debug, 'Sending sudo password' ch.send_data "#{options.sudo_password}\n" if options.file_to_stream.nil? log :debug, 'Sending EOF after sudo password because no file' ch.eof! end end end ch.on_request('exit-status') do |_, data| response.exit_code = data.read_long&.to_i log :debug, "Exit code: #{response.exit_code}" end ch.on_request('exit-signal') do |_, data| response.exit_signal = data.read_long end if options.file_to_stream ch.on_process do |_, data| next if ch.eof? if ch.output.length < 128 * 1024 if data = options.file_to_stream.read(1024 * 1024) ch.send_data(data) response.bytes_streamed += data.bytesize else ch.eof! end end end end end end channel.wait end rescue Timeout::Error log :debug, 'Got timeout error while executing command' kill! response.timeout! ensure response.finish_time = Time.now end handle_response(response, options) end
kill!()
click to toggle source
Kill the underlying connection
# File lib/sshake/session.rb, line 88 def kill! log :debug, 'Attempting kill/shutdown of session' @session.shutdown! log :debug, 'Session shutdown success' @session = nil end
port()
click to toggle source
Return the port that will be connected to
@return [Integer]
# File lib/sshake/session.rb, line 48 def port @session_options[:port] || 22 end
user()
click to toggle source
Return the username for the connection
@return [String]
# File lib/sshake/session.rb, line 41 def user @user || ENV['USER'] end
write_data(path, data, options = nil, &block)
click to toggle source
# File lib/sshake/session.rb, line 182 def write_data(path, data, options = nil, &block) connect unless connected? tmp_path = "/tmp/sshake-tmp-file-#{SecureRandom.hex(32)}" @session.sftp.file.open(tmp_path, 'w') do |f| d = data.dup.force_encoding('BINARY') f.write(d.slice!(0, 1024)) until d.empty? end response = execute("mv #{tmp_path} #{path}", options, &block) response.success? end