2010-08-02 4 views
30

que tienen un fragmento de código, simplemente tratando de ejecutar una secuencia de comandos en un servidor remoto, en el caso de que no, me gustaría hacer una llamada de seguimiento, imaginar esto:¿Cómo obtener el estado de salida con la biblioteca Ruby's Net :: SSH?

require 'rubygems' 
require 'net/ssh' 
require 'etc' 

server = 'localhost' 

Net::SSH.start(server, Etc.getlogin) do |ssh| 
    puts (ssh.exec("true") ? 'Exit Success' : "Exit Failure") 
    puts (ssh.exec("false") ? 'Exit Success' : "Exit Failure") 
end 

I esperaría (ignorando que stdout y stderr están impresos en mi ejemplo artificial) - pero la primera línea debería salir con 0, que esperaría que Ruby interpegara como false y muestre "Fallo de salida" (claro, la lógica es incorrecta, el ternario necesita para voltear) - pero la segunda línea debe salir con el estado opuesto, y no es así.

Ni siquiera puedo encontrar nada en la documentación sobre cómo hacer esto, y estoy un poco preocupado de que pueda estar haciendo mal?

Respuesta

66

Me parece mucho más útil la siguiente forma de ejecutar procesos con Net :: SSH. Le proporciona diferentes stdout y stderr, exit code y exit signal.

require 'rubygems' 
require 'net/ssh' 
require 'etc' 

server = 'localhost' 

def ssh_exec!(ssh, command) 
    stdout_data = "" 
    stderr_data = "" 
    exit_code = nil 
    exit_signal = nil 
    ssh.open_channel do |channel| 
    channel.exec(command) do |ch, success| 
     unless success 
     abort "FAILED: couldn't execute command (ssh.channel.exec)" 
     end 
     channel.on_data do |ch,data| 
     stdout_data+=data 
     end 

     channel.on_extended_data do |ch,type,data| 
     stderr_data+=data 
     end 

     channel.on_request("exit-status") do |ch,data| 
     exit_code = data.read_long 
     end 

     channel.on_request("exit-signal") do |ch, data| 
     exit_signal = data.read_long 
     end 
    end 
    end 
    ssh.loop 
    [stdout_data, stderr_data, exit_code, exit_signal] 
end 

Net::SSH.start(server, Etc.getlogin) do |ssh| 
    puts ssh_exec!(ssh, "true").inspect 
    # => ["", "", 0, nil] 

    puts ssh_exec!(ssh, "false").inspect 
    # => ["", "", 1, nil] 

end 

Espero que esto ayude.

+0

Wow, eso es genial. Gracias. – sarnold

+0

flitzwald, eso es increíble. ¡Ojalá pudiera agregar retrospectivamente una recompensa o algo así! ¡Muchas gracias! –

+0

Muchas gracias. Funciona perfectamente Esto debería estar en Net :: SSH. –

6

Sobre la base de la respuesta por flitzwald - He mono parcheado mi versión de esto en Net :: SSH (Rubí 1.9+)

class Net::SSH::Connection::Session 
    class CommandFailed < StandardError 
    end 

    class CommandExecutionFailed < StandardError 
    end 

    def exec_sc!(command) 
    stdout_data,stderr_data = "","" 
    exit_code,exit_signal = nil,nil 
    self.open_channel do |channel| 
     channel.exec(command) do |_, success| 
     raise CommandExecutionFailed, "Command \"#{command}\" was unable to execute" unless success 

     channel.on_data do |_,data| 
      stdout_data += data 
     end 

     channel.on_extended_data do |_,_,data| 
      stderr_data += data 
     end 

     channel.on_request("exit-status") do |_,data| 
      exit_code = data.read_long 
     end 

     channel.on_request("exit-signal") do |_, data| 
      exit_signal = data.read_long 
     end 
     end 
    end 
    self.loop 

    raise CommandFailed, "Command \"#{command}\" returned exit code #{exit_code}" unless exit_code == 0 

    { 
     stdout:stdout_data, 
     stderr:stderr_data, 
     exit_code:exit_code, 
     exit_signal:exit_signal 
    } 
    end 
end 
+0

¿Consideró enviar esto como un parche up-stream para ellos? –

+0

Actualmente estoy trabajando en un proyecto que depende de esta función: una vez que lo haya probado lo haré. Hay ocasiones en que el código de salida es> 0 a pesar de la ejecución exitosa, por lo que lo más probable es que modifique la subida para que sea opcional – Mikey

+0

@Mikey ¿Qué situaciones sería? ¿Habría un código de salida distinto de cero porque el shell, ssh o el problema de comunicación de la biblioteca o el comando devolvería el código de salida de nonzro pero haría su trabajo? – Phillipp

Cuestiones relacionadas