module Rye
  1. lib/rye/box.rb
  2. lib/rye/cmd.rb
  3. lib/rye/dsl.rb
  4. lib/rye/hop.rb
  5. lib/rye/key.rb
  6. lib/rye/rap.rb
  7. lib/rye/set.rb
  8. lib/rye.rb
  9. show all
Parent: rye.rb

vim: set sw=2 ts=2 :


vim: set sw=2 ts=2 :


vim: set sw=2 ts=2 :


vim: set sw=2 ts=2 :


vim: set sw=2 ts=2 :


Rye

Safely run remote commands via SSH in Ruby.

Rye is similar to Rush but everything happens over SSH (no HTTP daemon) and the default settings are less dangerous (for safety). For example, file globs and the "rm" command are disabled so unless otherwise specified, you can't do this: rbox.rm('/etc/*/').

However, you can do this:

rset = Rye::Set.new("dev-machines") rset.add_boxes('host1', 'host2', 'host3', 'host4') rset.ps('aux')

  • See bin/try for a bunch of working examples.

  • See Rye::Box#initialize for info about disabling safe-mode.

Constants

DEBUG = false unless defined?(Rye::DEBUG)  
HOME = File.expand_path( File.join(File.dirname(__FILE__), '..') )  

Public Class methods

sysinfo ()

Accessor for an instance of SystemInfo

[show source]
# File lib/rye.rb, line 75
def Rye.sysinfo
  @@sysinfo = SysInfo.new if @@sysinfo.nil?
  @@sysinfo
end

Public Instance methods

add_keys (*keys)

Add one or more private keys to the SSH Agent.

  • keys one or more file paths to private keys used for passwordless logins.

[show source]
# File lib/rye.rb, line 146
def add_keys(*keys)
  keys = keys.flatten.compact || []
  return if keys.empty?
  Rye.shell("ssh-add", keys)
end
escape (safe, cmd, *args)

Creates a string from cmd and args. If safe is true it will send them through Escape.shell_command otherwise it will return them joined by a space character.

[show source]
# File lib/rye.rb, line 256
def escape(safe, cmd, *args)
  args = args.flatten.compact || []
  safe ? Escape.shell_command(cmd, *args).to_s : [cmd, args].flatten.compact.join(' ')
end
find_private_keys (path)

Looks for private keys in path and returns an Array of paths to the files it finds. Raises an Exception if path does not exist. If path is a file rather than a directory, it will check whether that single file is a private key.

[show source]
# File lib/rye.rb, line 123
def find_private_keys(path)
  raise "#{path} does not exist" unless File.exists?(path || '')
  if File.directory?(path)
    files = Dir.entries(path).collect { |file| File.join(path, file) }
  else
    files = [path]
  end

  files = files.select do |file|
    next if File.directory?(file)
    pk = nil
    begin
      tmp = Rye::Key.from_file(file)
      pk = tmp if tmp.private?
    rescue OpenSSL::PKey::PKeyError
    end
    !pk.nil?
  end
  files || []
end
keys ()

Returns an Array of info about the currently available SSH keys, as provided by the SSH Agent.

Returns: [[bits, finger-print, file-path], ...]

[show source]
# File lib/rye.rb, line 157
def keys
  # 2048 76:cb:d7:82:90:92:ad:75:3d:68:6c:a9:21:ca:7b:7f /Users/rye/.ssh/id_rsa (RSA)
  # 2048 7b:a6:ba:55:b1:10:1d:91:9f:73:3a:aa:0c:d4:88:0e /Users/rye/.ssh/id_dsa (DSA)
  #keystr = Rye.shell("ssh-add", '-l')
  #return nil unless keystr
  #keystr.collect do |key|
  #  key.split(/\s+/)
  #end
  Dir.glob(File.join(Rye.sysinfo.home, '.ssh', 'id_*sa'))
end
mutex ()
[show source]
# File lib/rye.rb, line 115
def mutex
  @@mutex
end
prepare_command (cmd, *args)

Takes a command with arguments and returns it in a single String with escaped args and some other stuff.

  • cmd The shell command name or absolute path.

  • args an Array of command arguments.

The command is searched for in the local PATH (where Rye is running). An exception is raised if it's not found. NOTE: Because this happens locally, you won't want to use this method if the environment is quite different from the remote machine it will be executed on.

The command arguments are passed through Escape.shell_command (that means you can't use environment variables or asterisks).

[show source]
# File lib/rye.rb, line 190
def prepare_command(cmd, *args)
  args &&= [args].flatten.compact
  found_cmd = Rye.which(cmd)
  raise CommandNotFound.new(cmd || '[unknown]') unless found_cmd
  # Symbols to switches. :l -> -l, :help -> --help
  args.collect! do |a|
    a = "-#{a}" if a.is_a?(Symbol) && a.to_s.size == 1
    a = "--#{a}" if a.is_a?(Symbol)
    a
  end
  Rye.escape(@safe, found_cmd, *args)
end
reload ()

Reload Rye dynamically. Useful with irb. NOTE: does not reload rye.rb.

[show source]
# File lib/rye.rb, line 110
def reload
  pat = File.join(File.dirname(__FILE__), 'rye')
  %{key rap cmd box set hop}.each {|lib| load File.join(pat, "#{lib}.rb") }
end
remote_host_keys (*hostnames)
[show source]
# File lib/rye.rb, line 168
def remote_host_keys(*hostnames)
  hostnames = hostnames.flatten.compact || []
  return if hostnames.empty?
  Rye.shell("ssh-keyscan", hostnames)
end
shell (cmd, *args)

Execute a local system command (via the shell, not SSH)

  • cmd the executable path (relative or absolute)

  • args Array of arguments to be sent to the command. Each element

is one argument:. i.e. ['-l', 'some/path']

NOTE: shell is a bit paranoid so it escapes every argument. This means you can only use literal values. That means no asterisks too.

Returns a Rye::Rap object.

[show source]
# File lib/rye.rb, line 231
def shell(cmd, *args)
  args = args.flatten.compact
  cmd = cmd.to_s if cmd.is_a?(Symbol)
  # TODO: allow stdin to be sent to the cmd
  tf = Tempfile.new(cmd)
  cmd = Rye.prepare_command(cmd, args)
  cmd << " 2>#{tf.path}" # Redirect STDERR to file. Works in DOS too.
  # Deal with STDOUT
  handle = IO.popen(cmd, "r")
  stdout = handle.read.chomp
  handle.close
  # Then STDERR
  stderr = File.exists?(tf.path) ? File.read(tf.path) : ''
  tf.delete
  # Create the response object
  rap = Rye::Rap.new(self)
  rap.add_stdout(stdout || '')
  rap.add_stderr(stderr || '')
  rap.add_exit_status($?)
  rap
end
sshagent_info ()
[show source]
# File lib/rye.rb, line 261
def sshagent_info
  @@agent_env
end
strand ( len=8, safe=true )

Generates a string of random alphanumeric characters.

  • len is the length, an Integer. Default: 8

  • safe in safe-mode, ambiguous characters are removed (default: true):

    i l o 1 0
[show source]
# File lib/rye.rb, line 277
def strand( len=8, safe=true )
   chars = ("a".."z").to_a + ("0".."9").to_a
   chars.delete_if { |v| %(i l o 1 0).member?(v) } if safe
   str = ""
   1.upto(len) { |i| str << chars[rand(chars.size-1)] }
   str
end
sysinfo ()

Accessor for an instance of SystemInfo

[show source]
# File lib/rye.rb, line 81
def sysinfo; Rye.sysinfo end
which (executable)

An all ruby implementation of unix "which" command.

  • executable the name of the executable

Returns the absolute path if found in PATH otherwise nil.

[show source]
# File lib/rye.rb, line 208
def which(executable)
  return unless executable.is_a?(String)
  return executable if Rye.sysinfo.os == :windows
  #return executable if File.exists?(executable) # SHOULD WORK, MUST TEST
  shortname = File.basename(executable)
  dir = Rye.sysinfo.paths.select do |path|    # dir contains all of the
    next unless File.exists? path             # occurrences of shortname
    Dir.new(path).entries.member?(shortname)  # found in the paths.
  end
  File.join(dir.first, shortname) unless dir.empty? # Return just the first
end
without_indent (str)

Returns str with the leading indentation removed. Stolen from github.com/mynyml/unindent/ because it was better.

[show source]
# File lib/rye.rb, line 267
def without_indent(str)
  indent = str.split($/).each {|line| !line.strip.empty? }.map {|line| line.index(/[^\s]/) }.compact.min
  str.gsub(/^[[:blank:]]{#{indent}}/, '')
end