class Kitchen::Driver::SSHBaseGzip

Base class for a driver that uses SSH to communication with an instance. A subclass must implement the following methods:

@author Fletcher Nichol <fnichol@nichol.ca>

Public Instance Methods

converge(state) click to toggle source

(see Base#converge)

# File lib/kitchen/driver/ssh_base_gzip.rb, line 42
def converge(state)
  provisioner = instance.provisioner
  provisioner.create_sandbox

  Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
    run_remote(provisioner.install_command, conn)
    run_remote(provisioner.init_command, conn)
    do_sandbox_transfer provisioner, conn
    run_remote(provisioner.prepare_command, conn)
    run_remote(provisioner.run_command, conn)
  end
ensure
  provisioner && provisioner.cleanup_sandbox
end
create(state) click to toggle source

(see Base#create)

# File lib/kitchen/driver/ssh_base_gzip.rb, line 37
def create(state) # rubocop:disable Lint/UnusedMethodArgument
  raise ClientError, "#{self.class}#create must be implemented"
end
destroy(state) click to toggle source

(see Base#destroy)

# File lib/kitchen/driver/ssh_base_gzip.rb, line 73
def destroy(state) # rubocop:disable Lint/UnusedMethodArgument
  raise ClientError, "#{self.class}#destroy must be implemented"
end
login_command(state) click to toggle source

(see Base#login_command)

# File lib/kitchen/driver/ssh_base_gzip.rb, line 78
def login_command(state)
  SSH.new(*build_ssh_args(state)).login_command
end
remote_command(state, command) click to toggle source

Executes an arbitrary command on an instance over an SSH connection.

@param state [Hash] mutable instance and driver state @param command [String] the command to be executed @raise [ActionFailed] if the command could not be successfully completed

# File lib/kitchen/driver/ssh_base_gzip.rb, line 87
def remote_command(state, command)
  Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
    run_remote(command, conn)
  end
end
setup(state) click to toggle source

(see Base#setup)

# File lib/kitchen/driver/ssh_base_gzip.rb, line 58
def setup(state)
  Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
    run_remote(busser.setup_cmd, conn)
  end
end
ssh(ssh_args, command) click to toggle source

**(Deprecated)** Executes a remote command over SSH.

@param ssh_args [Array] ssh arguments @param command [String] remote command to invoke @deprecated This method should no longer be called directly and exists

to support very old drivers. This will be removed in the future.
# File lib/kitchen/driver/ssh_base_gzip.rb, line 99
def ssh(ssh_args, command)
  Kitchen::SSH.new(*ssh_args) do |conn|
    run_remote(command, conn)
  end
end

Private Instance Methods

archive_sandbox(sandbox_path) click to toggle source

Creates a temporary folder containing an archive of the current TestKitchen sandbox.

@param sandbox_path [String]

# File lib/kitchen/driver/ssh_base_gzip.rb, line 189
def archive_sandbox(sandbox_path)
  archive_dir  = Dir.mktmpdir("#{instance.name}-sandbox-archive-")
  archive_file = "#{archive_dir}/#{self[:sandbox_archive]}"

  Dir.chdir(sandbox_path) do |dir|
    tgz = Zlib::GzipWriter.new(File.open(archive_file, 'wb'), Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY)
    Archive::Tar::Minitar.pack('.', tgz)
  end

  archive_dir
end
build_ssh_args(state) click to toggle source

Builds arguments for constructing a `Kitchen::SSH` instance.

@param state [Hash] state hash @return [Array] SSH constructor arguments @api private

# File lib/kitchen/driver/ssh_base_gzip.rb, line 112
def build_ssh_args(state)
  combined = config.to_hash.merge(state)

  opts = Hash.new
  opts[:user_known_hosts_file] = "/dev/null"
  opts[:verify_host_key] = false
  opts[:keys_only] = true if combined[:ssh_key]
  opts[:password] = combined[:password] if combined[:password]
  opts[:forward_agent] = combined[:forward_agent] if combined[:forward_agent] # if combined.key? :forward_agent
  opts[:port] = combined[:port] if combined[:port]
  opts[:keys] = Array(combined[:ssh_key]) if combined[:ssh_key]
  opts[:logger] = logger

  [combined[:hostname], combined[:username], opts]
end
do_sandbox_transfer(provisioner, connection) click to toggle source

Transfers the local sandbox to the instance.

  • Archives/extracts if the tar command is available remotely.

@param provisioner [Kitchen::Provisioner::Base] the provisioner @param connection [Kitchen:SSH] an SSH connection

# File lib/kitchen/driver/ssh_base_gzip.rb, line 206
def do_sandbox_transfer(provisioner, connection)
  root_path     = provisioner[:root_path]
  sandbox_path  = provisioner.sandbox_path
  archive_file  = self[:sandbox_archive]
  archive_path  = false
  do_archive    = remote_supports_tar? connection

  begin
    # Archive sandbox if enabled (We keep a copy of the archive path so that we do not)
    # delete the sandbox if an exception is thrown
    if do_archive
      info 'Creating sandbox archive'
      archive_path = archive_sandbox sandbox_path
      sandbox_path = archive_path
    end

    # Initiate transfer
    transfer_path(Dir.glob("#{sandbox_path}/*"), root_path, connection)

    # Extract archive if enabled (and cleanup locally)
    if do_archive
      info 'Extracting sandbox archive remotely'
      run_remote("tar xf #{root_path}/#{archive_file} -C #{root_path}", connection)
    end
  ensure
    # Ensure archive temporary directory is removed, if used.
    FileUtils.rmtree(archive_path) if archive_path
  end
end
env_cmd(cmd) click to toggle source

Adds http and https proxy environment variables to a command, if set in configuration data.

@param cmd [String] command string @return [String] command string @api private

# File lib/kitchen/driver/ssh_base_gzip.rb, line 134
def env_cmd(cmd)
  env = "env"
  env << " http_proxy=#{config[:http_proxy]}"   if config[:http_proxy]
  env << " https_proxy=#{config[:https_proxy]}" if config[:https_proxy]

  env == "env" ? cmd : "#{env} #{cmd}"
end
remote_supports_tar?(connection) click to toggle source

Checks whether the remote instance supports archive extraction using the `tar` command.

@param connection [Kitchen::SSH] an SSH connection

# File lib/kitchen/driver/ssh_base_gzip.rb, line 240
def remote_supports_tar?(connection)
  begin
    run_remote('tar --version > /dev/null 2>&1', connection)
    return true
  rescue ActionFailed => ex
      return false
  end
end
run_remote(command, connection) click to toggle source

Executes a remote command over SSH.

@param command [String] remove command to run @param connection [Kitchen::SSH] an SSH connection @raise [ActionFailed] if an exception occurs @api private

# File lib/kitchen/driver/ssh_base_gzip.rb, line 148
def run_remote(command, connection)
  return if command.nil?

  connection.exec(env_cmd(command))
rescue SSHFailed, Net::SSH::Exception => ex
  raise ActionFailed, ex.message
end
transfer_path(locals, remote, connection) click to toggle source

Transfers one or more local paths over SSH.

@param locals [Array<String>] array of local paths @param remote [String] remote destination path @param connection [Kitchen::SSH] an SSH connection @raise [ActionFailed] if an exception occurs @api private

# File lib/kitchen/driver/ssh_base_gzip.rb, line 163
def transfer_path(locals, remote, connection)
  return if locals.nil? || Array(locals).empty?

  info("Transferring files to #{instance.to_str}")
  locals.each { |local| connection.upload_path!(local, remote) }
  debug("Transfer complete")
rescue SSHFailed, Net::SSH::Exception => ex
  raise ActionFailed, ex.message
end
wait_for_sshd(hostname, username = nil, options = {}) click to toggle source

Blocks until a TCP socket is available where a remote SSH server should be listening.

@param hostname [String] remote SSH server host @param username [String] SSH username (default: `nil`) @param options [Hash] configuration hash (default: `{}`) @api private

# File lib/kitchen/driver/ssh_base_gzip.rb, line 180
def wait_for_sshd(hostname, username = nil, options = {})
  SSH.new(hostname, username, { :logger => logger }.merge(options)).wait
end