diff options
-rw-r--r-- | .travis.yml | 17 | ||||
-rw-r--r-- | CHANGES.txt | 5 | ||||
-rw-r--r-- | README.rdoc | 2 | ||||
-rw-r--r-- | Rakefile | 10 | ||||
-rw-r--r-- | gem-public_cert.pem | 36 | ||||
-rw-r--r-- | lib/net/ssh/multi/pending_connection.rb | 22 | ||||
-rw-r--r-- | lib/net/ssh/multi/server.rb | 2 | ||||
-rw-r--r-- | lib/net/ssh/multi/session.rb | 11 | ||||
-rw-r--r-- | lib/net/ssh/multi/session_actions.rb | 4 | ||||
-rw-r--r-- | lib/net/ssh/multi/version.rb | 10 | ||||
-rw-r--r-- | net-ssh-multi.gemspec | 16 | ||||
-rw-r--r-- | test/channel_test.rb | 2 | ||||
-rw-r--r-- | test/session_actions_test.rb | 2 | ||||
-rw-r--r-- | test/session_test.rb | 21 |
14 files changed, 124 insertions, 36 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b520c8f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +language: ruby +sudo: false +rvm: + - 2.0.0 + - 2.1.0 + - 2.2.0 + - 2.3.0 + - jruby-head + - rbx-2 + +install: gem install test-unit mocha net-ssh net-ssh-gateway + +script: rake test + +matrix: + allow_failures: + - rvm: jruby-head diff --git a/CHANGES.txt b/CHANGES.txt index 48d94ab..92be5cd 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +=== 1.3.0.rc1 / 12 Mar 2016 + +* Make sure we wait no more than keeepalive in select [Eugene Kenny] +* Forward action [Yukihiko SAWANOBORI] +* Net-ssh 3.0 compatibility [Balasankar C] === 1.2.1 / 11 Apr 2015 diff --git a/README.rdoc b/README.rdoc index f45918e..1187637 100644 --- a/README.rdoc +++ b/README.rdoc @@ -66,7 +66,7 @@ If you want to run the tests or use any of the Rake tasks, you'll need: * gem install net-ssh-multi -However, in order to be sure the code you're installing hasn't been tampered with, it's recommended that you verify the signiture[http://docs.rubygems.org/read/chapter/21]. To do this, you need to add my public key as a trusted certificate (you only need to do this once): +However, in order to be sure the code you're installing hasn't been tampered with, it's recommended that you verify the signature[http://docs.rubygems.org/read/chapter/21]. To do this, you need to add my public key as a trusted certificate (you only need to do this once): # Add the public key as a trusted certificate # (You only need to do this once) @@ -31,8 +31,14 @@ begin s.license = "MIT" - s.signing_key = File.join('/mnt/gem/', 'gem-private_key.pem') - s.cert_chain = ['gem-public_cert.pem'] + unless ENV['NET_SSH_NOKEY'] + signing_key = File.join('/mnt/gem/', 'net-ssh-private_key.pem') + s.signing_key = signing_key + s.cert_chain = ['gem-public_cert.pem'] + unless (Rake.application.top_level_tasks & ['build','install']).empty? + raise "No key found at #{signing_key} for signing, use rake <taskname> NET_SSH_NOKEY=1 to build without key" unless File.exist?(signing_key) + end + end end Jeweler::GemcutterTasks.new rescue LoadError diff --git a/gem-public_cert.pem b/gem-public_cert.pem index 1bda370..ffa10de 100644 --- a/gem-public_cert.pem +++ b/gem-public_cert.pem @@ -1,20 +1,20 @@ -----BEGIN CERTIFICATE----- -MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMQ8wDQYDVQQDDAZkZWxh -bm8xGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZFgNj -b20wHhcNMTMwMjA2MTE1NzQ1WhcNMTQwMjA2MTE1NzQ1WjBBMQ8wDQYDVQQDDAZk -ZWxhbm8xGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZ -FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDg1hMtl0XsMuUK -AKTgYWv3gjj7vuEsE2EjT+vyBg8/LpqVVwZziiaebJT9IZiQ+sCFqbiakj0b53pI -hg1yOaBEmH6/W0L7rwzqaRV9sW1eJs9JxFYQCnd67zUnzj8nnRlOjG+hhIG+Vsij -npsGbt28pefuNZJjO5q2clAlfSniIIHfIsU7/StEYu6FUGOjnwryZ0r5yJlr9RrE -Gs+q0DW8QnZ9UpAfuDFQZuIqeKQFFLE7nMmCGaA+0BN1nLl3fVHNbLHq7Avk8+Z+ -ZuuvkdscbHlO/l+3xCNQ5nUnHwq0ADAbMLOlmiYYzqXoWLjmeI6me/clktJCfN2R -oZG3UQvvAgMBAAGjOTA3MAkGA1UdEwQCMAAwHQYDVR0OBBYEFMSJOEtHzE4l0azv -M0JK0kKNToK1MAsGA1UdDwQEAwIEsDANBgkqhkiG9w0BAQUFAAOCAQEAtOdE73qx -OH2ydi9oT2hS5f9G0y1Z70Tlwh+VGExyfxzVE9XwC+iPpJxNraiHYgF/9/oky7ZZ -R9q0/tJneuhAenZdiQkX7oi4O3v9wRS6YHoWBxMPFKVRLNTzvVJsbmfpCAlp5/5g -ps4wQFy5mibElGVlOobf/ghqZ25HS9J6kd0/C/ry0AUtTogsL7TxGwT4kbCx63ub -3vywEEhsJUzfd97GCABmtQfRTldX/j7F1z/5wd8p+hfdox1iibds9ZtfaZA3KzKn -kchWN9B6zg9r1XMQ8BM2Jz0XoPanPe354+lWwjpkRKbFow/ZbQHcCLCq24+N6b6g -dgKfNDzwiDpqCA== +MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAduZXQt +c3NoMRkwFwYKCZImiZPyLGQBGRYJc29sdXRpb3VzMRMwEQYKCZImiZPyLGQBGRYD +Y29tMB4XDTE1MTIwNjIxMDYyNFoXDTE2MTIwNTIxMDYyNFowQjEQMA4GA1UEAwwH +bmV0LXNzaDEZMBcGCgmSJomT8ixkARkWCXNvbHV0aW91czETMBEGCgmSJomT8ixk +ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMYnhNtn0f6p +nTylB8mE8lMdoMLJC8KwpMWsvk73Pe2WVDsH/OSwwwz6oUGk1i70cJyDjIEBNpwT +88GpVXJSumvqVsf9fCg3mWNeb5t0J+aeNm9MIvYVMTqj5tydoXQiwnILRDYHV9tZ +1c3o59/VlahSTpZ7YEgzVufpAkvEGkbJiG849exiipK7MN/ZIkMOxYVnyRXk43Xc +6GYlsHOfSgPwcXwW5g57DCwLQLWrjDsTka28dxDmO7B5Lv5EqzINxVxWsu43OgZG +21Io/jIyf5PNpeKPKNGDuAQJ8mvdMYBJoDhtCwgsUYbl0BZzA7g4ytl51HtIeP+j +Qp/eAvs/RrECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUBfKiwO2eM4NE +iRrVG793qEPLYyMwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQCfZFdb +p4jzkfIzGDbiOxd0R8sdqJoC4nMLEgnQ7dLulawwA3IXe3sHAKgA5kmH3prsKc5H +zVmM5NlH2P1nRbegIkQTYiIod1hZQCNxdmVG/fprMqPq0ybpUOjjrP5pj0OtszE1 +F2dQia1hOEstMR+n0nAtWII9HJAEyeZjVV0s2Cl7Pt85XJ3hxFcCKwzqsK5xRI7a +B3vwh3/JJYrFonIohQ//Lg9qTZASEkoKLlq1/hFeICoCGGIGLq45ZB7CzXLooCKi +s/ZUKye79ELwFYKJOhjW5g725OL3hy+llhEleytwKRwgXFQBPTC4f5UkdxZVVWGH +e2C9M1m/2odPZo8h -----END CERTIFICATE----- diff --git a/lib/net/ssh/multi/pending_connection.rb b/lib/net/ssh/multi/pending_connection.rb index 6af0fac..5faaf70 100644 --- a/lib/net/ssh/multi/pending_connection.rb +++ b/lib/net/ssh/multi/pending_connection.rb @@ -31,6 +31,28 @@ module Net; module SSH; module Multi end end + # Represents a #forward action. + class ForwardRecording + def initialize + @recordings = [] + end + + def remote(port, host, remote_port, remote_host="127.0.0.1") + @recordings << [:remote, port, host, remote_port, remote_host] + end + + def replay_on(session) + forward = session.forward + @recordings.each { |args| forward.send(*args) } + end + end + + def forward + forward = ForwardRecording.new + @recordings << forward + forward + end + # Represents a #send_global_request action. class SendGlobalRequestRecording #:nodoc: attr_reader :type, :extra, :callback diff --git a/lib/net/ssh/multi/server.rb b/lib/net/ssh/multi/server.rb index 77c5948..bcf3678 100644 --- a/lib/net/ssh/multi/server.rb +++ b/lib/net/ssh/multi/server.rb @@ -1,4 +1,5 @@ require 'net/ssh' +require 'timeout' module Net; module SSH; module Multi # Encapsulates the connection information for a single remote server, as well @@ -55,6 +56,7 @@ module Net; module SSH; module Multi @gateway = @options.delete(:via) @failed = false + @session = @ready_session = nil end # Returns the value of the server property with the given +key+. Server diff --git a/lib/net/ssh/multi/session.rb b/lib/net/ssh/multi/session.rb index 2e2468f..409aeae 100644 --- a/lib/net/ssh/multi/session.rb +++ b/lib/net/ssh/multi/session.rb @@ -425,7 +425,7 @@ module Net; module SSH; module Multi # +false+ (the block returned +false+). def process(wait=nil, &block) realize_pending_connections! - wait = @connect_threads.any? ? 0 : wait + wait = @connect_threads.any? ? 0 : io_select_wait(wait) return false unless preprocess(&block) @@ -441,6 +441,15 @@ module Net; module SSH; module Multi end end + def io_select_wait(wait) + [wait, keepalive_interval].compact.min + end + + def keepalive_interval + servers = server_list.select { |s| s.options[:keepalive] } + servers.map { |s| s.options[:keepalive_interval] }.compact.min + end + # Runs the preprocess stage on all servers. Returns false if the block # returns false, and true if there either is no block, or it returns true. # This is called as part of the #process method. diff --git a/lib/net/ssh/multi/session_actions.rb b/lib/net/ssh/multi/session_actions.rb index 2d87392..c6b1355 100644 --- a/lib/net/ssh/multi/session_actions.rb +++ b/lib/net/ssh/multi/session_actions.rb @@ -118,8 +118,8 @@ module Net; module SSH; module Multi # end def exec(command, &block) open_channel do |channel| - channel.exec(command) do |ch, success| - raise "could not execute command: #{command.inspect} (#{ch[:host]})" unless success + channel.exec(command) do |c, success| + raise "could not execute command: #{command.inspect} (#{c[:host]})" unless success channel.on_data do |ch, data| if block diff --git a/lib/net/ssh/multi/version.rb b/lib/net/ssh/multi/version.rb index 9854f32..c2f085e 100644 --- a/lib/net/ssh/multi/version.rb +++ b/lib/net/ssh/multi/version.rb @@ -7,13 +7,17 @@ module Net; module SSH; module Multi MAJOR = 1 # The minor component of the library's version - MINOR = 2 + MINOR = 3 # The tiny component of the library's version - TINY = 1 + TINY = 0 + + # The prerelease component of this version of the Net::SSH library + # nil allowed + PRE = "rc1" # The library's version as a Version instance - CURRENT = new(MAJOR, MINOR, TINY) + CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact) # The library's version as a String instance STRING = CURRENT.to_s diff --git a/net-ssh-multi.gemspec b/net-ssh-multi.gemspec index 5b3bbe7..fb7ade3 100644 --- a/net-ssh-multi.gemspec +++ b/net-ssh-multi.gemspec @@ -2,15 +2,17 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- +# stub: net-ssh-multi 1.3.0.rc1 ruby lib Gem::Specification.new do |s| s.name = "net-ssh-multi" - s.version = "1.2.1" + s.version = "1.3.0.rc1" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib"] s.authors = ["Jamis Buck", "Delano Mandelbaum"] s.cert_chain = ["gem-public_cert.pem"] - s.date = "2015-04-11" + s.date = "2016-03-24" s.description = "Control multiple Net::SSH connections via a single interface." s.email = "net-ssh@solutious.com" s.extra_rdoc_files = [ @@ -18,6 +20,7 @@ Gem::Specification.new do |s| "README.rdoc" ] s.files = [ + ".travis.yml", "CHANGES.txt", "LICENSE.txt", "README.rdoc", @@ -45,14 +48,13 @@ Gem::Specification.new do |s| ] s.homepage = "https://github.com/net-ssh/net-scp" s.licenses = ["MIT"] - s.require_paths = ["lib"] s.rubyforge_project = "net-ssh-multi" - s.rubygems_version = "1.8.23" - s.signing_key = "/mnt/gem/gem-private_key.pem" + s.rubygems_version = "2.4.6" + s.signing_key = "/mnt/gem/net-ssh-private_key.pem" s.summary = "Control multiple Net::SSH connections via a single interface." if s.respond_to? :specification_version then - s.specification_version = 3 + s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q<net-ssh>, [">= 2.6.5"]) diff --git a/test/channel_test.rb b/test/channel_test.rb index 2c08573..475c59b 100644 --- a/test/channel_test.rb +++ b/test/channel_test.rb @@ -3,7 +3,7 @@ require 'net/ssh/multi/channel' class ChannelTest < Minitest::Test def test_each_should_iterate_over_each_component_channel - channels = [c1 = mock('channel'), c2 = mock('channel'), c3 = mock('channel')] + channels = [mock('channel'), mock('channel'), mock('channel')] channel = Net::SSH::Multi::Channel.new(mock('session'), channels) result = [] channel.each { |c| result << c } diff --git a/test/session_actions_test.rb b/test/session_actions_test.rb index e6de5b1..c9e29d6 100644 --- a/test/session_actions_test.rb +++ b/test/session_actions_test.rb @@ -94,7 +94,7 @@ class SessionActionsTest < Minitest::Test c.expects(:on_extended_data).yields(c, 1, "stderr") c.expects(:on_request) results = {} - @session.exec("something") do |c, stream, data| + @session.exec("something") do |_, stream, data| results[stream] = data end assert_equal({:stdout => "stdout", :stderr => "stderr"}, results) diff --git a/test/session_test.rb b/test/session_test.rb index 42a56b2..c027db9 100644 --- a/test/session_test.rb +++ b/test/session_test.rb @@ -198,4 +198,25 @@ class SessionTest < Minitest::Test IO.expects(:select).with([:a, :b, :c], [:a, :c], nil, 5).returns([[:b, :c], [:a, :c]]) @session.process(5) end + + def test_process_should_pass_minimum_keepalive_interval_as_io_select_timeout + @session.use('h1', :keepalive => true) + @session.use('h2', :keepalive_interval => 1) + @session.use('h3', :keepalive => true, :keepalive_interval => 2) + @session.use('h4', :keepalive => true, :keepalive_interval => 3) + IO.expects(:select).with([], [], nil, 2) + @session.process + end + + def test_process_should_pass_wait_as_io_select_timeout_if_provided_and_minimum + @session.use('h1', :keepalive => true, :keepalive_interval => 1) + IO.expects(:select).with([], [], nil, 1) + @session.process(2) + end + + def test_process_should_pass_nil_as_io_select_timeout_by_default + @session.use('h1') + IO.expects(:select).with([], [], nil, nil) + @session.process + end end |