]> gitweb.fluxo.info Git - leap/leap_cli.git/commitdiff
more complete rsync compatibility with Net::SSH options
authorelijah <elijah@riseup.net>
Thu, 1 Nov 2012 08:08:04 +0000 (01:08 -0700)
committerelijah <elijah@riseup.net>
Thu, 1 Nov 2012 08:08:04 +0000 (01:08 -0700)
vendor/supply_drop/lib/supply_drop/rsync.rb

index 30300380d3ee7df66f8d3f30b4a8f583f0c0a575..6d561ea20b22cc66f0cc88938d10574303e3f462 100644 (file)
@@ -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