lib/ztk/ssh.rb in ztk-0.0.3 vs lib/ztk/ssh.rb in ztk-0.0.4

- old
+ new

@@ -15,10 +15,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ################################################################################ +require "ostruct" module ZTK class SSHError < Error; end class SSH @@ -26,161 +27,164 @@ attr_accessor :stdout, :stderr, :stdin, :config ################################################################################ - def initialize(logger=$logger, stdout=$stdout, stderr=$stderr, stdin=$stdin) - @logger, @stdout, @stderr, @stdin = logger, stdout, stderr, stdin - - @logger.sync = true if @logger.respond_to?(:sync=) - @stdout.sync = true if @stdout.respond_to?(:sync=) - @stderr.sync = true if @stderr.respond_to?(:sync=) - @stdin.sync = true if @stdin.respond_to?(:sync=) - - @config = Hash.new(nil) + def initialize(config={}) + @config = OpenStruct.new({ + :stdout => $stdout, + :stderr => $stderr, + :stdin => $stdin, + :logger => $logger, + :ssh => Hash.new(nil) + }.merge(config)) + @config.stdout.sync = true if @config.stdout.respond_to?(:sync=) + @config.stderr.sync = true if @config.stderr.respond_to?(:sync=) + @config.stdin.sync = true if @config.stdin.respond_to?(:sync=) + @config.logger.sync = true if @config.logger.respond_to?(:sync=) end ################################################################################ def console - @logger and @logger.debug { "config(#{@config.inspect})" } + @config.logger and @config.logger.debug { "config(#{@config.ssh.inspect})" } command = [ "ssh" ] command << [ "-q" ] command << [ "-o", "UserKnownHostsFile=/dev/null" ] command << [ "-o", "StrictHostKeyChecking=no" ] command << [ "-o", "KeepAlive=yes" ] command << [ "-o", "ServerAliveInterval=60" ] - command << [ "-i", @config[:identity_file] ] if @config[:identity_file] - command << [ "-o", "ProxyCommand=\"#{proxy_command}\"" ] if @config[:proxy] - command << "#{@config[:ssh_user]}@#{@config[:host]}" + command << [ "-i", @config.ssh[:identity_file] ] if @config.ssh[:identity_file] + command << [ "-o", "ProxyCommand=\"#{proxy_command}\"" ] if @config.ssh[:proxy] + command << "#{@config.ssh[:ssh_user]}@#{@config.ssh[:host]}" command = command.flatten.compact.join(" ") - @logger and @logger.info { "command(#{command})" } + @config.logger and @config.logger.info { "command(#{command})" } Kernel.exec(command) end ################################################################################ def exec(command, options={}) - @ssh ||= Net::SSH.start(@config[:host], @config[:ssh_user], ssh_options) + @ssh ||= Net::SSH.start(@config.ssh[:host], @config.ssh[:ssh_user], ssh_options) options = { :silence => false }.merge(options) silence = options[:silence] output = "" - @logger and @logger.debug { "config(#{@config.inspect})" } - @logger and @logger.debug { "options(#{options.inspect})" } - @logger and @logger.info { "command(#{command})" } + @config.logger and @config.logger.debug { "config(#{@config.ssh.inspect})" } + @config.logger and @config.logger.debug { "options(#{options.inspect})" } + @config.logger and @config.logger.info { "command(#{command})" } channel = @ssh.open_channel do |chan| - @logger and @logger.debug { "channel opened" } + @config.logger and @config.logger.debug { "channel opened" } chan.exec(command) do |ch, success| raise SSHError, "Could not execute '#{command}'." unless success ch.on_data do |c, data| output += data - @logger and @logger.debug { data.chomp.strip } - @stdout.print(data) if !silence + @config.logger and @config.logger.debug { data.chomp.strip } + @config.stdout.print(data) if !silence end ch.on_extended_data do |c, type, data| output += data - @logger and @logger.debug { data.chomp.strip } - @stderr.print(data) if !silence + @config.logger and @config.logger.debug { data.chomp.strip } + @config.stderr.print(data) if !silence end end end channel.wait - @logger and @logger.debug { "channel closed" } + @config.logger and @config.logger.debug { "channel closed" } output end ################################################################################ def upload(local, remote) - @sftp ||= Net::SFTP.start(@config[:host], @config[:ssh_user], ssh_options) + @sftp ||= Net::SFTP.start(@config.ssh[:host], @config.ssh[:ssh_user], ssh_options) - @logger and @logger.debug { "config(#{@config.inspect})" } - @logger and @logger.info { "parameters(#{local},#{remote})" } + @config.logger and @config.logger.debug { "config(#{@config.ssh.inspect})" } + @config.logger and @config.logger.info { "parameters(#{local},#{remote})" } @sftp.upload!(local.to_s, remote.to_s) do |event, uploader, *args| case event when :open - @logger and @logger.info { "upload(#{args[0].local} -> #{args[0].remote})" } + @config.logger and @config.logger.info { "upload(#{args[0].local} -> #{args[0].remote})" } when :close - @logger and @logger.debug { "close(#{args[0].remote})" } + @config.logger and @config.logger.debug { "close(#{args[0].remote})" } when :mkdir - @logger and @logger.debug { "mkdir(#{args[0]})" } + @config.logger and @config.logger.debug { "mkdir(#{args[0]})" } when :put - @logger and @logger.debug { "put(#{args[0].remote}, size #{args[2].size} bytes, offset #{args[1]})" } + @config.logger and @config.logger.debug { "put(#{args[0].remote}, size #{args[2].size} bytes, offset #{args[1]})" } when :finish - @logger and @logger.info { "finish" } + @config.logger and @config.logger.info { "finish" } end end end ################################################################################ def download(remote, local) - @sftp ||= Net::SFTP.start(@config[:host], @config[:ssh_user], ssh_options) + @sftp ||= Net::SFTP.start(@config.ssh[:host], @config.ssh[:ssh_user], ssh_options) - @logger and @logger.debug { "config(#{@config.inspect})" } - @logger and @logger.info { "parameters(#{remote},#{local})" } + @config.logger and @config.logger.debug { "config(#{@config.ssh.inspect})" } + @config.logger and @config.logger.info { "parameters(#{remote},#{local})" } @sftp.download!(remote.to_s, local.to_s) do |event, downloader, *args| case event when :open - @logger and @logger.info { "download(#{args[0].remote} -> #{args[0].local})" } + @config.logger and @config.logger.info { "download(#{args[0].remote} -> #{args[0].local})" } when :close - @logger and @logger.debug { "close(#{args[0].local})" } + @config.logger and @config.logger.debug { "close(#{args[0].local})" } when :mkdir - @logger and @logger.debug { "mkdir(#{args[0]})" } + @config.logger and @config.logger.debug { "mkdir(#{args[0]})" } when :get - @logger and @logger.debug { "get(#{args[0].remote}, size #{args[2].size} bytes, offset #{args[1]})" } + @config.logger and @config.logger.debug { "get(#{args[0].remote}, size #{args[2].size} bytes, offset #{args[1]})" } when :finish - @logger and @logger.info { "finish" } + @config.logger and @config.logger.info { "finish" } end end end ################################################################################ private ################################################################################ def proxy_command - @logger and @logger.debug { "config(#{@config.inspect})" } + @config.logger and @config.logger.debug { "config(#{@config.ssh.inspect})" } - if !@config[:identity_file] + if !@config.ssh[:identity_file] message = "You must specify an identity file in order to SSH proxy." - @logger and @logger.fatal { message } + @config.logger and @config.logger.fatal { message } raise SSHError, message end command = ["ssh"] command << [ "-q" ] command << [ "-o", "UserKnownHostsFile=/dev/null" ] command << [ "-o", "StrictHostKeyChecking=no" ] command << [ "-o", "KeepAlive=yes" ] command << [ "-o", "ServerAliveInterval=60" ] - command << [ "-i", @config[:proxy_identity_file] ] if @config[:proxy_identity_file] - command << "#{@config[:proxy_ssh_user]}@#{@config[:proxy_host]}" + command << [ "-i", @config.ssh[:proxy_identity_file] ] if @config.ssh[:proxy_identity_file] + command << "#{@config.ssh[:proxy_ssh_user]}@#{@config.ssh[:proxy_host]}" command << "nc %h %p" command = command.flatten.compact.join(" ") - @logger and @logger.debug { "command(#{command})" } + @config.logger and @config.logger.debug { "command(#{command})" } command end ################################################################################ def ssh_options - @logger and @logger.debug { "config(#{@config.inspect})" } + @config.logger and @config.logger.debug { "config(#{@config.ssh.inspect})" } options = {} - options.merge!(:password => @config[:ssh_password]) if @config[:ssh_password] - options.merge!(:keys => @config[:identity_file]) if @config[:identity_file] - options.merge!(:timeout => @config[:timeout]) if @config[:timeout] - options.merge!(:user_known_hosts_file => '/dev/null') if !@config[:host_key_verify] - options.merge!(:proxy => Net::SSH::Proxy::Command.new(proxy_command)) if @config[:proxy] - @logger and @logger.debug { "options(#{options.inspect})" } + options.merge!(:password => @config.ssh[:ssh_password]) if @config.ssh[:ssh_password] + options.merge!(:keys => @config.ssh[:identity_file]) if @config.ssh[:identity_file] + options.merge!(:timeout => @config.ssh[:timeout]) if @config.ssh[:timeout] + options.merge!(:user_known_hosts_file => '/dev/null') if !@config.ssh[:host_key_verify] + options.merge!(:proxy => Net::SSH::Proxy::Command.new(proxy_command)) if @config.ssh[:proxy] + @config.logger and @config.logger.debug { "options(#{options.inspect})" } options end ################################################################################