Скрипт Ruby на все узлы работают не только для обучения


Я написал следующий скрипт на Ruby несколько лет назад и уже используют его часто с тех пор, как на биоинформатики вычислительного кластера.

Он достает список хостов, с момента очереди системы qnodes. Это СШ'ES и выполняет команду на все узлы. Затем он печатает в выходной и/или ошибок в определенном порядке (алфавитном сортировки хостов).

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

on-all-nodes-run

Я хотел бы использовать его как пример для практикума, рубиновый. Не могли бы вы, пожалуйста, предложите лучшие практики и улучшен дизайн шаблон?

#!/usr/bin/ruby

EXCLUDE = [/girkelab/, /biocluster/, /parrot/, /owl/] 

require "open3"

# Non-interactive, no password asking, and seasonable timeouts
SSH_OPTIONS = ["-o PreferredAuthentications=publickey,hostbased,gssapi,gssapi-with-mic",
               "-o ForwardX11=no",
               "-o BatchMode=yes",
               "-o SetupTimeOut=5",
               "-o ServerAliveInterval=5",
               "-o ServerAliveCountMax=2"
              ].join(" ")

SSH    = "/usr/bin/ssh #{SSH_OPTIONS}"
MKDIR  = "/bin/mkdir"

raise "Pleae give this command at least one argument" if ARGV.size < 1
COMMAND = ARGV[0..-1].join(' ')

output_o = {}
output_e = {}


IO_CONNECTIONS_TO_REMOTE_PROCESSES = {}

def on_all_nodes(&block)
  nodes = []
  Kernel.open('|qnodes | grep -v "^ " | grep -v "^$"') do |f|
    while line = f.gets
      i = line.split(' ').first
      nodes.push(i) if EXCLUDE.select{|x| i =~ x}.empty?
    end
  end
  nodes.sort.each {|n| block.call(n)}
end


# Create processes
on_all_nodes do |node|
  stdin, stdout, stderr = Open3.popen3("#{SSH} #{node} \"#{COMMAND}\"")
  IO_CONNECTIONS_TO_REMOTE_PROCESSES[node] = [stdin, stdout, stderr]
end


has_remote_errors = false

# Collect results
on_all_nodes do |node|
  stdin, stdout, stderr = IO_CONNECTIONS_TO_REMOTE_PROCESSES[node]

  stdin.close

  e_thread = Thread.new do
    while line = stderr.gets
      line.chomp!
      STDERR.puts "#{node} ERROR: #{line}"
      has_remote_errors = true
    end
  end

  o_thread = Thread.new do
    while line = stdout.gets
      line.chomp!
      puts "#{node}      : #{line}"
    end
  end

  # Let the threads finish
  t1 = nil
  t2 = nil
  while [t1, t2].include? nil
    if t1.nil?
      t1 = e_thread.join(0.1) # Gives 1/10 of a second to STDERR
    end
    if t2.nil?
      t2 = o_thread.join(0.1) # Give 1/10 of a second to STDOUT
    end
  end

end


exit(1) if has_remote_errors


Комментарии