开发者

Respond to a SSH prompt before first command with ruby and Net::SSH

I'm trying to connect, using Net::SSH, to a server that immediately after login executes a script that requires input from user. The user has to enter "1" or "2" and will receive some data via in the terminal afterwards.

My problem is that, although I am able to connect, I can not figure out a way to send "1\n" to the server and to receive the output.

The following code stops at "INFO -- net.ssh.connection.session[80906b74]: channel_open_confirmation: 0 0 0 32768".

Using channel.exec( "1\n" ) instead of channel.send_data unsurprisingly do开发者_高级运维es not work either.

Net::SSH.start('host', 'user', :password => "pass", :auth_methods => ["password"], :verbose => :debug) do |session|

  session.open_channel do |channel|

    channel.on_data do |ch, data|
      STDOUT.print data
    end 

    channel.send_data( "1\n")

  end

  session.loop
end    

Any ideas, anyone?

Thanks in advance


Can you verify that your send_data call is happening after you get the prompt from the remote server? Try constructing a channel.on_data block around your send_data call so that you can verify that you get the expected prompt from the server before you send a response.

You might not want to be using exec here. From the docs for Net::SSH::Connection::Channel:

Sends a channel request asking that the given command be invoked.

You are wanting to send a text string to reply to a prompt, not invoke a command. The docs show exec being used to send full CLI commands like "ls -l /home".

Instead, send_data is probably what you want. The docs show it used to send arbitrary text such as channel.send_data("the password\n"). Note, however, this sentence in the docs:

Note that it does not immediately send the data across the channel, but instead merely appends the given data to the channel‘s output buffer, preparatory to being packaged up and sent out the next time the connection is accepting data.

You might want to take a look at channel.request_pty. It appears to be designed for interaction with a console-based application.

If you are trying to (in essence) script an SSH session that you would normally do manually, you may find it easier to use an expect-like interface (for example, a gem like sshExpect might be worth a try).


Thank you all for the pointers. I have been able to put my finger on the problem – besides using channel.request_pty it was also necessary to request a shell. The following finally works as expected:

Net::SSH.start('host', 'user', :password => "pass", :auth_methods => ["password"]) do |session|

  session.open_channel do |channel|

    channel.request_pty do |ch, success| 
      raise "Error requesting pty" unless success 

      ch.send_channel_request("shell") do |ch, success| 
        raise "Error opening shell" unless success  
      end  
    end

    channel.on_data do |ch, data|
      STDOUT.print data
    end 

    channel.on_extended_data do |ch, type, data|
      STDOUT.print "Error: #{data}\n"
    end

    channel.send_data( "1\n" )

    session.loop
  end  
end    


I'm not terribly familiar with the Net::SSH libs so I can't help with that per-se but it sounds like you could achieve what you want using Capistrano.

For example I have a capistrano task which connects to a remote server, runs a command which expects input and then continues. Capistrano takes care of the remote i/o. Maybe that could be a solution for you?

Hope it helps!


If I execute "1\n" in a shell the reply I get is: bash: 1: command not found

If I execute echo "1" I get: 1

Are you sure you want to try to execute the text you are sending? Maybe you were looking for something like:

output = ""
Net::SSH.start('host', 'user', :password => "pass") do |ssh|
   output = ssh.exec! "echo 1"
end
puts output


I'm not proficient with that lib, but on SSH you can open multiple channels. Maybe the server only responds to the first default channel and if you open another one you get a fresh shell.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