Skip to content

Latest commit

 

History

History
148 lines (85 loc) · 5.15 KB

README.rdoc

File metadata and controls

148 lines (85 loc) · 5.15 KB

Rye - v0.8

Safely run SSH commands on a bunch of machines at the same time (from Ruby).

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

Installation

One of:

$ sudo gem install rye
$ sudo gem install delano-rye --source http://gems.github.com/
$ git clone git://github.com/delano/rye.git

See bin/try for examples!

EXAMPLE 1 – SSH Authorization

Does it annoy you to manually authorize remote SSH accounts? Rye can help!

Enable passwordless logins to HOST1 and HOST2:

$ rye authorize HOST1 HOST2

This will copy your public SSH keys to the ~/.ssh/authorized_keys and ~/.ssh/authorized_keys2 files on the remote machine(s).

See rye -h for more info

EXAMPLE 2 – Basic Usage

rbox = Rye::Box.new('localhost')
rbox.uptime                            # => 11:02  up 16:01, 3 users
rbox['/usr/bin'].pwd                   # => /usr/bin

You can specify environment variables

rbox.setenv(:RYE, "Forty Creek")
rbox.env             # => ['HOME=/home/rye', 'RYE=Forty Creek', ...]

EXAMPLE 3a – Accessing Multiple Machines

rset = Rye::Set.new
rbox = Rye::Box.new

rset.add_boxes(rbox, 'localhost')      # Add boxes as hostnames or objects

Calling methods on Rye::Set objects is very similar to calling them on Rye::Box objects. In fact, it’s identical:

p rset.uptime        # => [[14:19:02 up 32 days, 19:35 ...], [14:19:02 up 30 days, 01:35]]
p rset['/etc'].ls    # => [['file1', 'file2', ...], ['life1', 'life2', ...]]

EXAMPLE 3b – Accessing Multiple Machines – In Parallel

By default, Rye:Set connects to each machine sequentially in the order they were added to the set. Commands can also be run in parallel:

rset = Rye::Set.new('set-name', :parallel => true)
  OR
rset.parallel = true

EXAMPLE 4 – File Transfers

rbox = Rye::Box.new("localhost", :info => true)

dir_upload = "#{Rye.sysinfo.tmpdir}/rye-upload/"
dir_download = "#{Rye.sysinfo.tmpdir}/rye-download/"

rbox.file_upload("#{RYE_HOME}/README.rdoc", 
            "#{RYE_HOME}/LICENSE.txt", dir_upload)

applejack = StringIO.new("Some in-memory content")
rbox.file_upload(applejack, "#{dir_upload}/applejack.txt")

p rbox.ls(dir_upload)      # => [README.rdoc, LICENSE.txt, applejack.txt]
p rbox.cat("#{dir_upload}/applejack.txt")   # => "Some in-memory content"

filecontent = StringIO.new
rbox.file_download("#{dir_upload}/applejack.txt", filecontent)

p filecontent.read

About Safe-Mode

In safe-mode:

  • You can’t use file globs. This means you can’t do this: rbox.ls('*.rb'). ~ also doesn’t work!

  • You can’t use environment variables as arguments. This means you can’t do this: rbox.echo('$HOME'). However, environment variables are available to the commands you run.

  • Pipes and operators don’t work: |, &&, >, <, ||, ~, etc…

  • Backticks don’t work either: procs=`ps aux`

Why? In safe-mode, all command arguments are escaped which turns all arguments into their literal values.

Using a Ruby interface to execute shell commands is pretty awesome, particularly to run them on several machines simultaneously. That’s a lot of power and it’s potentially very dangerous. That’s why Rye disables this stuff by default. There’s probably a way to do it safely but it’s not obvious yet (to me). If you have any ideas, I’d love to hear them!

Command Whitelist

Rye permits only a limited number of system commands to be run. This default whitelist is defined in Rye::Cmd but you can add your own commands as you please (see Example 3).

Dependencies

  • OpenSSL (The C library)

  • Ruby Gems:

    • net-ssh

    • net-scp

    • highline

    • drydock

    • sysinfo

    • storable

Known Issues

This list will grow. If you find one let me know!

  • Rye doesn’t read the ~/.ssh/config file yet

  • Rye uses OpenSSL’s ssh-agent (if it exists). Rye starts it up as a child process and shuts it down using at_exit. If you have code in an at_exit that rely’s on Rye, make sure your code runs before Rye’s at_exit block is called. For example, Drydock uses at_exit too which is why in bin/rye you can see that Drydock is called explicitly so that Rye’s at_exit is executed after Drydock executes a command.

Thanks

More Info

Credits

  • Delano Mandelbaum (delano@solutious.com)

  • Escape, Copyright © 2006,2007 Tanaka Akira <akr@fsij.org>

  • Rye::Box#instance_exec (for Ruby 1.8) Mauricio Fernandez

License

See: LICENSE.txt