Class: Kitchen::SSH

Inherits:
Object
  • Object
show all
Defined in:
lib/kitchen/ssh.rb

Overview

Class to help establish SSH connections, issue remote commands, and transfer files between a local system and remote node.

Author:

Instance Method Summary collapse

Constructor Details

#initialize(hostname, username, options = {}) {|self| ... } ⇒ SSH

Constructs a new SSH object.

Examples:

basic usage


ssh = Kitchen::SSH.new("remote.example.com", "root")
ssh.exec("sudo apt-get update")
ssh.upload!("/tmp/data.txt", "/var/lib/data.txt")
ssh.shutdown

block usage


Kitchen::SSH.new("remote.example.com", "root") do |ssh|
  ssh.exec("sudo apt-get update")
  ssh.upload!("/tmp/data.txt", "/var/lib/data.txt")
end

Parameters:

  • hostname (String)

    the remote hostname (IP address, FQDN, etc.)

  • username (String)

    the username for the remote host

  • options (Hash) (defaults to: {})

    configuration options

Options Hash (options):

  • :logger (Logger)

    the logger to use (default: ::Logger.new(STDOUT))

Yields:

  • (self)

    if a block is given then the constructed object yields itself and calls #shutdown at the end, closing the remote connection



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/kitchen/ssh.rb', line 63

def initialize(hostname, username, options = {})
  @hostname = hostname
  @username = username
  @options = options.dup
  @logger = @options.delete(:logger) || ::Logger.new(STDOUT)

  if block_given?
    yield self
    shutdown
  end
end

Instance Method Details

#exec(cmd) ⇒ Object

Execute a command on the remote host.

Parameters:

  • cmd (String)

    command string to execute

Raises:

  • (SSHFailed)

    if the command does not exit with a 0 code



79
80
81
82
83
84
85
86
# File 'lib/kitchen/ssh.rb', line 79

def exec(cmd)
  logger.debug("[SSH] #{self} (#{cmd})")
  exit_code = exec_with_exit(cmd)

  if exit_code != 0
    raise SSHFailed, "SSH exited (#{exit_code}) for command: [#{cmd}]"
  end
end

#login_commandLoginCommand

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

Returns:



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

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

#shutdownObject

Shuts down the session connection, if it is still active.



122
123
124
125
126
127
128
129
# File 'lib/kitchen/ssh.rb', line 122

def shutdown
  return if @session.nil?

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

#upload!(local, remote, options = {}, &progress) ⇒ Object

Uploads a local file to remote host.

Parameters:

  • local (String)

    path to local file

  • remote (String)

    path to remote file destination

  • options (Hash) (defaults to: {})

    configuration options that are passed to Net::SCP.upload

See Also:



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/kitchen/ssh.rb', line 95

def upload!(local, remote, options = {}, &progress)
  if progress.nil?
    progress = lambda { |_ch, name, sent, total|
      if sent == total
        logger.debug("Uploaded #{name} (#{total} bytes)")
      end
    }
  end

  session.scp.upload!(local, remote, options, &progress)
end

#upload_path!(local, remote, options = {}, &progress) ⇒ Object

Uploads a recursive directory to remote host.

Parameters:

  • local (String)

    path to local file or directory

  • remote (String)

    path to remote file destination

  • options (Hash) (defaults to: {})

    configuration options that are passed to Net::SCP.upload

Options Hash (options):

  • :recursive (true, false)

    recursive copy (default: true)

See Also:



115
116
117
118
119
# File 'lib/kitchen/ssh.rb', line 115

def upload_path!(local, remote, options = {}, &progress)
  options = { :recursive => true }.merge(options)

  upload!(local, remote, options, &progress)
end

#waitObject

Blocks until the remote host's SSH TCP port is listening.



132
133
134
# File 'lib/kitchen/ssh.rb', line 132

def wait
  logger.info("Waiting for #{hostname}:#{port}...") until test_ssh
end