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
82 83 84 |
# File 'lib/train/transports/ssh_connection.rb', line 82 def check_proxy [@proxy_command, @bastion_host].any? { |type| !type.nil? } end |
#close ⇒ Object
57 58 59 60 61 62 63 64 |
# 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
122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/train/transports/ssh_connection.rb', line 122 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
86 87 88 89 90 91 92 93 94 95 |
# File 'lib/train/transports/ssh_connection.rb', line 86 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
98 99 100 101 102 103 104 |
# File 'lib/train/transports/ssh_connection.rb', line 98 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
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/train/transports/ssh_connection.rb', line 66 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
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/train/transports/ssh_connection.rb', line 107 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
148 149 150 |
# File 'lib/train/transports/ssh_connection.rb', line 148 def uri "ssh://#{@username}@#{@hostname}:#{@port}" end |
#wait_until_ready ⇒ Object
137 138 139 140 141 142 143 144 145 146 |
# File 'lib/train/transports/ssh_connection.rb', line 137 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 |