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


60
61
62
63
64
65
66
67
68
69
70
# File 'lib/kitchen/ssh.rb', line 60

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


76
77
78
79
80
81
82
83
# File 'lib/kitchen/ssh.rb', line 76

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:


152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/kitchen/ssh.rb', line 152

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.


134
135
136
137
138
139
140
141
# File 'lib/kitchen/ssh.rb', line 134

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


102
103
104
105
106
107
108
109
110
111
112
# File 'lib/kitchen/ssh.rb', line 102

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

  session.scp.upload(local, remote, options, &progress)
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:


92
93
94
95
96
97
98
99
100
# File 'lib/kitchen/ssh.rb', line 92

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

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

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


128
129
130
131
# File 'lib/kitchen/ssh.rb', line 128

def upload_path(local, remote, options = {}, &progress)
  options = { recursive: true }.merge(options)
  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:


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

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.


144
145
146
# File 'lib/kitchen/ssh.rb', line 144

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