2010-07-28 17 views
5

He estado tratando de escribir una pequeña biblioteca utilizando Thor para ayudarme a crear proyectos y sitios nuevos. Escribí este pequeño método:Net :: SSH comando sudo se cuelga después de ingresar la contraseña

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

a sólo me ayudan en la ejecución de comandos rápidos en servidores remotos cuando sea necesario.

El problema es cuando necesito ejecutar un comando bajo sudo en el extremo remoto, el script simplemente parece colgarse de mí. Por ejemplo, cuando la ejecución de este ...

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

El guión me va a pedir una contraseña

[sudo] password for user: 

Pero entonces todo hhangs después de escribir en.

qué alguien pasar a conocer ¿Por qué se cuelga exactamente, y qué puedo hacer para ejecutar el comando sudo en un servidor remoto en Net :: SSH (o alguna alternativa)?

* nota: Antes había sugerido, originalmente había comenzado a escribir esta biblioteca como una receta en Capistrano, hasta que encontré a Thor, y pensé que sería una buena oportunidad para probarlo. No estoy en contra de tener que cambiar todo de nuevo a Capistrano si es necesario, pero me sorprendería mucho que no haya una manera fácil de ejecutar comandos sudo en un servidor remoto.

+0

¿puede insertar la contraseña? 'ssh (" sudo cp # {from} # {to} <"mysupass") ' – Fosco

+0

por supuesto me olvidé de escapar de las comillas dobles en el comentario anterior. – Fosco

+0

Probé esto, pero no funciona. Vuelve con "bash: mysupass: No existe ese archivo o directorio". ¿Es esto un intento de pasar la contraseña al prompt? De ser así, la idea podría funcionar, pero la sintaxis probablemente esté apagada. Veré qué puedo encontrar sobre eso. – joeellis

Respuesta

1

Lo primero que debe probar es usar claves públicas en lugar de contraseñas para iniciar sesión. Luego también intente ejecutar el comando desde el shell interactivo.

Por ejemplo:

(Esta parte realmente depende del software de servidor/cliente tiene)

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

$ scp -c "ls" 

esto debería funcionar sin ningún tipo de indicaciones, si el intercambio de clave fue exitosa.

+1

En realidad estoy usando claves públicas. La contraseña que está solicitando no es la contraseña para la conexión ssh, sino la contraseña para sudo ejecutar el comando. Así que al menos sé que se conecta, pero se cuelga después de completar la contraseña de sudo. – joeellis

+0

Puede intentar configurar sudo para no solicitar una contraseña para el usuario específico. – sukru

+0

Lo intenté en el archivo sudoers en el servidor remoto agregando las líneas seguidoras al final "usuario ALL = (ALL) ALL ", pero sigo recibiendo indicaciones. ¿Estoy haciendo esto? es incorrecto? – joeellis

4

Es posible configurarlo con net/ssh, pero en realidad es demasiado esfuerzo, sólo hay que ejecutar ssh comando como este:

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

Este -t significa asignar un TTY. Sin él, seguirá funcionando, pero su contraseña se verá en claro.

(supongo que tiene la intención de escribir sudo contraseña manualmente. Si no, vaya a la forma de teclas autorizadas).

5

Aquí es una solución posible:

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 

Sin embargo, con esta solución, que ha su contraseña de root writen en claro en un archivo de script en alguna parte ...

+0

@japancheese El último código que ha publicado no maneja la contraseña de sudo prompt. Es exactamente el mismo código dado en su pregunta. – Riba

-1

En realidad, al final, hice algo muy similar a la sugerencia de Riba (aunque su/su código es mucho mejor y más inteligente, creo)

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 
13

espero que esto ayude a alguien a buscar.También necesitaba sudo durante el despliegue (reiniciar casos finas)

# 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 

Tenga en cuenta que un canal sólo puede ejecutar un comando. De ahí que los comandos encadenado junto con commands.join(';')

Referencia: Net::SSH::Connection::Channel

2

hice trampa haciendo añadiendo esto:

sudouser ALL=(ALL:ALL) NOPASSWD: ALL 

a /etc/sudoers

Además, asegúrese de usar visudo al editar !! !

Cuestiones relacionadas