Class: RightScraper::Processes::SSHAgent

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

Overview

Manage a dedicated SSH agent.

Defined Under Namespace

Classes: SSHAgentError

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSSHAgent

Returns a new instance of SSHAgent.



36
37
38
39
40
41
42
# File 'lib/right_scraper/processes/ssh.rb', line 36

def initialize
  @display = ENV['DISPLAY']
  @askpass = ENV['SSH_ASKPASS']
  @sshauth = ENV['SSH_AUTH_SOCK']
  @agentpid = ENV['SSH_AGENT_PID']
  @home = ENV['HOME']
end

Class Method Details

.withObject

Execute the block in a new ssh agent. Equivalent to

agent = SSHAgent.new
begin
 agent.open
 ...
ensure
 agent.close
end


177
178
179
180
181
182
183
184
185
# File 'lib/right_scraper/processes/ssh.rb', line 177

def self.with
  agent = SSHAgent.new
  begin
    agent.open
    yield agent
  ensure
    agent.close
  end
end

Instance Method Details

#add_key(key) ⇒ Object

Add the given key data to the ssh agent.

Parameters

key(String)

ssh key data



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/right_scraper/processes/ssh.rb', line 122

def add_key(key)
  begin
    file = Tempfile.new('key')
    file.puts(key)
    file.close

    add_keyfile(file.path)
  ensure
    file.close(true) unless file.nil?
  end
end

#add_keyfile(file) ⇒ Object

Add the key data in the given file to the ssh agent.

Parameters

file(String)

file containing key data



138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/right_scraper/processes/ssh.rb', line 138

def add_keyfile(file)
  @ssh_add_output = ::RightScale::RightPopen::SafeOutputBuffer.new
  cmd = ['ssh-add', file]
  ::RightScale::RightPopen.popen3_sync(
    cmd,
    :target          => self,
    :inherit_io      => true,  # avoid killing any rails connection
    :stderr_handler  => :output_ssh_add,
    :stdout_handler  => :output_ssh_add,
    :timeout_handler => :timeout_ssh_add,
    :exit_handler    => :exit_ssh_add,
    :timeout_seconds => 10)
end

#closeObject

Close the connection to the SSH agent, and restore ENV.



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/right_scraper/processes/ssh.rb', line 75

def close
  begin
    FileUtils.remove_entry_secure @dir
    lay_to_rest
  ensure
    setvar 'SSH_AGENT_PID', @agentpid
    setvar 'DISPLAY', @display
    setvar 'SSH_ASKPASS', @askpass
    setvar 'SSH_AUTH_SOCK', @sshauth
    setvar 'HOME', @home
  end
end

#exit_ssh_add(status) ⇒ Object



160
161
162
163
164
165
166
# File 'lib/right_scraper/processes/ssh.rb', line 160

def exit_ssh_add(status)
  unless status.success?
    @ssh_add_output.safe_buffer_data("Exit code = #{status.exitstatus}")
    raise SSHAgentError, "ssh-add failed: #{@ssh_add_output.display_text}"
  end
  true
end

#exit_ssh_agent(status) ⇒ Object



110
111
112
113
114
115
116
# File 'lib/right_scraper/processes/ssh.rb', line 110

def exit_ssh_agent(status)
  unless @interupted_to_close || status.success?
    @ssh_agent_output.safe_buffer_data("Exit code = #{status.exitstatus}")
    raise SSHAgentError, "ssh-agent failed: #{@ssh_agent_output.display_text}"
  end
  true
end

#openObject

Open a connection to the SSH agent and set ENV appropriately.



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
# File 'lib/right_scraper/processes/ssh.rb', line 46

def open
  ENV['SSH_ASKPASS'] = File.expand_path(File.join(File.dirname(__FILE__),
                                                  '..', '..', '..',
                                                  'scripts',
                                                  'stub_ssh_askpass'))
  ENV['HOME'] = "/dev/null"
  @dir = Dir.mktmpdir
  @socketfile = File.join(@dir, "agent")
  @process = nil
  @interupted_to_close = false
  @ssh_agent_output = ::RightScale::RightPopen::SafeOutputBuffer.new
  cmd = ['ssh-agent', '-a', @socketfile, '-d']
  ::RightScale::RightPopen.popen3_sync(
    cmd,
    :target          => self,
    :inherit_io      => true,  # avoid killing any rails connection
    :watch_handler   => :watch_ssh_agent,
    :stderr_handler  => :output_ssh_agent,
    :stdout_handler  => :output_ssh_agent,
    :timeout_handler => :timeout_ssh_agent,
    :exit_handler    => :exit_ssh_agent,
    :timeout_seconds => 10)
  if @process
    ENV['SSH_AGENT_PID'] = @process.pid.to_s
    ENV['SSH_AUTH_SOCK'] = @socketfile
  end
end

#output_ssh_add(data) ⇒ Object



152
153
154
# File 'lib/right_scraper/processes/ssh.rb', line 152

def output_ssh_add(data)
  @ssh_add_output.safe_buffer_data(data)
end

#output_ssh_agent(data) ⇒ Object



88
89
90
# File 'lib/right_scraper/processes/ssh.rb', line 88

def output_ssh_agent(data)
  @ssh_agent_output.safe_buffer_data(data)
end

#timeout_ssh_addObject

Raises:



156
157
158
# File 'lib/right_scraper/processes/ssh.rb', line 156

def timeout_ssh_add
  raise SSHAgentError, 'ssh-add timed out'
end

#timeout_ssh_agentObject



104
105
106
107
108
# File 'lib/right_scraper/processes/ssh.rb', line 104

def timeout_ssh_agent
  unless @interupted_to_close
    raise SSHAgentError, 'Timed out waiting for ssh-agent control socket to appear'
  end
end

#watch_ssh_agent(process) ⇒ TrueClass|FalseClass

abandons watch when socket file appears

Returns:

  • (TrueClass|FalseClass)

    true to continue watch, false to abandon



95
96
97
98
99
100
101
102
# File 'lib/right_scraper/processes/ssh.rb', line 95

def watch_ssh_agent(process)
  if @interupted_to_close
    true
  else
    @process = process
    !::File.exists?(@socketfile)
  end
end