Net :: SSH sudo命令在输入密码后挂起

问题描述:

我一直在尝试使用Thor编写一个小型库来帮助我快速创建新项目和网站。我写了这个小方法:Net :: SSH sudo命令在输入密码后挂起

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}") 

输入密码以后整个事情hhangs该脚本会提示我输入密码

[sudo] password for user: 

但随后。

会有人碰巧知道为什么它完全挂起,以及我可以做什么来在Net :: SSH(或其他备选)下的远程服务器上运行sudo命令?

*注意:建议之前,我最初开始将这个图书馆作为Capistrano下的食谱编写,直到我找到Thor,并且认为这将是一个很好的尝试的机会。如果需要的话,我并不反对将所有事情都交给Capistrano,但如果没有简单的方法在远程服务器上运行sudo命令,我会感到非常惊讶。

+0

你可以在密码中输入密码吗? 'ssh(“sudo cp#{from}#{to} Fosco 2010-07-28 19:58:35

+0

当然,我忘了在以前的评论中忘掉双引号 – Fosco 2010-07-28 20:14:51

+0

试过了,但它不起作用。 “bash:mysupass:没有这样的文件或目录”,这是否试图将密码输入到提示符中?如果是这样,这个想法可能会起作用,但是语法可能只是关闭了,我会看看我能找到什么 – joeellis 2010-07-28 20:24:42

您可能想要尝试的第一件事是使用公钥而不是密码登录。然后尝试从交互式shell运行命令。

例如:

(这部分真的取决于你拥有的服务器/客户端软件)

$ ssh-keygen 
$ scp .ssh/id-dsa.pub server: 
$ ssh server 
server$ cat id-dsa.pub >> .ssh/authorizedkeys 

$ scp -c "ls" 

这应该没有任何提示,如果密钥共享成功。

+1

实际上我使用的是公钥,它提示的密码不是ssh连接的密码,而是sudo运行命令的密码,所以我至少知道它连接了,但是我填入后会挂起 – joeellis 2010-07-28 20:21:34

+0

你可能会尝试设置sudo不要求为特定用户输入密码 – sukru 2010-07-28 20:32:06

+0

我已经在远程服务器的sudoers文件中通过在最后添加了跟随者行“user ALL =(ALL)ALL “,但我仍然得到提示,我在做什么不正确? – joeellis 2010-07-28 20:42:58

有可能与net/ssh设置它,但它确实太多精力,就执行这样ssh命令:

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

-t意味着分配一个tty。没有它,它仍然可以工作,但你的密码将被清楚地看到。

(我假设你打算手动输入sudo密码,如果没有,请使用授权密钥方式)。

这里是一个可能的解决方案:到底

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 

但是这种解决方案,你有你的根密码以明文在某处的脚本文件writen ...

+0

@japancheese您发布的最后一个代码不处理sudo提示符密码。这与你的问题中给出的代码完全相同。 – Riba 2010-11-22 16:00:36

其实,我做了非常类似于Riba的建议(尽管他/她的代码更好,更聪明,我认为)

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 

我希望这会帮助别人搜索。在部署过程中我还需要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

我被骗做添加此:

sudouser ALL=(ALL:ALL) NOPASSWD: ALL 

/etc/sudoers

此外,请务必在编辑时使用visudo! !