Ответьте на приглашение SSH перед первой командой с помощью Ruby и Net::SSH.
Вопрос
Я пытаюсь подключиться, используя net :: ssh, к серверу, который сразу после входа в систему выполняет сценарий, который требует ввода от пользователя.Пользователь должен ввести «1» или «2», после чего он получит некоторые данные через терминал.
Моя проблема в том, что, хотя я могу подключиться, я не могу найти способ отправить «1 » на сервер и получить выходные данные.
Следующий код останавливается на «INFO -- net.ssh.connection.session[80906b74]:канал_open_confirmation:0 0 0 32768".
Использование Channel.exec( "1 " ) вместо Channel.send_data, что неудивительно, также не работает.
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
Есть идеи, кто-нибудь?
заранее спасибо
Решение
Можете ли вы убедиться, что ваш send_data
звонок происходит после вы получаете приглашение от удаленного сервера?Попробуйте построить channel.on_data
блокировать вокруг своего send_data
вызовите, чтобы убедиться, что вы получили ожидаемое приглашение от сервера перед отправкой ответа.
Возможно, вы не захотите использовать exec
здесь.Из документации для Net::SSH::Connection::Channel:
Отправляет запрос канала с просьбой вызвать данную команду.
Вы хотите отправить текстовую строку для ответа на приглашение, а не для вызова команды.Документы показывают exec
используется для отправки полных команд CLI, таких как «ls -l /home».
Вместо, send_data
вероятно, это то, что вы хотите.Документы показывают, что он использовался для отправки произвольного текста, такого как channel.send_data("the password\n")
.Однако обратите внимание на это предложение в документации:
Обратите внимание, что он не сразу отправляет данные по каналу, но вместо этого просто добавляет данные данные в выходной буфер канала, подготовительную к упаковке и отправке в следующий раз, когда соединение принимает данные.
Возможно, вы захотите взглянуть на channel.request_pty
.Похоже, он предназначен для взаимодействия с консольным приложением.
Если вы пытаетесь (по сути) создать сценарий сеанса SSH, который обычно делаете вручную, возможно, вам будет проще использовать expect
-подобный интерфейс (например, гем типа sshExpect возможно, стоит попробовать).
Другие советы
Спасибо всем за указатели.Мне удалось понять проблему: помимо использования Channel.request_pty необходимо было также запросить оболочку.Следующее, наконец, работает так, как ожидалось:
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
Я не очень хорошо знаком с библиотеками Net::SSH, поэтому не могу помочь с этим как таковым, но похоже, что вы можете добиться того, чего хотите, используя Капистрано.
Например, у меня есть задача capistrano, которая подключается к удаленному серверу, запускает команду, которая ожидает ввода, а затем продолжает работу.Capistrano заботится об удаленном вводе-выводе.Может быть, это может быть решением для вас?
Надеюсь, поможет!
Если я выполню "1\n"
в оболочке я получаю ответ: bash: 1: command not found
Если я выполню echo "1"
Я получил: 1
Вы уверены, что хотите попробовать выполнить отправляемый текст?Возможно, вы искали что-то вроде:
output = ""
Net::SSH.start('host', 'user', :password => "pass") do |ssh|
output = ssh.exec! "echo 1"
end
puts output
Я не разбираюсь в этой библиотеке, но по SSH вы можете открыть несколько каналов.Возможно, сервер отвечает только на первый канал по умолчанию, и если вы откроете другой, вы получите новую оболочку.