Class: Kitchen::Transport::Ssh::Connection

Inherits:
Base::Connection show all
Defined in:
lib/kitchen/transport/ssh.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.

Author:

Instance Method Summary collapse

Methods inherited from Base::Connection

#initialize

Methods included from Logging

#banner, #debug, #error, #fatal, #info, #warn

Constructor Details

This class inherits a constructor from Kitchen::Transport::Base::Connection

Instance Method Details

#closeObject

Closes the session connection, if it is still active.



87
88
89
90
91
92
93
94
# File 'lib/kitchen/transport/ssh.rb', line 87

def close
  return if @session.nil?

  logger.debug("[SSH] closing connection to #{self}")
  session.close
ensure
  @session = nil
end

#execute(command) ⇒ Object

Execute a command on the remote host.

Parameters:

  • command (String)

    command string to execute

Raises:

  • (TransportFailed)

    if the command does not exit successfully, which may vary by implementation



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/kitchen/transport/ssh.rb', line 97

def execute(command)
  return if command.nil?
  logger.debug("[SSH] #{self} (#{command})")
  exit_code = execute_with_exit_code(command)

  if exit_code != 0
    raise Transport::SshFailed,
      "SSH exited (#{exit_code}) for command: [#{command}]"
  end
rescue Net::SSH::Exception => ex
  raise SshFailed, "SSH command failed (#{ex.message})"
end

#login_commandLoginCommand

Builds a LoginCommand which can be used to open an interactive session on the remote host.

Returns:

  • (LoginCommand)

    an object containing the array of command line tokens and exec options to be used in a fork/exec

Raises:



111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/kitchen/transport/ssh.rb', line 111

def 
  args  = %W[ -o UserKnownHostsFile=/dev/null ]
  args += %W[ -o StrictHostKeyChecking=no ]
  args += %W[ -o IdentitiesOnly=yes ] if options[:keys]
  args += %W[ -o LogLevel=#{logger.debug? ? "VERBOSE" : "ERROR"} ]
  if options.key?(:forward_agent)
    args += %W[ -o ForwardAgent=#{options[:forward_agent] ? "yes" : "no"} ]
  end
  Array(options[:keys]).each { |ssh_key| args += %W[ -i #{ssh_key} ] }
  args += %W[ -p #{port} ]
  args += %W[ #{username}@#{hostname} ]

  LoginCommand.new("ssh", args)
end

#upload(locals, remote) ⇒ Object

Uploads local files or directories to remote host.

Parameters:

  • locals (Array<String>)

    paths to local files or directories

  • remote (String)

    path to remote destination

Raises:

  • (TransportFailed)

    if the files could not all be uploaded successfully, which may vary by implementation



127
128
129
130
131
132
133
134
135
136
137
# File 'lib/kitchen/transport/ssh.rb', line 127

def upload(locals, remote)
  Array(locals).each do |local|
    opts = File.directory?(local) ? { :recursive => true } : {}

    session.scp.upload!(local, remote, opts) do |_ch, name, sent, total|
      logger.debug("Uploaded #{name} (#{total} bytes)") if sent == total
    end
  end
rescue Net::SSH::Exception => ex
  raise SshFailed, "SCP upload failed (#{ex.message})"
end

#wait_until_readyObject

Block and return only when the remote host is prepared and ready to execute command and upload files. The semantics and details will vary by implementation, but a round trip through the hosted service is preferred to simply waiting on a socket to become available.



140
141
142
143
144
145
146
147
148
149
# File 'lib/kitchen/transport/ssh.rb', line 140

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"
  )
  execute(PING_COMMAND.dup)
end