ruby-on-railsrubysshnet-ssh

How to properly close a Net::SSH connection?


Many articles demonstrate Net::SSH by using a block, such as the following:

Net::SSH.start("host", "user") do |ssh|
  ssh.exec! "cp /some/file /another/location"
  hostname = ssh.exec!("hostname")

  ssh.open_channel do |ch|
    ch.exec "sudo -p 'sudo password: ' ls" do |ch, success|
      abort "could not execute sudo ls" unless success

      ch.on_data do |ch, data|
        print data
        if data =~ /sudo password: /
          ch.send_data("password\n")
        end
      end
    end
  end

  ssh.loop
end

However, I am actually using it in a Ruby class and calling it from various other functions and methods within my application. For example, I have an SSHCommand class that does the following:

class SSHCommand
    def initialize
        ...
        @ssh = establish_ssh
        ...
    end

    def establish_ssh
        ssh = Net::SSH.start(
            @ip, 'root',
            :host_key => 'ssh-rsa',
            :encryption => 'aes256-ctr',
            :keys => [@key],
            :compression => "zlib@openssh.com",
            :port => @port
        )
        return ssh
    end
    def execute(command)
        results = String.new
        results = run_cmd(command)
        if results.include? "no matches found"
            results = ""
        end
        return results
    end
end

and to execute a command over an SSH connection, I just simply run the following:

ssh = SSHCommand.new
ssh.execute("ifconfig")

How do I actually terminate this SSH session? I noticed that when my Sidekiq workers in Ruby on Rails are completed, I get the following message:

zlib(finalizer): the stream was freed prematurely.
zlib(finalizer): the stream was freed prematurely.

The reason I avoided using a block is because I wanted to have multiple commands sent from my worker to be executed via an already-established SSH connection.

Am I not using this the way it's intended, or is there an actual way to close this connection when I've completed my tasks?


Solution

  • If you start an SSH connection without a block, you'll get a Net::SSH::Connection::Session, on which you should eventually call close.

    Here is a Net::SSH demonstration program, plus some images and links to interactive visualizations of how Net::SSH works overall, including close.