Class: Train::Transports::SSH::Connection
- Inherits:
-
BaseConnection
- Object
- BaseConnection
- Train::Transports::SSH::Connection
- Defined in:
- lib/train/transports/ssh_connection.rb
Overview
A Connection instance can be generated and re-generated, given new connection details such as connection port, hostname, credentials, etc. This object is responsible for carrying out the actions on the remote host such as executing commands, transferring files, etc.
Instance Attribute Summary collapse
-
#hostname ⇒ Object
readonly
rubocop:disable Metrics/ClassLength.
Instance Method Summary collapse
- #check_proxy ⇒ Object
- #close ⇒ Object
- #download(remotes, local) ⇒ Object
- #generate_proxy_command ⇒ Object
-
#initialize(options) ⇒ Connection
constructor
A new instance of Connection.
- #login_command ⇒ Object
- #ssh_opts ⇒ Object
- #upload(locals, remote) ⇒ Object
- #uri ⇒ Object
- #wait_until_ready ⇒ Object
Constructor Details
#initialize(options) ⇒ Connection
Returns a new instance of Connection.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/train/transports/ssh_connection.rb', line 34 def initialize() # Track IOS command retries to prevent infinite loop on IOError. This must # be done before `super()` because the parent runs detection commands. @ios_cmd_retries = 0 super() @username = @options.delete(:username) @hostname = @options.delete(:hostname) @port = @options[:port] # don't delete from options @connection_retries = @options.delete(:connection_retries) @connection_retry_sleep = @options.delete(:connection_retry_sleep) @max_wait_until_ready = @options.delete(:max_wait_until_ready) @max_ssh_sessions = @options.delete(:max_ssh_connections) { 9 } @session = nil @transport_options = @options.delete(:transport_options) @cmd_wrapper = nil @proxy_command = @options.delete(:proxy_command) @bastion_host = @options.delete(:bastion_host) @bastion_user = @options.delete(:bastion_user) @bastion_port = @options.delete(:bastion_port) @cmd_wrapper = CommandWrapper.load(self, @transport_options) end |
Instance Attribute Details
#hostname ⇒ Object (readonly)
rubocop:disable Metrics/ClassLength
33 34 35 |
# File 'lib/train/transports/ssh_connection.rb', line 33 def hostname @hostname end |
Instance Method Details
#check_proxy ⇒ Object
81 82 83 |
# File 'lib/train/transports/ssh_connection.rb', line 81 def check_proxy [@proxy_command, @bastion_host].any? { |type| !type.nil? } end |
#close ⇒ Object
57 58 59 60 61 62 63 |
# File 'lib/train/transports/ssh_connection.rb', line 57 def close return if @session.nil? logger.debug("[SSH] closing connection to #{self}") session.close ensure @session = nil end |
#download(remotes, local) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/train/transports/ssh_connection.rb', line 120 def download(remotes, local) waits = [] Array(remotes).map do |remote| opts = file(remote).directory? ? { recursive: true } : {} waits.push session.scp.download(remote, local, opts) do |_ch, name, recv, total| logger.debug("Downloaded #{name} (#{total} bytes)") if recv == total end waits.shift.wait while waits.length >= @max_ssh_sessions end waits.each(&:wait) rescue Net::SSH::Exception => ex raise Train::Transports::SSHFailed, "SCP download failed (#{ex.})" end |
#generate_proxy_command ⇒ Object
85 86 87 88 89 90 91 92 93 |
# File 'lib/train/transports/ssh_connection.rb', line 85 def generate_proxy_command return @proxy_command unless @proxy_command.nil? args = %w{ ssh } args += ssh_opts args += %W( #{@bastion_user}@#{@bastion_host} ) args += %W( -p #{@bastion_port} ) args += %w{ -W %h:%p } args.join(' ') end |
#login_command ⇒ Object
96 97 98 99 100 101 102 |
# File 'lib/train/transports/ssh_connection.rb', line 96 def login_command args = ssh_opts args += %W( -o ProxyCommand='#{generate_proxy_command}' ) if check_proxy args += %W( -p #{@port} ) args += %W( #{@username}@#{@hostname} ) LoginCommand.new('ssh', args) end |
#ssh_opts ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/train/transports/ssh_connection.rb', line 65 def ssh_opts level = logger.debug? ? 'VERBOSE' : 'ERROR' fwd_agent = [:forward_agent] ? 'yes' : 'no' args = %w{ -o UserKnownHostsFile=/dev/null } args += %w{ -o StrictHostKeyChecking=no } args += %w{ -o IdentitiesOnly=yes } if [:keys] args += %w{ -o BatchMode=yes } if [:non_interactive] args += %W( -o LogLevel=#{level} ) args += %W( -o ForwardAgent=#{fwd_agent} ) if .key?(:forward_agent) Array([:keys]).each do |ssh_key| args += %W( -i #{ssh_key} ) end args end |
#upload(locals, remote) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/train/transports/ssh_connection.rb', line 105 def upload(locals, remote) waits = [] Array(locals).each do |local| opts = File.directory?(local) ? { recursive: true } : {} waits.push session.scp.upload(local, remote, opts) do |_ch, name, sent, total| logger.debug("Uploaded #{name} (#{total} bytes)") if sent == total end waits.shift.wait while waits.length >= @max_ssh_sessions end waits.each(&:wait) rescue Net::SSH::Exception => ex raise Train::Transports::SSHFailed, "SCP upload failed (#{ex.})" end |
#uri ⇒ Object
146 147 148 |
# File 'lib/train/transports/ssh_connection.rb', line 146 def uri "ssh://#{@username}@#{@hostname}:#{@port}" end |
#wait_until_ready ⇒ Object
135 136 137 138 139 140 141 142 143 144 |
# File 'lib/train/transports/ssh_connection.rb', line 135 def wait_until_ready delay = 3 session( retries: @max_wait_until_ready / delay, delay: delay, message: "Waiting for SSH service on #{@hostname}:#{@port}, " \ "retrying in #{delay} seconds", ) run_command(PING_COMMAND.dup) end |