Class: Ridley::HostConnector::SSH

Inherits:
Base
  • Object
show all
Defined in:
lib/ridley/host_connector/ssh.rb

Constant Summary collapse

DEFAULT_PORT =
22
EMBEDDED_RUBY_PATH =
'/opt/chef/embedded/bin/ruby'.freeze

Instance Method Summary collapse

Methods included from Logging

logger, #logger, set_logger

Instance Method Details

#bootstrap(host, options = {}) ⇒ HostConnector::Response

Bootstrap a node

Parameters:

  • host (String)

    the host to perform the action on

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

    a customizable set of options

Options Hash (options):

  • :ssh (Hash)
    • :user (String) a shell user that will login to each node and perform the bootstrap command on

    • :password (String) the password for the shell user that will perform the bootstrap

    • :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password

    • :timeout (Float) timeout value for SSH bootstrap (5.0)

    • :sudo (Boolean) run as sudo

Returns:



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

def bootstrap(host, options = {})
  options = options.reverse_merge(ssh: Hash.new)
  options[:ssh].reverse_merge!(sudo: true, timeout: 5.0)
  context = BootstrapContext::Unix.new(options)

  log.info "Bootstrapping host: #{host}"
  run(host, context.boot_command, options)
end

#chef_client(host, options = {}) ⇒ HostConnector::Response

Perform a chef client run on a node

Parameters:

  • host (String)

    the host to perform the action on

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

    a customizable set of options

Options Hash (options):

  • :ssh (Hash)
    • :user (String) a shell user that will login to each node and perform the bootstrap command on

    • :password (String) the password for the shell user that will perform the bootstrap

    • :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password

    • :timeout (Float) timeout value for SSH bootstrap (5.0)

    • :sudo (Boolean) run as sudo

Returns:



114
115
116
# File 'lib/ridley/host_connector/ssh.rb', line 114

def chef_client(host, options = {})
  run(host, "chef-client", options)
end

#put_secret(host, secret, options = {}) ⇒ HostConnector::Response

Write your encrypted data bag secret on a node

Parameters:

  • host (String)

    the host to perform the action on

  • secret (String)

    your organization’s encrypted data bag secret

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

    a customizable set of options

Options Hash (options):

  • :ssh (Hash)
    • :user (String) a shell user that will login to each node and perform the bootstrap command on

    • :password (String) the password for the shell user that will perform the bootstrap

    • :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password

    • :timeout (Float) timeout value for SSH bootstrap (5.0)

    • :sudo (Boolean) run as sudo

Returns:



133
134
135
136
# File 'lib/ridley/host_connector/ssh.rb', line 133

def put_secret(host, secret, options = {})
  cmd = "echo '#{secret}' > /etc/chef/encrypted_data_bag_secret; chmod 0600 /etc/chef/encrypted_data_bag_secret"
  run(host, cmd, options)
end

#ruby_script(host, command_lines, options = {}) ⇒ HostConnector::Response

Execute line(s) of Ruby code on a node using Chef’s embedded Ruby

Parameters:

  • host (String)

    the host to perform the action on

  • command_lines (Array<String>)

    An Array of lines of the command to be executed

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

    a customizable set of options

Options Hash (options):

  • :ssh (Hash)
    • :user (String) a shell user that will login to each node and perform the bootstrap command on

    • :password (String) the password for the shell user that will perform the bootstrap

    • :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password

    • :timeout (Float) timeout value for SSH bootstrap (5.0)

    • :sudo (Boolean) run as sudo

Returns:



153
154
155
# File 'lib/ridley/host_connector/ssh.rb', line 153

def ruby_script(host, command_lines, options = {})
  run(host, "#{EMBEDDED_RUBY_PATH} -e \"#{command_lines.join(';')}\"", options)
end

#run(host, command, options = {}) ⇒ HostConnector::Response

Execute a shell command on a node

Parameters:

  • host (String)

    the host to perform the action on

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

    a customizable set of options

Options Hash (options):

  • :ssh (Hash)
    • :user (String) a shell user that will login to each node and perform the bootstrap command on

    • :password (String) the password for the shell user that will perform the bootstrap

    • :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password

    • :timeout (Float) timeout value for SSH bootstrap (5.0)

    • :sudo (Boolean) run as sudo

Returns:



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/ridley/host_connector/ssh.rb', line 23

def run(host, command, options = {})
  options = options.reverse_merge(ssh: Hash.new)
  options[:ssh].reverse_merge!(port: DEFAULT_PORT, paranoid: false, sudo: false)

  command = "sudo #{command}" if options[:ssh][:sudo]

  Ridley::HostConnector::Response.new(host).tap do |response|
    begin
      log.info "Running SSH command: '#{command}' on: '#{host}' as: '#{options[:ssh][:user]}'"

      defer {
        Net::SSH.start(host, options[:ssh][:user], options[:ssh].slice(*Net::SSH::VALID_OPTIONS)) do |ssh|
          ssh.open_channel do |channel|
            if options[:sudo]
              channel.request_pty do |channel, success|
                unless success
                  raise "Could not aquire pty: A pty is required for running sudo commands."
                end

                channel_exec(channel, command, host, response)
              end
            else
              channel_exec(channel, command, host, response)
            end
          end
          ssh.loop
        end
      }
    rescue Net::SSH::AuthenticationFailed => ex
      response.exit_code = -1
      response.stderr    = "Authentication failure for user #{ex}"
    rescue Net::SSH::ConnectionTimeout, Timeout::Error
      response.exit_code = -1
      response.stderr    = "Connection timed out"
    rescue Errno::EHOSTUNREACH
      response.exit_code = -1
      response.stderr    = "Host unreachable"
    rescue Errno::ECONNREFUSED
      response.exit_code = -1
      response.stderr    = "Connection refused"
    rescue Net::SSH::Exception => ex
      response.exit_code = -1
      response.stderr    = ex.inspect
    end

    case response.exit_code
    when 0
      log.info "Successfully ran SSH command on: '#{host}' as: '#{options[:ssh][:user]}'"
    when -1
      log.info "Failed to run SSH command on: '#{host}' as: '#{options[:ssh][:user]}'"
    else
      log.info "Successfully ran SSH command on: '#{host}' as: '#{options[:ssh][:user]}' but it failed"
    end
  end
end

#uninstall_chef(host, options = {}) ⇒ HostConnector::Response

Uninstall Chef from a node

Parameters:

  • host (String)

    the host to perform the action on

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

    a customizable set of options

Options Hash (options):

  • :skip_chef (Boolena) — default: false

    skip removal of the Chef package and the contents of the installation directory. Setting this to true will only remove any data and configurations generated by running Chef client.

  • :ssh (Hash)
    • :user (String) a shell user that will login to each node and perform the bootstrap command on

    • :password (String) the password for the shell user that will perform the bootstrap

    • :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password

    • :timeout (Float) timeout value for SSH bootstrap (5.0)

    • :sudo (Boolean) run as sudo (true)

Returns:



174
175
176
177
178
179
180
# File 'lib/ridley/host_connector/ssh.rb', line 174

def uninstall_chef(host, options = {})
  options = options.reverse_merge(ssh: Hash.new)
  options[:ssh].reverse_merge!(sudo: true, timeout: 5.0)

  log.info "Uninstalling Chef from host: #{host}"
  run(host, CommandContext::UnixUninstall.command(options), options)
end