class Pennyworth::SshKeysImporter

Public Class Methods

import(ip, username, password, identity_file = nil) click to toggle source
# File lib/pennyworth/ssh_keys_importer.rb, line 22
    def self.import(ip, username, password, identity_file = nil)
      tmp_file = Tempfile.new("pennyworth-ssh-key-importer")

      cmd = "ssh-copy-id"
      if identity_file
        cmd << " -i \"#{identity_file}\""
        cmd << " -o \"IdentityFile=#{identity_file}\""
      end
      cmd << " -o \"UserKnownHostsFile=/dev/null\""
      cmd << " -o \"StrictHostKeyChecking=no\""
      cmd << " #{username}@#{ip}"

      # This temporary bash script copies the SSH keys to the host using
      # ssh-copy-id.
      #
      # In order to drive this interactive command it is executed by expect.
      tmp_file.write(<<-EOF
        #!/usr/bin/expect -f

        spawn #{cmd}
        expect {
          -re ".*assword.*" {
            send "#{password}\\r"
            expect {
              -re ".*assword.*" {
                exit 1
              }
              -re ".*Number of key.*" {
                exit 0
              }
            }
          }
          -re ".*Number of key.*" {
            exit 0
          }
          "skipped" {
            exit 2
          }
          "authenticity" {
            send "yes\\r"
            exp_continue
          }
          "Connection refused" {
            exit 3
          }
        }
        exit 4
      EOF
      )
      tmp_file.close

      attempt = 1
      begin
        Cheetah.run("expect", tmp_file.path)
      rescue Cheetah::ExecutionFailed => e
        case e.status.exitstatus
          when 1
            raise WrongPasswordException, "Error: Could not upload SSH keys because" \
              " the password is wrong."
          when 2
            raise SshKeysAlreadyExistsException, "SSH keys were not uploaded because they" \
              " were already on the host."
          when 3
            # We give sshd 30 seconds to start up
            if attempt > 30
              raise SshConnectionFailed, "SSH connection failed."
            else
              attempt += 1
              sleep 1
              retry
            end
          when 4
            raise RuntimeError, "An unknown error occured while trying to upload " \
              "the SSH keys."
          when 127
            raise CommandNotFoundError, "Error: Please install expect before running" \
              " pennyworth copy-ssh-keys."
          else
            raise e
        end
      end
    ensure
      tmp_file.unlink
    end