From 25e78a550c34239a2542e8eaf056813702d3174b Mon Sep 17 00:00:00 2001 From: Kerry Buckley Date: Fri, 22 Aug 2008 14:03:17 +0100 Subject: [PATCH] Allow gateway to be specified as an array, in which case a chain of tunnels is created --- lib/capistrano/configuration/connections.rb | 18 +++++++++++----- test/configuration/connections_test.rb | 28 ++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 11 deletions(-) mode change 100644 => 100755 lib/capistrano/configuration/connections.rb diff --git a/lib/capistrano/configuration/connections.rb b/lib/capistrano/configuration/connections.rb old mode 100644 new mode 100755 index 3d26345..ee60af7 --- a/lib/capistrano/configuration/connections.rb +++ b/lib/capistrano/configuration/connections.rb @@ -23,21 +23,27 @@ module Capistrano class GatewayConnectionFactory #:nodoc: def initialize(gateway, options) - Thread.abort_on_exception = true - server = ServerDefinition.new(gateway) - @options = options - @gateway = SSH.connection_strategy(server, options) do |host, user, connect_options| + @options[:logger].debug "Creating gateway using #{[*gateway].join(', ')}" if @options[:logger] + Thread.abort_on_exception = true + @gateways = [*gateway].collect { |g| ServerDefinition.new(g) } + tunnel = SSH.connection_strategy(@gateways[0], @options) do |host, user, connect_options| Net::SSH::Gateway.new(host, user, connect_options) end + @gateway = (@gateways[1..-1]).inject(tunnel) do |tunnel, destination| + @options[:logger].debug "Creating tunnel to #{destination}" if @options[:logger] + local_host = ServerDefinition.new("127.0.0.1", :user => destination.user, :port => tunnel.open(destination.host, (destination.port || 22))) + SSH.connection_strategy(local_host, @options) do |host, user, connect_options| + Net::SSH::Gateway.new(host, user, connect_options) + end + end end - + def connect_to(server) @options[:logger].debug "establishing connection to `#{server}' via gateway" if @options[:logger] local_host = ServerDefinition.new("127.0.0.1", :user => server.user, :port => @gateway.open(server.host, server.port || 22)) session = SSH.connect(local_host, @options) session.xserver = server - @options[:logger].trace "connected: `#{server}' (via gateway)" if @options[:logger] session end end diff --git a/test/configuration/connections_test.rb b/test/configuration/connections_test.rb index ba9b28d..554d380 100644 --- a/test/configuration/connections_test.rb +++ b/test/configuration/connections_test.rb @@ -58,18 +58,36 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase assert_equal :session, @config.connection_factory.connect_to(server) end - def test_connection_factory_should_return_gateway_instance_if_gateway_variable_is_set - @config.values[:gateway] = "j@capistrano" - Net::SSH::Gateway.expects(:new).with("capistrano", "j", :password => nil, :auth_methods => %w(publickey hostbased)).returns(stub_everything) + def test_should_connect_through_gateway_if_gateway_variable_is_set + @config.values[:gateway] = "j@gateway" + Net::SSH::Gateway.expects(:new).with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased)).returns(stub_everything) assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory end def test_connection_factory_as_gateway_should_honor_config_options - @config.values[:gateway] = "capistrano" + @config.values[:gateway] = "gateway" @config.values.update(@ssh_options) - Net::SSH::Gateway.expects(:new).with("capistrano", "user", :debug => :verbose, :port => 8080, :password => nil, :auth_methods => %w(publickey hostbased)).returns(stub_everything) + Net::SSH::Gateway.expects(:new).with("gateway", "user", :debug => :verbose, :port => 8080, :password => nil, :auth_methods => %w(publickey hostbased)).returns(stub_everything) assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory end + + def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable_is_an_array + @config.values[:gateway] = ["j@gateway1", "k@gateway2"] + gateway1 = mock + Net::SSH::Gateway.expects(:new).with("gateway1", "j", :password => nil, :auth_methods => %w(publickey hostbased)).returns(gateway1) + gateway1.expects(:open).returns(65535) + Net::SSH::Gateway.expects(:new).with("127.0.0.1", "k", :port => 65535, :password => nil, :auth_methods => %w(publickey hostbased)).returns(stub_everything) + assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory + end + + def test_connection_factory_as_gateway_should_share_gateway_between_connections + @config.values[:gateway] = "j@gateway" + Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased)).returns(stub_everything) + Capistrano::SSH.stubs(:connect).returns(stub_everything) + assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory + @config.establish_connections_to(server("capistrano")) + @config.establish_connections_to(server("another")) + end def test_establish_connections_to_should_accept_a_single_nonarray_parameter Capistrano::SSH.expects(:connect).with { |s,| s.host == "capistrano" }.returns(:success) -- 1.5.6.5