Module: RHC::SSHHelpers

Defined Under Namespace

Classes: MultipleGearTask

Instance Method Summary collapse

Instance Method Details

#check_ssh_executable!(path) ⇒ Object

return supplied ssh executable, if valid (executable, searches $PATH). if none was supplied, return installed ssh, if any.



356
357
358
359
360
361
362
363
364
365
366
# File 'lib/rhc/ssh_helpers.rb', line 356

def check_ssh_executable!(path)
  if not path
    raise RHC::InvalidSSHExecutableException.new("No system SSH available. Please use the --ssh option to specify the path to your SSH executable, or install SSH.") unless has_ssh?
    'ssh'
  else
    bin_path = path.split(' ').first
    raise RHC::InvalidSSHExecutableException.new("SSH executable '#{bin_path}' does not exist.") unless File.exist?(bin_path) or exe?(bin_path)
    raise RHC::InvalidSSHExecutableException.new("SSH executable '#{bin_path}' is not executable.") unless File.executable?(bin_path) or exe?(bin_path)
    path
  end
end

#exe?(executable) ⇒ Boolean

Returns:

  • (Boolean)


286
287
288
289
290
# File 'lib/rhc/ssh_helpers.rb', line 286

def exe?(executable)
  ENV['PATH'].split(File::PATH_SEPARATOR).any? do |directory|
    File.executable?(File.join(directory, executable.to_s))
  end
end

#fingerprint_for_default_keyObject



317
318
319
# File 'lib/rhc/ssh_helpers.rb', line 317

def fingerprint_for_default_key
  fingerprint_for_local_key(RHC::Config.ssh_pub_key_file_path)
end

#fingerprint_for_local_key(key) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/rhc/ssh_helpers.rb', line 304

def fingerprint_for_local_key(key)
  Net::SSH::KeyFactory.load_public_key(key).fingerprint
rescue NoMethodError, NotImplementedError => e
  ssh_keygen_fallback key
  nil
rescue OpenSSL::PKey::PKeyError, Net::SSH::Exception => e
  error e.message
  nil
rescue => e
  debug e.message
  nil
end

#generate_ssh_key_ruby(type = "RSA", bits = 2048, comment = "ProtonBox-Key") ⇒ Object

Public: Generate an SSH key and store it in ~/.ssh/id_rsa

type - The String type RSA or DSS. bits - The Integer value for number of bits. comment - The String comment for the key

Examples

generate_ssh_key_ruby
# => /home/user/.ssh/id_rsa.pub

Returns nil on failure or public key location as a String on success



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/rhc/ssh_helpers.rb', line 261

def generate_ssh_key_ruby(type="RSA", bits = 2048, comment = "ProtonBox-Key")
  key = RHC::Vendor::SSHKey.generate(:type => type,
                                     :bits => bits,
                                     :comment => comment)
  ssh_dir = RHC::Config.ssh_dir
  priv_key = RHC::Config.ssh_priv_key_file_path
  pub_key = RHC::Config.ssh_pub_key_file_path

  if File.exists?(priv_key)
    say "SSH key already exists: #{priv_key}.  Reusing..."
    return nil
  else
    unless File.exists?(ssh_dir)
      FileUtils.mkdir_p(ssh_dir)
      File.chmod(0700, ssh_dir)
    end
    File.open(priv_key, 'w') {|f| f.write(key.private_key)}
    File.chmod(0600, priv_key)
    File.open(pub_key, 'w') {|f| f.write(key.ssh_public_key)}

    ssh_add
  end
  pub_key
end

#has_ssh?Boolean

return whether or not SSH is installed

Returns:

  • (Boolean)


344
345
346
347
348
349
350
351
352
# File 'lib/rhc/ssh_helpers.rb', line 344

def has_ssh?
  @has_ssh ||= begin
    @ssh_version = nil
    ssh_version
    $?.success?
  rescue
    false
  end
end

#run_on_gears(command, gears, opts = {}, &block) ⇒ Object



135
136
137
138
# File 'lib/rhc/ssh_helpers.rb', line 135

def run_on_gears(command, gears, opts={}, &block)
  debug "Executing #{command} on each of #{gears.inspect}"
  MultipleGearTask.new(command, gears, {:limit => options.limit, :always_prefix => options.always_prefix, :raw => options.raw}.merge(opts)).run(&block)
end

#ssh_command_for_op(operation) ⇒ Object



146
147
148
149
150
# File 'lib/rhc/ssh_helpers.rb', line 146

def ssh_command_for_op(operation)
  #case operation
  raise RHC::OperationNotSupportedException, "The operation #{operation} is not supported."
  #end
end

#ssh_key_triple_for(key) ⇒ Object

for an SSH public key specified by ‘key’, return a triple

type, content, comment

which is basically the space-separated list of the SSH public key content



324
325
326
327
328
329
330
331
332
# File 'lib/rhc/ssh_helpers.rb', line 324

def ssh_key_triple_for(key)
  begin
    IO.read(key).chomp.split
  rescue Errno::ENOENT => e
    raise ::RHC::KeyFileNotExistentException.new("File '#{key}' does not exist.")
  rescue Errno::EACCES => e
    raise ::RHC::KeyFileAccessDeniedException.new("Access denied to '#{key}'.")
  end
