lib/chef/provisioning/transport/ssh.rb in chef-provisioning-0.17 vs lib/chef/provisioning/transport/ssh.rb in chef-provisioning-0.18

- old
+ new

@@ -22,11 +22,13 @@ # - options: a hash of options for the transport itself, including: # - :prefix: a prefix to send before each command (e.g. "sudo ") # - :ssh_pty_enable: set to false to disable pty (some instances don't # support this, most do) # - :ssh_gateway: the gateway to use, e.g. "jkeiser@145.14.51.45:222". - # nil (the default) means no gateway. + # nil (the default) means no gateway. If the username is omitted, + # then the default username is used instead (i.e. the user running + # chef, or the username configured in .ssh/config). # - global_config: an options hash that looks suspiciously similar to # Chef::Config, containing at least the key :log_level. # # The options are used in # Net::SSH.start(host, username, ssh_options) @@ -278,12 +280,14 @@ options.key?(:ssh_gateway) and ! options[:ssh_gateway].nil? end def gateway gw_user, gw_host = options[:ssh_gateway].split('@') + # If we didn't have an '@' in the above, then the value is actually + # the hostname, not the username. + gw_host, gw_user = gw_user, gw_host if gw_host.nil? gw_host, gw_port = gw_host.split(':') - gw_user = ssh_options[:ssh_username] unless gw_user ssh_start_opts = { timeout:10 }.merge(ssh_options) ssh_start_opts[:port] = gw_port || 22 Chef::Log.debug("Opening SSH gateway to #{gw_user}@#{gw_host} with options #{ssh_start_opts.dup.tap { @@ -308,25 +312,37 @@ # Forwards a port over the connection, and returns the def forward_port(local_port, local_host, remote_port, remote_host) # This bit is from the documentation. if session.forward.respond_to?(:active_remote_destinations) - got_remote_port, remote_host = session.forward.active_remote_destinations[[local_port, local_host]] - if !got_remote_port + # active_remote_destinations tells us exactly what remotes the current + # ssh session is *actually* tracking. If multiple people share this + # session and set up their own remotes, this will prevent us from + # overwriting them. + + actual_remote_port, actual_remote_host = session.forward.active_remote_destinations[[local_port, local_host]] + if !actual_remote_port Chef::Log.debug("Forwarding local server #{local_host}:#{local_port} to #{username}@#{self.host}") - session.forward.remote(local_port, local_host, remote_port, remote_host) do |actual_remote_port| - got_remote_port = actual_remote_port || :error + session.forward.remote(local_port, local_host, remote_port, remote_host) do |new_remote_port, new_remote_host| + actual_remote_host = new_remote_host + actual_remote_port = new_remote_port || :error :no_exception # I'll take care of it myself, thanks end # Kick SSH until we get a response - session.loop { !got_remote_port } - if got_remote_port == :error + session.loop { !actual_remote_port } + if actual_remote_port == :error return nil end end - [ got_remote_port, remote_host ] + [ actual_remote_port, actual_remote_host ] else + # If active_remote_destinations isn't on net-ssh, we stash our own list + # of ports *we* have forwarded on the connection, and hope that we are + # right. + # TODO let's remove this when net-ssh 2.9.2 is old enough, and + # bump the required net-ssh version. + @forwarded_ports ||= {} remote_port, remote_host = @forwarded_ports[[local_port, local_host]] if !remote_port Chef::Log.debug("Forwarding local server #{local_host}:#{local_port} to #{username}@#{self.host}") old_active_remotes = session.forward.active_remotes