This module is for parellel remote (SSH) execution of a single command string on Multiple hosts. The module itself consists of one method for execution (Rcmd.run_command) which does not accept any arguments. The required arguments are set as variables through the use of accessors.
VERSION
- Version number string
String containing the command to be used. (Manditory)
An array of hosts to run the given command on. (Manditory)
Prefered/requested number of threads to be used. (Manditory)
Boolean for disabling STDOUT output. SDTERR is always displayed. (Optional)
Array containing the current iterations thread objects.
What user should we connect as. (Manditory)
Main method for this module which should be called after the correct variables have been set.
We iterate over the host list until it is empty, creating all needed threads based upon the prefered number of threads for execution. Before creating the threads, the method first checks if the preferred number of threads is greater then the number of hosts remaining in the host list. If false (threads > num hosts) then the number of remaining hosts becomes the thread count. This prevents spawning of unneeded threads.
:user
- User to run the command as
:command
- Command to be executed
:host_list
- Array containing the hosts for command execution.
:nthreads
- Preferred max number of threads
:quiet
- Do not print to STDOUT. STDERR is always printed
:threads
- Array of the current threads
require 'rcmd' Rcmd.host_list= ["host1", "host2", "host3", "host4", "host 5", "host6"] Rcmd.user= 'root' Rcmd.command= 'rpm -qa kernel\*' Rcmd.nthreads= 6 Rcmd.run_command
# File lib/rcmd.rb, line 74 def Rcmd.run_command() if not @command raise ArgumentError.new("No command set for execution") end if not @host_list.count >= 1 raise ArgumentError.new("host_list must contain at least one system") end @host_list.each do |host| @queue << host end until @queue.empty? # Don't start more threads then hosts. num_threads = @nthreads <= @queue.length ? @nthreads : @queue.length # Prepare threads @threads = [ ] num_threads.times do |i| @threads[i] = Thread.new { begin conn_options = { :user => @user, :host => @queue.pop, :password => nil, :quiet => @quiet} Net::SSH.start(conn_options[:host], conn_options[:user], :password => conn_options[:passwd]) do |session| # Open channel for input/output control session.open_channel do |channel| channel.on_data do |ch, data| # Print recieved data if quiet is not true STDOUT.print "#{conn_options[:host]} :: #{data}" unless conn_options[:quiet] end channel.on_extended_data do |ch,type,data| # Always print stderr data STDERR.print "#{conn_options[:host]} :: ERROR :: #{data}" end # Execute command channel.exec @command end # Loop until command completes session.loop end rescue STDERR.print "#{conn_options[:host]} :: CONNECT ERROR :: Unable to connect to host!\n" end } # Execute threads end @threads.each { |t| t.join } end unless @threads.each.map {|t| t.alive?}.none? sleep 1 end end