end

#ssh_key_triple_for_default_keyObject



334
335
336
# File 'lib/rhc/ssh_helpers.rb', line 334

def ssh_key_triple_for_default_key
  ssh_key_triple_for(RHC::Config.ssh_pub_key_file_path)
end

#ssh_keygen_fallback(path) ⇒ Object

For Net::SSH versions (< 2.0.11) that does not have Net::SSH::KeyFactory.load_public_key, we drop to shell to get the key’s fingerprint



295
296
297
298
299
300
301
302
# File 'lib/rhc/ssh_helpers.rb', line 295

def ssh_keygen_fallback(path)
  fingerprint = `ssh-keygen -lf #{path} 2>&1`.split(' ')[1]

  if $?.exitstatus != 0
    error "Unable to compute SSH public key finger print for #{path}"
  end
  fingerprint
end

#ssh_ruby(host, username, command, compression = false, request_pty = false, &block) ⇒ Object

Public: Run ssh command on remote host

host - The String of the remote hostname to ssh to. username - The String username of the remote user to ssh as. command - The String command to run on the remote host. compression - Use compression in ssh, set to false if sending files. request_pty - Request for pty, set to false when pipe a file. block - Will yield this block and send the channel if provided.

Examples

ssh_ruby('myapp-t.protonbox.me',
          '109745632b514e9590aa802ec015b074',
          'pboxsh tail -f $PROTONBOX_LOG_DIR/*"')
# => true

Returns true on success



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/rhc/ssh_helpers.rb', line 169

def ssh_ruby(host, username, command, compression=false, request_pty=false, &block)
  debug "Opening Net::SSH connection to #{host}, #{username}, #{command}"
  exit_status = 0
  Net::SSH.start(host, username, :compression => compression) do |session|
    #:nocov:
    channel = session.open_channel do |channel|
      if request_pty
        channel.request_pty do |ch, success|
          say "pty could not be obtained" unless success
        end
      end
      channel.exec(command) do |ch, success|
        channel.on_data do |ch, data|
          print data
        end
        channel.on_extended_data do |ch, type, data|
          print data
        end
        channel.on_close do |ch|
          debug "Terminating ... "
        end
        channel.on_request("exit-status") do |ch, data|
          exit_status = data.read_long
        end
        yield channel if block_given?
        channel.eof!
      end
    end
    session.loop
    #:nocov:
  end
  raise RHC::SSHCommandFailed.new(exit_status) if exit_status != 0
rescue Errno::ECONNREFUSED => e
  debug_error e
  raise RHC::SSHConnectionRefused.new(host, username)
rescue Net::SSH::AuthenticationFailed => e
  debug_error e
  raise RHC::SSHAuthenticationFailed.new(host, username)
rescue SocketError => e
  debug_error e
  raise RHC::ConnectionFailed, "The connection to #{host} failed: #{e.message}"
end

#ssh_send_file_ruby(host, username, command, filename) ⇒ Object

Public: Run ssh command on remote host and pipe the specified file contents to the command input

host - The String of the remote hostname to ssh to. username - The String username of the remote user to ssh as. command - The String command to run on the remote host. filename - The String path to file to send.



221
222
223
224
225
226
227
228
229
230
# File 'lib/rhc/ssh_helpers.rb', line 221

def ssh_send_file_ruby(host, username, command, filename)
  filename = File.expand_path(filename)
  ssh_ruby(host, username, command) do |channel|
    File.open(filename, 'rb') do |file|
      file.chunk(1024) do |chunk|
        channel.send_data chunk
      end
    end
  end
end

#ssh_send_url_ruby(host, username, command, content_url) ⇒ Object

Public: Run ssh command on remote host and pipe the specified url contents to the command input

host - The String of the remote hostname to ssh to. username - The String username of the remote user to ssh as. command - The String command to run on the remote host. content_url - The url with the content to pipe to command.



240
241
242
243
244
245
246
247
# File 'lib/rhc/ssh_helpers.rb', line 240

def ssh_send_url_ruby(host, username, command, content_url)
  content_url = URI.parse(URI.encode(content_url.to_s))
  ssh_ruby(host, username, command) do |channel|
    HTTPClient.new.get_content(content_url) do |chunk|
      channel.send_data chunk
    end
  end
end

#ssh_versionObject

check the version of SSH that is installed



339
340
341
# File 'lib/rhc/ssh_helpers.rb', line 339

def ssh_version
  @ssh_version ||= `ssh -V 2>&1`.strip
end

#table_from_gears(command, groups, opts = {}, &block) ⇒ Object



140
141
142
143
144
# File 'lib/rhc/ssh_helpers.rb', line 140

def table_from_gears(command, groups, opts={}, &block)
  cells = run_on_gears(command, groups, {:as => :table}.merge(opts), &block)
  cells.each{ |r| r.concat(r.pop.first.split(opts[:split_cells_on])) } if !block_given? && opts[:split_cells_on]
  say table cells, opts unless options.raw
end