lib/pec2/pssh.rb in pec2-0.5.1 vs lib/pec2/pssh.rb in pec2-0.6.0

- old
+ new

@@ -1,40 +1,70 @@ -require 'shellwords' +require 'net/ssh' +require 'parallel' +require 'colorize' module Pec2 class Pssh - PSSH_PATH = File.expand_path('../../../exe/bin/pssh', __FILE__) - - def initialize(options, hosts_file, parallel = 1) - @pssh_command = "#{PSSH_PATH} -t 0 -x '-tt' -h #{hosts_file} -O StrictHostKeyChecking=no" - if options[:print] - @pssh_command = "#{@pssh_command} -P" - end - - if options[:user] - @pssh_command = "#{@pssh_command} -l #{options[:user]}" - end - - if options[:log] - @pssh_command = "#{@pssh_command} -o #{options[:log]}" - end - - @pssh_command = "#{@pssh_command} -p #{options[:parallel] || parallel}" + def initialize(options, servers, parallel = 1) + @parallel = parallel + color_index = 0 + colors = String.colors.select{ |color| + !color.to_s.start_with?('light_') && !color.to_s.include?('red') && !color.to_s.include?('yellow') + } + @servers = servers.map { |server| + result = {} + result[:host] = server + result[:color] = colors[color_index] + if colors.size == color_index + 1 + color_index = 0 + else + color_index = color_index + 1 + end + result + } + @user = options[:user] + @print = options[:print] @sudo_password = options[:sudo_password] + @ssh_options = { + verify_host_key: false, + user_known_hosts_file: '/dev/null', + } + @logger = Logger.new(STDOUT) end - def build_pssh_command(command) - if @sudo_password - %Q{(echo #{@sudo_password}) | #{@pssh_command} -I #{Shellwords.escape(command)}} - else - %Q{#{@pssh_command} -i #{Shellwords.escape(command)}} - end - end - def exec_pssh_command(command) return false if command.nil? || command.empty? - build_command = build_pssh_command(command) - system(build_command) + error_servers = [] + Parallel.each(@servers, in_threads: @parallel) do |server| + begin + Net::SSH.start(server[:host], @user, @ssh_options) do |ssh| + channel = ssh.open_channel do |channel, success| + channel.on_data do |channel, data| + if data =~ /^\[sudo\] password for / + channel.send_data "#{@sudo_password}\n" + else + data.to_s.lines.each do |line| + if @print + print %Q{#{server[:host]}:#{line}}.colorize(server[:color]) + end + end + end + end + channel.request_pty + channel.exec(command) + channel.wait + end + channel.wait + end + rescue => e + error_servers << server[:host] + puts "\n#{e.message}\n#{e.backtrace.join("\n")}" + end + end + if error_servers.size > 0 + @logger.error "error servers => #{error_servers.join(', ')}".colorize(:red) + end + return true end end end