Responder a uma solicitação SSH antes do primeiro comando com rubi e Net :: SSH
Pergunta
Eu estou tentando se conectar, usando Net :: SSH, para um servidor que imediatamente após de login executa um script que requer entrada do usuário. O usuário tem que digitar "1" ou "2" e receberá alguns dados via no terminal depois.
Meu problema é que, embora eu seja capaz de se conectar, eu não consigo descobrir uma maneira de enviar "1 \ n" para o servidor e para receber a saída.
O código a seguir pára em "INFO - net.ssh.connection.session [80906b74]: channel_open_confirmation: 0 0 0 32768".
Usando channel.exec ( "1 \ n") em vez de channel.send_data sem surpresa não quer trabalhar.
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
Todas as ideias, qualquer um?
Agradecemos antecipadamente
Solução
Você pode verificar se a sua chamada send_data
está acontecendo após você receber o prompt do servidor remoto? Tentar construir um bloco channel.on_data
em torno de sua chamada send_data
para que você possa verificar se você obter o prompt de espera do servidor antes de enviar uma resposta.
Você não pode querer estar usando exec
aqui. De docs para Net :: SSH :: Conexão :: Canal:
Envia um pedido de canal pedindo que o comando dado ser invocado.
Você está querendo enviar uma seqüência de texto para responder a uma solicitação, não invocar um comando. Os documentos mostram exec
sendo usado para enviar comandos completa CLI como "ls -l / home".
Em vez disso, send_data
é provavelmente o que você quer. Os documentos mostram que costumava enviar mensagens de texto arbitrária como channel.send_data("the password\n")
. Note, no entanto, esta frase nos docs:
Note que ele não envia imediatamente os dados através do canal, mas em vez disso simplesmente anexa os dados fornecidos ao tampão de saída do canal, preparatório para ser empacotado e enviado da próxima vez que a conexão está a aceitar os dados.
Você pode querer dar uma olhada em channel.request_pty
. Parece ser projetado para a interação com um aplicativo baseado em console.
Se você está tentando (em essência) script de uma sessão SSH que você faria normalmente manualmente, você pode achar que é mais fácil de usar um expect
-como interface (por exemplo, uma jóia como sshExpect pode valer a pena tentar).
Outras dicas
Obrigado a todos para os ponteiros. Eu tenho sido capaz de colocar o dedo sobre o problema - além de usar channel.request_pty também foi necessário para solicitar uma concha. A seguir, finalmente funciona como esperado:
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
Eu não sou terrivelmente familiarizados com as libs Net :: SSH para que eu não posso ajudar com isso por si só, mas parece que você poderia conseguir o que deseja usando Capistrano .
Por exemplo, eu tenho uma tarefa capistrano que se conecta a um servidor remoto, executa um comando que espera de entrada e, em seguida, continua. Capistrano cuida do remota i / o. Talvez isso poderia ser uma solução para você?
Espero que ajude!
Se eu executar "1\n"
em um shell a resposta que recebo é: bash: 1: command not found
Se eu executar echo "1"
eu recebo: 1
Você tem certeza que quer tentar executar o texto que você está enviando? Talvez você estava procurando algo como:
output = ""
Net::SSH.start('host', 'user', :password => "pass") do |ssh|
output = ssh.exec! "echo 1"
end
puts output
Eu não sou proficiente com que lib, mas em SSH você pode abrir vários canais. Talvez o servidor só responde ao primeiro canal padrão e se você abrir um outro você começa um novo shell.