require 'net/ssh/gateway' require 'net/scp' module Sprinkle module Actors class Ssh attr_accessor :options def initialize(options = {}, &block) #:nodoc: @options = options.update(:user => 'root') self.instance_eval &block if block end def roles(roles) @options[:roles] = roles end def gateway(gateway) @options[:gateway] = gateway end def user(user) @options[:user] = user end def process(name, commands, roles, suppress_and_return_failures = false) return process_with_gateway(name, commands, roles) if gateway_defined? process_direct(name, commands, roles) end def transfer(name, source, destination, roles, recursive = true, suppress_and_return_failures = false) return transfer_with_gateway(name, source, destination, roles, recursive) if gateway_defined? transfer_direct(name, source, destination, roles, recursive) end protected def process_with_gateway(name, commands, roles) on_gateway do |gateway| Array(roles).each { |role| execute_on_role(commands, role, gateway) } end end def process_direct(name, commands, roles) Array(roles).each { |role| execute_on_role(commands, role) } end def transfer_with_gateway(name, source, destination, roles, recursive) on_gateway do |gateway| Array(roles).each { |role| transfer_to_role(source, destination, role, recursive, gateway) } end end def transfer_direct(name, source, destination, roles, recursive) Array(roles).each { |role| transfer_to_role(source, destination, role, recursive) } end def execute_on_role(commands, role, gateway = nil) hosts = @options[:roles][role] Array(hosts).each { |host| execute_on_host(commands, host, gateway) } end def transfer_to_role(source, destination, role, gateway = nil) hosts = @options[:roles][role] Array(hosts).each { |host| transfer_to_host(source, destination, host, gateway) } end def execute_on_host(commands, host, gateway = nil) if gateway # SSH connection via gateway gateway.ssh(host, @options[:user]) do |ssh| execute_on_connection(commands, ssh) end else # direct SSH connection Net::SSH.start(host, @options[:user]) do |ssh| execute_on_connection(commands, ssh) end end end def execute_on_connection(commands, connection) Array(commands).each do |command| connection.exec! command do |ch, stream, data| logger.send((stream == :stderr ? 'error' : 'debug'), data) end end end def transfer_to_host(source, destination, host, recursive, gateway = nil) if gateway # SSH connection via gateway gateway.ssh(host, @options[:user]) do |ssh| transfer_on_connection(source, destination, recursive, ssh) end else # direct SSH connection Net::SSH.start(host, @options[:user]) do |ssh| transfer_on_connection(source, destination, recursive, ssh) end end end def transfer_on_connection(source, destination, recursive, connection) scp = Net::SCP.new(connection) scp.upload! source, destination, :recursive => recursive end private def gateway_defined? !! @options[:gateway] end def on_gateway(&block) gateway = Net::SSH::Gateway.new(@options[:gateway], @options[:user]) block.call gateway ensure gateway.shutdown! end end end end