実行可能なコンポーネントを持つ宝石/モジュールとしてRubyスクリプトを書き直すことにしました。オリジナルはうまく動作しますが、宝石としてすべての依存関係を維持/インストールする方が簡単です。コマンドから実行したときにスレッド出力が表示されない(irbで動作)
このコマンドは、ホストとコマンドの配列をとり、スレッドを介してホスト上で実行します。私が現在持っている問題は、コマンドの出力が端末に表示されないということです。ただし、IRB内からモジュールコードを実行すると出力が生成されます。次のように
モジュールのコードは次のとおり
require "rcmd/version"
require 'net/ssh'
require 'thread'
module Rcmd
@queue = Queue.new
class << self
attr_accessor :nthreads
attr_accessor :user
attr_accessor :quiet
attr_accessor :command
attr_accessor :host_list
attr_accessor :threads
end
# Built in function called by each thread for executing the command on individual hosts
def Rcmd.run_command_on_host(conn_options)
begin
# Create ssh session to host
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
puts "#{conn_options[:host]} :: #{data}" unless conn_options[:quiet]
end
channel.on_extended_data do |ch,type,data|
# Always print stderr data
puts "#{conn_options[:host]} :: ERROR :: #{data}"
end
# Execute command
channel.exec @command
end
# Loop until command completes
session.loop
end
rescue
puts "#{conn_options[:host]} :: CONNECT ERROR :: Unable to connect to host!\n"
end
end
# Main method of module for starting the execution of the specified command on provided hosts
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 <= @host_list.count ? @nthreads : @host_list.count
# Prepare threads
@threads = { }
num_threads.times do |i|
@threads[i] = Thread.new {
conn_options = { :user => @user, :host => @queue.pop, :password => nil, :quiet => @quiet}
unless conn_options[:host].nil?
self.run_command_on_host(conn_options)
end
}
end
# Execute threads
@threads.each(&:join)
end
end
end
テストスニペット:
require 'rcmd'
Rcmd.host_list= ["localhost", "dummy-host"]
Rcmd.nthreads= 2
Rcmd.user= 'root'
Rcmd.command= "hostname -f"
Rcmd.run_command
IRB上記ランニング生成:予想されたように
dummy-host :: CONNECT ERROR :: Unable to connect to host!
localhost :: darkstar.lan
。しかし、スクリプトファイル(GEMコマンド)から、またはRubyで同じことを実行すると、直接出力なしで結果:
[email protected]:~/repos/rcmd$ rcmd -n localhost,dummy-host -c 'hostname -f'
[email protected]:~/repos/rcmd$
以前私は$ stdout.putsを使用して$ stderr.putsだけでなく、定数の変種が、中絶望はそれをただのものに移した。私はまた、印刷物や、スレッドにストリームを渡したり、スレッドが終了してもすべての出力を印刷するなど、さまざまな方法で試してみましたが、役に立たなくなってしまいました。
コードから「p」文を追加した後、コマンドから実行すると、出力はrun_command_on_hostメソッドのNet :: SSH.startコールの直前で停止します。
また、スレッド作成内でそのメソッド全体を実行しようとしましたが、完全に実行できませんでした。したがって、2つの方法がある。スレッドを作成するためのものと、sshのセッションとコマンドを実行するためにスレッドによって使用されるもの。
ruby-2.3.3とruby-2.0.0-p648の両方で失敗しているので、私は何かばかげていると思う。
誰かが自分の心の中でこのRuby初心者に何か間違っていると言ってもらうと、非常に感謝しています。