Как правильно закрыть соединение Net::SSH?

Многие статьи демонстрируют Net::SSH с помощью блока, например следующего:

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

Однако на самом деле я использую его в классе Ruby и вызываю из различных других функций и методов в своем приложении. Например, у меня есть класс SSHCommand, который делает следующее:

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 => "[email protected]",
            :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

и чтобы выполнить команду через SSH-соединение, я просто запускаю следующее:

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

Как мне на самом деле завершить этот сеанс SSH? Я заметил, что когда мои рабочие процессы Sidekiq в Ruby on Rails завершены, я получаю следующее сообщение:

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

Причина, по которой я избегал использования блока, заключается в том, что я хотел, чтобы несколько команд, отправленных моим воркером, выполнялись через уже установленное соединение SSH.

Я использую это не так, как предполагалось, или есть реальный способ закрыть это соединение, когда я выполню свои задачи?


person LewlSauce    schedule 29.06.2020    source источник
comment
Вы также можете переписать свой инициализатор, чтобы использовать блок, например. SSHCommand.new { |ssh| ssh.execute("ifconfig") ... }   -  person Stefan    schedule 29.06.2020
comment
Нет ли способа закрыть его так, как написано?   -  person LewlSauce    schedule 29.06.2020
comment
Ну, ваш класс SSHCommand не знает, когда рабочий закончит отправлять команды, не так ли? Обернуть рабочий код в блок — это самый простой способ, который я могу придумать. Другой подход заключается в использовании ObjectSpace.define_finalizer, но простого блока на мой взгляд намного чище.   -  person Stefan    schedule 29.06.2020
comment
Попался. Имеет смысл. Я признателен за это!   -  person LewlSauce    schedule 29.06.2020


Ответы (1)


Если вы запустите соединение SSH без блока, вы получите Net::SSH::Connection::Session, на котором вы должны в конечном итоге вызвать close.

Вот Net ::Демонстрационная программа SSH, а также несколько изображений и ссылок на интерактивные визуализации того, как работает Net::SSH в целом, включая close.

person kgilpin    schedule 01.07.2020