Class: RightScraper::Processes::SSHAgent

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

Overview

Manage a dedicated SSH agent.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSSHAgent

Returns a new instance of SSHAgent.



31
32
33
34
35
36
37
# File 'lib/right_scraper/processes/ssh.rb', line 31

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



148
149
150
151
152
153
154
155
156
157
158
# File 'lib/right_scraper/processes/ssh.rb', line 148

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



164
165
166
# File 'lib/right_scraper/processes/ssh.rb', line 164

def add_keyfile(file)
  ProcessWatcher.watch("ssh-add", [file], nil, -1, 10)
end

#closeObject

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



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/right_scraper/processes/ssh.rb', line 64

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

#lay_to_rest(pid, timeout = 10) ⇒ Object

Kill pid. Initially use SIGTERM to be kind and a good citizen. If it doesn’t die after timeout seconds, use SIGKILL instead. In any case, the process will die. The status information is accessible in $?.

Parameters

pid(Fixnum)

pid of process to kill

timeout(Fixnum)

time in seconds to wait before forcing process to die. Defaults to 10 seconds.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/right_scraper/processes/ssh.rb', line 87

def lay_to_rest(pid, timeout=10)
  #refuse to kill ourselves, or to pass a bad arg to Process.kill
  return 0 unless pid.is_a?(Integer) && pid > 0

  Process.kill('TERM', pid)
  time_waited = 0
  loop do
    if time_waited >= timeout
      Process.kill('KILL', pid)
      # can't waitpid here, because the ssh-agent isn't our
      # child.  Still, after SIGKILL it will die and init will
      # reap it, so continue
      return
    end
    # still can't waitpid here, so we see if it's still alive
    return unless still_alive?(pid)
    sleep 1
    time_waited += 1
  end
end

#openObject

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



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/right_scraper/processes/ssh.rb', line 41

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")
  @monitor = ProcessWatcher::ProcessMonitor.new
  @pid = @monitor.spawn('ssh-agent', '-a', @socketfile, '-d') {}
  timeout = 0
  until File.exists?(@socketfile)
    timeout += 1
    sleep 0.1
    if timeout > 100
      raise "Couldn't find SSH agent control socket in time.  Timing out"
    end
  end
  ENV['SSH_AGENT_PID'] = @pid.to_s
  ENV['SSH_AUTH_SOCK'] = @socketfile
end

#still_alive?(pid) ⇒ Boolean

Check to see if the process pid is still alive, by sending the 0 signal and checking for an exception.

Parameters

pid(Fixnum)

pid of process to check on

Return

Boolean

true if process is still alive

Returns:

  • (Boolean)


116
117
118
119
120
121
122
123
# File 'lib/right_scraper/processes/ssh.rb', line 116

def still_alive?(pid)
  begin
    Process.kill(0, pid)
    true
  rescue Errno::ESRCH
    false
  end
end