2011-07-24 8 views
6

Quiero escribir el código en Ruby witch net :: ssh que ejecuta los comandos uno por uno en la máquina remota de Linux y registra todo (llamado comando, stdout y stderr en máquina de linux).Ruby, ejecuta los comandos de Linux uno por uno, mediante SSH y LOG todo

Por lo tanto, la función de escribir:

def rs(ssh,cmds) 
    cmds.each do |cmd| 
     log.debug "[SSH>] #{cmd}" 
     ssh.exec!(cmd) do |ch, stream, data|  
     log.debug "[SSH:#{stream}>] #{data}"    
     end 
    end 
    end 

Por ejemplo, si quiero crear en Linux remota nuevas carpetas y archivos: "./verylongdirname/anotherlongdirname/a.txt", y archivos de lista en que direcotry, y encontrar firefox allí (que es tonto un poco: P) para que yo llamo el procedimiento anterior así:

Net::SSH.start(host, user, :password => pass) do |ssh| 

    cmds=["mkdir verylongdirname", \         #1 
     "cd verylongdirname; mkdir anotherlongdirname, \   #2 
     "cd verylongdirname/anotherlongdirname; touch a.txt", \ #3 
     "cd verylongdirname/anotherlongdirname; ls -la", \   #4 
     "cd verylongdirname/anotherlongdirname; find ./ firefox" #5 that command send error to stderr. 
     ] 

    rs(ssh,cmds) # HERE we call our function 

    ssh.loop 
end 

Después de ejecutar código anterior voy a tener información de brujas registro completo sobre ejecuciones comandos en la línea # 1, # 2, # 3, # 4, # 5. El problema es que el estado en Linux, entre los comandos de ejecución de cmds array, no se guarda (así que debo repetir la instrucción "cd" antes de ejecutar el comando correcto). Y no estoy satisfecho con eso.

Mi objetivo es tener tablas CMDS así:

cmds=["mkdir verylongdirname", \  #1 
     "cd verylongdirname", \   
     "mkdir anotherlongdirname", \ #2 
     "cd anotherlongdirname", \ 
     "touch a.txt", \    #3 
     "ls -la", \     #4 
     "find ./ firefox"]    #5 

Como se ve, te estado entre la ejecución de cada comando es ahorrar en la máquina Linux (y que no es necesario repetir apropriate "cd" declaración antes de ejecutar el comando correcto). ¿Cómo cambiar el procedimiento "rs (ssh, cmds)" para hacerlo y LOG TODO (comand, stdout, stdin) como antes?

Respuesta

3

Quizás intente con un canal ssh en su lugar para abrir un shell remoto. Eso debería preservar el estado entre sus comandos como la conexión se mantendrá abierta:

http://net-ssh.github.com/ssh/v1/chapter-5.html

Aquí es también un artículo de hacer algo similar con un poco enfoque diferente:

http://drnicwilliams.com/2006/09/22/remote-shell-with-ruby/

Editar 1:

Ok. Veo lo que dices. SyncShell se eliminó de Net :: SSH 2.0. Sin embargo, me encontré con esto, que parece que hace más o menos lo hizo SyncShell:

http://net-ssh-telnet.rubyforge.org/

Ejemplo:

s = Net::SSH.start(host, user) 
t = Net::SSH::Telnet.new("Session" => s, "Prompt" => %r{^myprompt :}) 
puts t.cmd("cd /tmp") 
puts t.cmd("ls")  # <- Lists contents of /tmp 

es decir, Net::SSH::Telnet es síncrono y preserva el estado, ya que se ejecuta en una pty con su entorno de shell remoto. Recuerde establecer la detección de solicitud correcta, de lo contrario Net::SSH::Telnet parecerá colgar una vez que lo llame (está tratando de encontrar la solicitud).

+0

1. En http: // drnicwilliams. com/2006/09/22/remote-shell-with-ruby/vemos: 'shell = session.shell.sync' Thad web es de 2006. Hoy en ruby ​​shell.sync no funciona. Shell probablemente haya caído de develop net :: ssh (no sé por qué). Existe un paquete alternativo net-ssh-shell pero es joven para usarlo (no se implementan muchas funciones allí). –

+0

2. Leí http://net-ssh.github.com/ssh/v1/chapter-5.html antes. Cuando trato de usar canales con sus funciones on_data (para stdout), on_extended_data (para stderr) y send_data (para enviar comandos uno a uno en bucle), pero no puedo forzar el registro secuencial (para registrar comandos secuenciales1, stdout1, stderr1) , command2, stdout2, stderr2, command3, stdout3, sterr3 ...). El motivo es que en send_data, todos los comandos se enviaron antes de ejecutarse primero en la máquina remota (de modo que en el registro vemos: comando1, comando2, comando3, ..., stdout1, stderr1, stdout2, stderr2, stdout3, stderr3 ... .) –

+1

@ user860099 - Ver mi edición. – Casper

2

Se puede utilizar tubería en su lugar:

require "open3" 

SERVER = "..." 
BASH_PATH = "/bin/bash" 

BASH_REMOTE = lambda do |command| 
    Open3.popen3("ssh #{SERVER} #{BASH_PATH}") do |stdin, stdout, stderr| 
    stdin.puts command 
    stdin.close_write 
    puts "STDOUT:", stdout.read 
    puts "STDERR:", stderr.read 
    end 
end 

BASH_REMOTE["ls /"] 
BASH_REMOTE["ls /no_such_file"] 
+0

Esa solución no funciona en Windows, por lo que no es portátil. No lo compruebo en Linux, pero gracias por su tiempo. Maby en el futuro alguien lo usará. –

+0

Revise este enlace http://rubyforge.org/projects/win32utils ('win32-popen3') –

2

Ok, finalmente, con la ayuda de @Casper me sale el procedimiento (Maby alguien usarlo):

# Remote command execution 
    # t=net::ssh:telnet, c="command_string" 
    def cmd(t,c)  
    first=true 
    d=''  
    # We send command via SSH and read output piece by piece (in 'cm' variable) 
    t.cmd(c) do |cm|  
     # below we cleaning up output piece (becouse it have strange chars)  
     d << cm.gsub(/\e\].*?\a/,"").gsub(/\e\[.*?m/,"").gsub(/\r/,"")  
     # when we read entire line(composed of many pieces) we write it to log 
     if d =~ /(^.*?)\n(.*)$/m 
     if first ; 
      # instead of the first line (which has repeated commands) we log commands 'c' 
      @log.info "[SSH]>"+c; 
      first=false 
     else 
      @log.info "[SSH] "+$1; 
     end 
     d=$2   
     end  
    end 

    # We print lines that were at the end (in last piece) 
    d.each_line do |l| 
     @log.info "[SSH] "+l.chomp  
    end 
    end 

y lo llamamos en el código :

#!/usr/bin/env ruby 

require 'rubygems' 

require 'net/ssh' 

require 'net/ssh/telnet' 

require 'log4r' 
... 
... 
... 
Net::SSH.start(host, user, :password => pass) do |ssh| 
    t = Net::SSH::Telnet.new("Session" => ssh) 
    cmd(t,"cd /") 
    cmd(t,"ls -la") 
    cmd(t,"find ./ firefox") 
end 

Gracias, bye.

Cuestiones relacionadas