Команда Net :: SSH sudo зависает после ввода пароля - PullRequest
5 голосов
/ 28 июля 2010

Я пытался написать небольшую библиотеку, используя Thor, чтобы помочь мне в быстром создании новых проектов и сайтов.Я написал этот небольшой метод:

def ssh(cmd)
  Net::SSH.start( server_ip, user, :port => port) do |session|
    session.exec cmd
  end
end

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

Проблема в том, что когда мне нужно запустить команду под sudo на удаленном конце, сценарий просто зависает на мне.Например, при выполнении этого ...

ssh("sudo cp #{file_from_path} #{file_to_path}" )

Сценарий запросит у меня пароль

[sudo] password for user:

Но тогда все наберется после ввода.

Может кто-нибудь узнать, почему он зависает именно так, и что я могу сделать, чтобы запустить команду sudo на удаленном сервере под Net :: SSH (или какой-нибудь другой вариант)?начал писать эту библиотеку как рецепт под Capistrano, пока я не наткнулся на Тора, и подумал, что это будет хороший шанс опробовать его.Я не против того, чтобы переключать все это обратно на Capistrano, если это необходимо, но я был бы очень удивлен, если бы не было простого способа запуска команд sudo на удаленном сервере.

Ответы [ 6 ]

13 голосов
/ 30 ноября 2012

Надеюсь, это поможет кому-то искать.Мне также нужно было sudo во время развертывания (перезапуск тонких экземпляров)

# deploy.rake
require 'net/ssh'

# INITIALIZE CONSTANTS HERE
HOST = 'yourwebsite.com'
USER = 'admin'
PASSWORD = 'your server password' # or use ENV variables?
# etc.

namespace :deploy do 
  namespace :staging do  
    task :restart do
      commands = [
        "cd #{PATH_TO_STAGING_APP} && git checkout master",
        "git reset --hard HEAD",
        "git pull origin master",
        "bundle install --without test development",
        "sudo thin restart -C /etc/thin/#{STAGING_APP}.yml"
      ]

      Net::SSH.start(HOST, USER, :password => PASSWORD) do |ssh|
        ssh.open_channel do |channel|
          channel.request_pty do |ch, success|
            if success
              puts "Successfully obtained pty"
            else
              puts "Could not obtain pty"
            end
          end

          channel.exec(commands.join(';')) do |ch, success|
            abort "Could not execute commands!" unless success

            channel.on_data do |ch, data|
              puts "#{data}"
              channel.send_data "#{PASSWORD}\n" if data =~ /password/
            end

            channel.on_extended_data do |ch, type, data|
              puts "stderr: #{data}"
            end

            channel.on_close do |ch|
              puts "Channel is closing!"
            end
          end
        end
        ssh.loop
      end
    end
  end
end

Обратите внимание, что один канал может выполнять только одну команду.Поэтому я связал команды вместе с commands.join(';')

Ссылка: Net :: SSH :: Connection :: Channel

5 голосов
/ 21 ноября 2010

Вот возможное решение:

def ssh(cmd)
  Net::SSH.start( server_ip, user, :port => port) do |session|
    result = nil
    session.exec!(cmd) do |channel, stream, data|
      if data =~ /^\[sudo\] password for user:/
        channel.send_data 'your_sudo_password'
      else
        result << data
      end
    end
    result # content of 'cmd' result
  end
end

Но с этим решением ваш корневой пароль записан в открытом виде в файле сценария где-то ...

4 голосов
/ 29 июля 2010

Возможно установить его с помощью net/ssh, но на самом деле это слишком много усилий, просто выполните команду ssh следующим образом:

system("ssh", "-t", "#{user}@#{host}", "sudo cp #{file_from_path} #{file_to_path}")

Это -t означает выделение tty. Без него все равно будет работать, но ваш пароль будет виден в открытом виде.

(я предполагаю, что вы намерены ввести пароль sudo вручную. Если нет, перейдите по пути авторизованных ключей).

2 голосов
/ 06 декабря 2012

Я обманул, добавив следующее:

sudouser  ALL=(ALL:ALL) NOPASSWD: ALL

к /etc/sudoers

Кроме того, обязательно используйте visudo при редактировании !!!

1 голос
/ 28 июля 2010

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

Например:

(эта часть действительно зависит от имеющегося у вас программного обеспечения сервера / клиента)должен работать без каких-либо подсказок, если обмен ключами прошел успешно.

0 голосов
/ 21 ноября 2010

На самом деле, в конце концов, я сделал что-то очень похожее на предложение Рибы (хотя его / ее код гораздо лучше и умнее, я думаю)

def ssh(env, cmd, opts={})
    Net::SSH.start( config[env]["ip"], config[env]["user"], :port => config[env]["port"]) do |session|
        cmd = "sudo #{cmd}" if opts[:sudo]
        print cmd
        session.exec cmd
    end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...