tags:

views:

226

answers:

5

Hello,

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 does 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

A: 

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!

Chris McCauley
A: 

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
ezpz
The problem is, I want to send "1\n" to the STDIN of the script waiting on the other end.
Molotoff
Is there any reason you are not just opening up a socket and listening on the remote machine?
ezpz
+2  A: 

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).

bta
I have actually tried using channel.request_pty, the request succeeds, but the data is neither being sent, nor received afterwards (using channel.send_data)
Molotoff
How can I verify whether I get a prompt from the remote server?
Molotoff
In your `channel.on_data do |ch, data| ... end` block, the variable "data" will hold the data sent to you from the server. Inside that block, `puts` it to the console/logfile and inspect it visually. Once you see what format the server's prompt will be in, you can write code to parse it. You might try something like `puts "got data: #{data.inspect}"`.
bta
A: 

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.

Shimodax
+1  A: 

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    
Molotoff