From e42be7b98bcf600d60f5bfb0b037f270ae74f2fa Mon Sep 17 00:00:00 2001 From: elijah Date: Thu, 1 Nov 2012 01:08:04 -0700 Subject: more complete rsync compatibility with Net::SSH options --- vendor/supply_drop/lib/supply_drop/rsync.rb | 133 ++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 9 deletions(-) (limited to 'vendor') diff --git a/vendor/supply_drop/lib/supply_drop/rsync.rb b/vendor/supply_drop/lib/supply_drop/rsync.rb index 3030038..6d561ea 100644 --- a/vendor/supply_drop/lib/supply_drop/rsync.rb +++ b/vendor/supply_drop/lib/supply_drop/rsync.rb @@ -24,23 +24,138 @@ module SupplyDrop next unless value # - # for a list of the options normally support by Net::SSH (and thus Capistrano), see + # Convert Net::SSH options into OpenSSH options. + # + # For a list of the options normally support by Net::SSH (and thus Capistrano), see # http://net-ssh.github.com/net-ssh/classes/Net/SSH.html#method-c-start # + # Also, to see how Net::SSH does the opposite of the conversion we are doing here, check out: + # https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/config.rb + # + # API mismatch: + # + # * many OpenSSH options not supported + # * some options only make sense for Net::SSH + # * compression: for Net::SSH, this option is supposed to accept true, false, or algorithm. OpenSSH accepts 'yes' or 'no' + # + # case key - when :keys then [value].flatten.select { |k| File.exist?(k) }.map { |k| "-i #{k}" } - when :config then "-F #{value}" - when :port then "-p #{value}" - when :user_known_hosts_file then "-o 'UserKnownHostsFile=#{value}'" - when :global_known_hosts_file then "-o 'GlobalKnownHostsFile=#{value}'" - when :host_key_alias then "-o 'HostKeyAlias=#{value}'" - when :paranoid then "-o 'StrictHostKeyChecking=yes'" - when :host_name then "-o 'HostName=#{value}'" + when :auth_methods then opt_auth_methods(value) + when :bind_address then opt('BindAddress', value) + when :compression then opt('Compression', value ? 'yes' : 'no') + when :compression_level then opt('CompressionLevel', value.to_i) + when :config then "-F '#{value}'" + when :encryption then opt('Ciphers', [value].flatten.join(',')) + when :forward_agent then opt('ForwardAgent', value) + when :global_known_hosts_file then opt('GlobalKnownHostsFile', value) + when :hmac then opt('MACs', [value].flatten.join(',')) + when :host_key then opt('HostKeyAlgorithms', [value].flatten.join(',')) + when :host_key_alias then opt('HostKeyAlias', value) + when :host_name then opt('HostName', value) + when :kex then opt('KexAlgorithms', [value].flatten.join(',')) + when :key_data then nil # not supported + when :keys then [value].flatten.select { |k| File.exist?(k) }.map { |k| "-i #{k}" } + when :keys_only then opt('IdentitiesOnly', value ? 'yes' : 'no') + when :languages then nil # not applicable + when :logger then nil # not applicable + when :paranoid then opt('StrictHostKeyChecking', value ? 'yes' : 'no') + when :passphrase then nil # not supported + when :password then nil # not supported + when :port then "-p #{value.to_i}" + when :properties then nil # not applicable + when :proxy then nil # not applicable + when :rekey_blocks_limit then nil # not supported + when :rekey_limit then opt('RekeyLimit', reverse_interpret_size(value)) + when :rekey_packet_limit then nil # not supported + when :timeout then opt('ConnectTimeout', value.to_i) + when :user then "-l #{value}" + when :user_known_hosts_file then opt('UserKnownHostsFile', value) + when :verbose then opt('LogLevel', interpret_log_level(value)) end end.compact %[-e "ssh #{mapped_options.join(' ')}"] unless mapped_options.empty? end + + private + + def opt(option_name, option_value) + "-o #{option_name}='#{option_value}'" + end + + # + # In OpenSSH, password and pubkey default to 'yes', hostbased defaults to 'no'. + # Regardless, if :auth_method is configured, then we explicitly set the auth method. + # + def opt_auth_methods(value) + value = [value].flatten + opts = [] + if value.any? + if value.include? 'password' + opts << opt('PasswordAuthentication', 'yes') + else + opts << opt('PasswordAuthentication', 'no') + end + if value.include? 'publickey' + opts << opt('PubkeyAuthentication', 'yes') + else + opts << opt('PubkeyAuthentication', 'no') + end + if value.include? 'hostbased' + opts << opt('HostbasedAuthentication', 'yes') + else + opts << opt('HostbasedAuthentication', 'no') + end + end + if opts.any? + return opts.join(' ') + else + nil + end + end + + # + # Converts the given integer size in bytes into a string with 'K', 'M', 'G' suffix, as appropriate. + # + # reverse of interpret_size in https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/config.rb + # + def reverse_interpret_size(size) + size = size.to_i + if size < 1024 + "#{size}" + elsif size < 1024 * 1024 + "#{size/1024}K" + elsif size < 1024 * 1024 * 1024 + "#{size/(1024*1024)}M" + else + "#{size/(1024*1024*1024)}G" + end + end + + def interpret_log_level(level) + if level.is_a? Symbol + case level + when :debug then "DEBUG" + when :info then "INFO" + when :warn then "ERROR" + when :error then "ERROR" + when :fatal then "FATAL" + else "INFO" + end + elsif level.is_a? Integer + case level + when Logger::DEBUG then "DEBUG" + when Logger::INFO then "INFO" + when Logger::WARN then "ERROR" + when Logger::ERROR then "ERROR" + when Logger::FATAL then "FATAL" + else "INFO" + end + else + "INFO" + end + end + end end end -- cgit v1.2.3