Hello community, here is the log from the commit of package rubygem-sshkit for openSUSE:Factory checked in at 2016-05-29 03:11:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-sshkit (Old) and /work/SRC/openSUSE:Factory/.rubygem-sshkit.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "rubygem-sshkit" Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-sshkit/rubygem-sshkit.changes 2016-04-28 16:53:05.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-sshkit.new/rubygem-sshkit.changes 2016-05-29 03:12:35.000000000 +0200 @@ -1,0 +2,20 @@ +Sat Apr 23 04:36:00 UTC 2016 - coolo@suse.com + +- updated to version 1.10.0 + see installed CHANGELOG.md + + ## 1.10.0 (2016-04-22) + + * You can now opt-in to caching of SSH's known_hosts file for a speed boost + when deploying to a large fleet of servers. Refer to the + [README](https://github.com/capistrano/sshkit#known-hosts-caching) for + details. We plan to turn this on by default in a future version of SSHKit. + [PR #330](https://github.com/capistrano/sshkit/pull/330) @byroot + * SSHKit now explicitly closes its pooled SSH connections when Ruby exits; + this fixes `zlib(finalizer): the stream was freed prematurely` warnings + [PR #343](https://github.com/capistrano/sshkit/pull/343) @mattbrictson + * Allow command map entries (`SSHKit::CommandMap#[]`) to be Procs + [PR #310](https://github.com/capistrano/sshkit/pull/310) + @mikz + +------------------------------------------------------------------- Old: ---- sshkit-1.9.0.gem New: ---- sshkit-1.10.0.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-sshkit.spec ++++++ --- /var/tmp/diff_new_pack.igOXgI/_old 2016-05-29 03:12:36.000000000 +0200 +++ /var/tmp/diff_new_pack.igOXgI/_new 2016-05-29 03:12:36.000000000 +0200 @@ -24,7 +24,7 @@ # Name: rubygem-sshkit -Version: 1.9.0 +Version: 1.10.0 Release: 0 %define mod_name sshkit %define mod_full_name %{mod_name}-%{version} ++++++ sshkit-1.9.0.gem -> sshkit-1.10.0.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md --- old/CHANGELOG.md 2016-03-10 18:00:42.000000000 +0100 +++ new/CHANGELOG.md 2016-04-22 19:56:55.000000000 +0200 @@ -8,6 +8,20 @@ * Add your entries below here, remember to credit yourself however you want to be credited! +## 1.10.0 (2016-04-22) + + * You can now opt-in to caching of SSH's known_hosts file for a speed boost + when deploying to a large fleet of servers. Refer to the + [README](https://github.com/capistrano/sshkit#known-hosts-caching) for + details. We plan to turn this on by default in a future version of SSHKit. + [PR #330](https://github.com/capistrano/sshkit/pull/330) @byroot + * SSHKit now explicitly closes its pooled SSH connections when Ruby exits; + this fixes `zlib(finalizer): the stream was freed prematurely` warnings + [PR #343](https://github.com/capistrano/sshkit/pull/343) @mattbrictson + * Allow command map entries (`SSHKit::CommandMap#[]`) to be Procs + [PR #310](https://github.com/capistrano/sshkit/pull/310) + @mikz + ## 1.9.0 **Refer to the 1.9.0.rc1 release notes for a full list of new features, fixes, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.md new/README.md --- old/README.md 2016-03-10 18:00:42.000000000 +0100 +++ new/README.md 2016-04-22 19:56:55.000000000 +0200 @@ -508,6 +508,19 @@ SSHKit::Backend::Netssh.pool.idle_timeout = 0 # disabled ``` +## Known hosts caching + +If you connect to many hosts with the `Netssh` backend, looking up `~/.ssh/known_hosts` can significantly impact performances. +You can mitigate this by using SSHKit's lookup caching like this: + +```ruby +SSHKit::Backend::Netssh.configure do |ssh| + ssh.ssh_options = { + known_hosts: SSHKit::Backend::Netssh::KnownHosts.new, + } +end +``` + ## Tunneling and other related SSH themes In order to do special gymnasitcs with SSH, tunneling, aliasing, complex options, etc with SSHKit it is possible to use [the underlying Net::SSH API](https://github.com/capistrano/sshkit/blob/master/EXAMPLES.md#setting-global-...) however in many cases it is preferred to use the system SSH configuration file at [`~/.ssh/config`](http://man.cx/ssh_config). This allows you to have personal configuration tied to your machine that does not have to be committed with the repository. If this is not suitable (everyone on the team needs a proxy command, or some special aliasing) a file in the same format can be placed in the project directory at `~/yourproject/.ssh/config`, this will be merged with the system settings in `~/.ssh/config`, and with any configuration specified in [`SSHKit::Backend::Netssh.config.ssh_options`](https://github.com/capistrano/sshkit/blob/master/lib/sshkit/backends/netssh....). Files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/all.rb new/lib/sshkit/all.rb --- old/lib/sshkit/all.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit/all.rb 2016-04-22 19:56:55.000000000 +0200 @@ -35,5 +35,6 @@ require_relative 'backends/connection_pool' require_relative 'backends/printer' require_relative 'backends/netssh' +require_relative 'backends/netssh/known_hosts' require_relative 'backends/local' require_relative 'backends/skipper' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/backends/connection_pool/cache.rb new/lib/sshkit/backends/connection_pool/cache.rb --- old/lib/sshkit/backends/connection_pool/cache.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit/backends/connection_pool/cache.rb 2016-04-22 19:56:55.000000000 +0200 @@ -53,10 +53,12 @@ end end - private + protected attr_reader :connections, :idle_timeout, :closer + private + def fresh?(expires_at) expires_at > Time.now end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/backends/connection_pool.rb new/lib/sshkit/backends/connection_pool.rb --- old/lib/sshkit/backends/connection_pool.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit/backends/connection_pool.rb 2016-04-22 19:56:55.000000000 +0200 @@ -78,10 +78,12 @@ end end - private + protected attr_reader :caches, :timed_out_connections + private + def cache_enabled? idle_timeout && idle_timeout > 0 end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/backends/netssh/known_hosts.rb new/lib/sshkit/backends/netssh/known_hosts.rb --- old/lib/sshkit/backends/netssh/known_hosts.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/sshkit/backends/netssh/known_hosts.rb 2016-04-22 19:56:55.000000000 +0200 @@ -0,0 +1,141 @@ +module SSHKit + + module Backend + + class Netssh < Abstract + + class KnownHostsKeys + include Mutex_m + + def initialize(path) + super() + @path = File.expand_path(path) + @hosts_keys = nil + end + + def keys_for(hostlist) + keys, hashes = hosts_keys, hosts_hashes + parse_file unless keys && hashes + keys, hashes = hosts_keys, hosts_hashes + + hostlist.split(',').each do |host| + key_list = keys[host] + return key_list if key_list + + hashes.each do |(hmac, salt), hash_keys| + if OpenSSL::HMAC.digest(sha1, salt, host) == hmac + return hash_keys + end + end + end + + [] + end + + private + + attr_reader :path + attr_accessor :hosts_keys, :hosts_hashes + + def sha1 + @sha1 ||= OpenSSL::Digest.new('sha1') + end + + def parse_file + synchronize do + return if hosts_keys && hosts_hashes + + unless File.readable?(path) + self.hosts_keys = {} + self.hosts_hashes = [] + return + end + + new_keys = {} + new_hashes = [] + File.open(path) do |file| + scanner = StringScanner.new("") + file.each_line do |line| + scanner.string = line + parse_line(scanner, new_keys, new_hashes) + end + end + self.hosts_keys = new_keys + self.hosts_hashes = new_hashes + end + end + + def parse_line(scanner, hosts_keys, hosts_hashes) + return if empty_line?(scanner) + + hostlist = parse_hostlist(scanner) + return unless supported_type?(scanner) + key = parse_key(scanner) + + if hostlist.size == 1 && hostlist.first =~ /\A\|1(\|.+){2}\z/ + hosts_hashes << [parse_host_hash(hostlist.first), key] + else + hostlist.each do |host| + (hosts_keys[host] ||= []) << key + end + end + end + + def parse_host_hash(line) + _, _, salt, hmac = line.split('|') + [Base64.decode64(hmac), Base64.decode64(salt)] + end + + def empty_line?(scanner) + scanner.skip(/\s*/) + scanner.match?(/$|#/) + end + + def parse_hostlist(scanner) + scanner.skip(/\s*/) + scanner.scan(/\S+/).split(',') + end + + def supported_type?(scanner) + scanner.skip(/\s*/) + Net::SSH::KnownHosts::SUPPORTED_TYPE.include?(scanner.scan(/\S+/)) + end + + def parse_key(scanner) + scanner.skip(/\s*/) + Net::SSH::Buffer.new(scanner.rest.unpack("m*").first).read_key + end + end + + class KnownHosts + include Mutex_m + + def initialize + super() + @files = {} + end + + def search_for(host, options = {}) + keys = ::Net::SSH::KnownHosts.hostfiles(options).map do |path| + known_hosts_file(path).keys_for(host) + end.flatten + ::Net::SSH::HostKeys.new(keys, host, self, options) + end + + def add(*args) + ::Net::SSH::KnownHosts.add(*args) + synchronize { @files = {} } + end + + private + + def known_hosts_file(path) + @files[path] || synchronize { @files[path] ||= KnownHostsKeys.new(path) } + end + end + + end + + end + +end \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/backends/netssh.rb new/lib/sshkit/backends/netssh.rb --- old/lib/sshkit/backends/netssh.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit/backends/netssh.rb 2016-04-22 19:56:55.000000000 +0200 @@ -1,3 +1,6 @@ +require 'English' +require 'strscan' +require 'mutex_m' require 'net/ssh' require 'net/scp' @@ -5,6 +8,8 @@ module SSH class Config class << self + remove_method :default_files + def default_files @@default_files + [File.join(Dir.pwd, '.ssh/config')] end @@ -18,13 +23,12 @@ module Backend class Netssh < Abstract - class Configuration attr_accessor :connection_timeout, :pty attr_writer :ssh_options def ssh_options - @ssh_options || {} + @ssh_options ||= {} end end @@ -42,7 +46,12 @@ end end + # Note that this pool must be explicitly closed before Ruby exits to + # ensure the underlying IO objects are properly cleaned up. We register an + # at_exit handler to do this automatically, as long as Ruby is exiting + # cleanly (i.e. without an exception). @pool = SSHKit::Backend::ConnectionPool.new + at_exit { @pool.close_connections if @pool && !$ERROR_INFO } class << self attr_accessor :pool diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/command_map.rb new/lib/sshkit/command_map.rb --- old/lib/sshkit/command_map.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit/command_map.rb 2016-04-22 19:56:55.000000000 +0200 @@ -31,18 +31,20 @@ end end + TO_VALUE = ->(obj) { obj.respond_to?(:call) ? obj.call : obj } + def initialize(value = nil) @map = CommandHash.new(value || defaults) end def [](command) if prefix[command].any? - prefixes = prefix[command].map{ |prefix| prefix.respond_to?(:call) ? prefix.call : prefix } + prefixes = prefix[command].map(&TO_VALUE) prefixes = prefixes.join(" ") "#{prefixes} #{command}" else - @map[command] + TO_VALUE.(@map[command]) end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/configuration.rb new/lib/sshkit/configuration.rb --- old/lib/sshkit/configuration.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit/configuration.rb 2016-04-22 19:56:55.000000000 +0200 @@ -2,7 +2,7 @@ class Configuration - attr_accessor :umask, :output_verbosity + attr_accessor :umask attr_writer :output, :backend, :default_env, :default_runner def output diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/host.rb new/lib/sshkit/host.rb --- old/lib/sshkit/host.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit/host.rb 2016-04-22 19:56:55.000000000 +0200 @@ -99,7 +99,7 @@ class SimpleHostParser def self.suitable?(host_string) - !host_string.match(/[:|@]/) + !host_string.match(/:|@/) end def initialize(host_string) @@ -127,7 +127,7 @@ class HostWithPortParser < SimpleHostParser def self.suitable?(host_string) - !host_string.match(/[@|\[|\]]/) + !host_string.match(/@|\[|\]/) end def port diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit/version.rb new/lib/sshkit/version.rb --- old/lib/sshkit/version.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit/version.rb 2016-04-22 19:56:55.000000000 +0200 @@ -1,3 +1,3 @@ module SSHKit - VERSION = "1.9.0" + VERSION = "1.10.0".freeze end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sshkit.rb new/lib/sshkit.rb --- old/lib/sshkit.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/lib/sshkit.rb 2016-04-22 19:56:55.000000000 +0200 @@ -4,7 +4,7 @@ class << self - attr_accessor :config + attr_writer :config def configure @@config ||= Configuration.new diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2016-03-10 18:00:42.000000000 +0100 +++ new/metadata 2016-04-22 19:56:55.000000000 +0200 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: sshkit version: !ruby/object:Gem::Version - version: 1.9.0 + version: 1.10.0 platform: ruby authors: - Lee Hambley @@ -9,7 +9,7 @@ autorequire: bindir: bin cert_chain: [] -date: 2016-03-10 00:00:00.000000000 Z +date: 2016-04-22 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: net-ssh @@ -158,6 +158,7 @@ - lib/sshkit/backends/connection_pool/nil_cache.rb - lib/sshkit/backends/local.rb - lib/sshkit/backends/netssh.rb +- lib/sshkit/backends/netssh/known_hosts.rb - lib/sshkit/backends/printer.rb - lib/sshkit/backends/skipper.rb - lib/sshkit/color.rb @@ -189,6 +190,8 @@ - test/functional/backends/test_netssh.rb - test/functional/test_ssh_server_comes_up_for_functional_tests.rb - test/helper.rb +- test/known_hosts/github +- test/known_hosts/github_hash - test/support/vagrant_wrapper.rb - test/unit/backends/test_abstract.rb - test/unit/backends/test_connection_pool.rb @@ -230,7 +233,7 @@ version: '0' requirements: [] rubyforge_project: -rubygems_version: 2.6.1 +rubygems_version: 2.6.2 signing_key: specification_version: 4 summary: SSHKit makes it easy to write structured, testable SSH commands in Ruby @@ -240,6 +243,8 @@ - test/functional/backends/test_netssh.rb - test/functional/test_ssh_server_comes_up_for_functional_tests.rb - test/helper.rb +- test/known_hosts/github +- test/known_hosts/github_hash - test/support/vagrant_wrapper.rb - test/unit/backends/test_abstract.rb - test/unit/backends/test_connection_pool.rb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/known_hosts/github new/test/known_hosts/github --- old/test/known_hosts/github 1970-01-01 01:00:00.000000000 +0100 +++ new/test/known_hosts/github 2016-04-22 19:56:55.000000000 +0200 @@ -0,0 +1 @@ +github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/known_hosts/github_hash new/test/known_hosts/github_hash --- old/test/known_hosts/github_hash 1970-01-01 01:00:00.000000000 +0100 +++ new/test/known_hosts/github_hash 2016-04-22 19:56:55.000000000 +0200 @@ -0,0 +1 @@ +|1|eKp+6E0rZ3lONgsIziurXEnaIik=|rcQB/rlJMUquUyFta64KugPjX4o= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/unit/backends/test_netssh.rb new/test/unit/backends/test_netssh.rb --- old/test/unit/backends/test_netssh.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/test/unit/backends/test_netssh.rb 2016-04-22 19:56:55.000000000 +0200 @@ -1,4 +1,5 @@ require 'helper' +require 'tempfile' module SSHKit module Backend @@ -53,6 +54,29 @@ end end + if Net::SSH::Version::CURRENT >= Net::SSH::Version[3, 1, 0] + def test_known_hosts_for_when_all_hosts_are_recognized + perform_known_hosts_test("github") + end + + def test_known_hosts_for_when_an_host_hash_is_recognized + perform_known_hosts_test("github_hash") + end + end + + private + + def perform_known_hosts_test(hostfile) + source = File.join(File.dirname(__FILE__), '../../known_hosts', hostfile) + kh = Netssh::KnownHosts.new + keys = kh.search_for('github.com', user_known_hosts_file: source, global_known_hosts_file: Tempfile.new('sshkit-test').path) + + assert_instance_of ::Net::SSH::HostKeys, keys + assert_equal(1, keys.count) + keys.each do |key| + assert_equal("ssh-rsa", key.ssh_type) + end + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/unit/test_command_map.rb new/test/unit/test_command_map.rb --- old/test/unit/test_command_map.rb 2016-03-10 18:00:42.000000000 +0100 +++ new/test/unit/test_command_map.rb 2016-04-22 19:56:55.000000000 +0200 @@ -16,6 +16,15 @@ assert_equal map[:rake], "/usr/local/rbenv/shims/rake" end + def test_setter_procs + map = CommandMap.new + i = 0 + map[:rake] = -> { i += 1; "/usr/local/rbenv/shims/rake#{i}" } + + assert_equal map[:rake], "/usr/local/rbenv/shims/rake1" + assert_equal map[:rake], "/usr/local/rbenv/shims/rake2" + end + def test_prefix map = CommandMap.new map.prefix[:rake].push("/home/vagrant/.rbenv/bin/rbenv exec")