delano-rye 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/CHANGES.txt +10 -1
  2. data/README.rdoc +127 -58
  3. data/lib/rye.rb +3 -4
  4. data/lib/rye/box.rb +26 -8
  5. data/rye.gemspec +1 -1
  6. metadata +1 -1
data/CHANGES.txt CHANGED
@@ -6,6 +6,15 @@ TODO
6
6
  * Fingerprints: ssh-keygen -l -f id_rsa_repos.pub
7
7
 
8
8
 
9
+ #### 0.8.5 (2009-07-14) #############################
10
+
11
+ * CHANGE: Rye::Box#getenv now accepts an option key name
12
+ * CHANGE: When not in safe mode, method missing will execute a
13
+ method name as a shell command
14
+ * ADDED: Rye::Box#execute for running arbitrary commands when
15
+ not in safe mode
16
+
17
+
9
18
  #### 0.8.4 (2009-06-30) #############################
10
19
 
11
20
  * FIXED: Reference to (still) non-existent net-ssh 2.0.12 is now 2.0.11
@@ -208,7 +217,7 @@ Rye.shell and Rye::Box.run_command (SSH) commands.
208
217
  * ADDED: hostname command to Rye::Cmd
209
218
  * ADDED: Rye::Box.connect now supports multiple password attempts if STDIN.tty returns true
210
219
  * ADDED: Rye::Box.interactive_ssh for opening an SSH session to the given box.
211
- * CHANGE: Using OpenSSL's ssh-agent but also let's Net::SSH handle the ssh keys.
220
+ * CHANGE: Using OpenSSH's ssh-agent but also let's Net::SSH handle the ssh keys.
212
221
 
213
222
 
214
223
  #### 0.4.1 (2009-04-06) #############################
data/README.rdoc CHANGED
@@ -1,89 +1,125 @@
1
1
  = Rye - v0.8
2
2
 
3
- Safely run SSH commands on a bunch of machines at the same time (from Ruby).
3
+ <strong>Safely run SSH commands on a bunch of machines at the same time (from Ruby).</strong>
4
4
 
5
- Rye is similar to Rush[http://rush.heroku.com] 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: <tt>rbox.rm('-rf', '/etc/**/*')</tt>.
5
+ Inspired by Rush[http://rush.heroku.com] and compatible with Ruby 1.8, 1.9, and JRuby 1.3+!
6
6
 
7
7
 
8
- == Installation
9
-
10
- One of:
8
+ == Overview
11
9
 
12
- $ sudo gem install rye
13
- $ sudo gem install delano-rye --source http://gems.github.com/
14
- $ git clone git://github.com/delano/rye.git
10
+ Rye is a Ruby abstraction for executing shell commands via SSH. By default, Rye errs on the side of caution by running in "safe-mode" which specifies a default whitelist of commands and aggressively escapes all command arguments. For example, file globs and the "rm" command are not available in safe-mode, so you can't do this: <tt>rbox.rm('-rf', '/etc/**/*')</tt>.
15
11
 
12
+ Rye does not require anything to be installed on the server side (other than an SSH daemon) so it can be run from any machine with Ruby, OpenSSL, and OpenSSH.
16
13
 
17
- See bin/try for examples!
14
+
15
+ == Example 1 -- Execute commands on a remote machine
18
16
 
17
+ Shell commands are executed by calling methods on a Rye::Box object.
18
+
19
+ rbox = Rye::Box.new('hostname')
20
+ rbox.pwd # => "/home/rye"
21
+ rbox.uname :a # => "Darwin rye-stage 9.7.0 ..."
19
22
 
20
- == EXAMPLE 1 -- SSH Authorization
23
+ Method arguments are sent directly as arguments to the shell command. Single-character Symbols are assumed to be single-character switches. <em>e.g. <tt>rbox.uname :a</tt> becomes <tt>uname -a</tt>.</em>
24
+
25
+ The return value for a command is a modified Array containing the contents of STDOUT split by line. It also gives access to STDERR and the exit code
21
26
 
22
- Does it annoy you to manually authorize remote SSH accounts? Rye can help!
27
+ ret = rbox.uptime # => "11:02 up 16:01, 3 users"
28
+ ret.stderr # => []
29
+ ret.exit_code # => 0
30
+ ret.stdout # => "11:02 up 16:01, 3 users"
31
+ ret.stdout.class # => Array
32
+ ret.class # => Rye::Rap
23
33
 
24
- Enable passwordless logins to HOST1 and HOST2:
25
34
 
26
- $ rye authorize HOST1 HOST2
35
+ == Example 2 -- Paths and environment variables
27
36
 
28
- This will copy your public SSH keys to the <tt>~/.ssh/authorized_keys</tt> and <tt>~/.ssh/authorized_keys2</tt> files on the remote machine(s).
37
+ You can change directories.
29
38
 
30
- See <tt>rye -h</tt> for more info
31
-
32
-
33
- == EXAMPLE 2 -- Basic Usage
39
+ rbox.cd '/tmp'
40
+ rbox.pwd # => '/tmp'
41
+ rbox['/etc'].ls # => ['apache', 'init.d', ...]
42
+ rbox.pwd # => '/etc'
43
+ rbox.cd # => '/home/rye'
34
44
 
35
- rbox = Rye::Box.new('localhost')
36
- rbox.uptime # => 11:02 up 16:01, 3 users
37
- rbox['/usr/bin'].pwd # => /usr/bin
38
-
39
- You can specify environment variables
45
+ You can specify environment variables.
40
46
 
41
- rbox.setenv(:RYE, "Forty Creek")
42
- rbox.env # => ['HOME=/home/rye', 'RYE=Forty Creek', ...]
47
+ rbox.setenv('TIPPLE', "Forty Creek")
48
+ rbox.getenv 'TIPPLE' # => "Forty Creek"
43
49
 
50
+
51
+ == Example 3 -- Adding and removing commands
52
+
53
+ You can add and remove commands to the whitelist.
54
+
55
+ rbox.add_command :anything, '/path/2/anything'
56
+ rbox.anything
57
+ rbox.remove_command :anything
58
+ rbox.anything # => Rye::CommandNotFound exception
59
+
60
+
61
+ == Example 4 -- Disabling Safe Mode
62
+
63
+ Safe mode can be disabled on one of the following ways.
64
+
65
+ rbox = Rye::Box.new 'HOST', :safe => false
66
+ OR
67
+ rbox.disable_safe_mode
68
+
69
+ When safe-mode is disabled, you can run any command (regardless of what is defined in the whitelist) with any valid arguments (fileglobs, tildas, etc...).
70
+
71
+ rbox.kill '-SIGHUP', 1928111
72
+ rbox.rm 'path/2/*'
44
73
 
45
- == EXAMPLE 3a -- Accessing Multiple Machines
74
+ You can also execute any valid shell command.
75
+
76
+ rbox.execute 'ps aux | grep ruby > /tmp/ruby-process-list'
46
77
 
78
+ See the "About Safe Mode" section below for more information.
79
+
80
+
81
+ == Example 5a -- Accessing Multiple Machines
82
+
83
+ Shell commands can be executed on multiple machines using a Rye::Set object. Create a "set" of machines.
84
+
85
+ rbox = Rye::Box.new 'HOST1
47
86
  rset = Rye::Set.new
48
- rbox = Rye::Box.new
87
+ rset.add_boxes(rbox, 'HOST2') # Add boxes as hostnames or objects
49
88
 
50
- rset.add_boxes(rbox, 'localhost') # Add boxes as hostnames or objects
89
+ Then call methods just like with Rye::Box, except now the return value is an Array of Arrays. The order of return values matches the order the machines were added to the set.
51
90
 
52
- Calling methods on Rye::Set objects is very similar to calling them on Rye::Box objects. In fact, it's identical:
53
-
54
- p rset.uptime # => [[14:19:02 up 32 days, 19:35 ...], [14:19:02 up 30 days, 01:35]]
55
- p rset['/etc'].ls # => [['file1', 'file2', ...], ['life1', 'life2', ...]]
91
+ rset.hostname # => [["HOST1"], ["HOST2"]]
92
+ rset.uname # => [["Darwin"], ["Linux"]]
93
+ rset.
56
94
 
57
- == EXAMPLE 3b -- Accessing Multiple Machines -- In Parallel
95
+ == Example 5b -- Accessing Multiple Machines in Parallel
58
96
 
59
- 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:
97
+ 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.
60
98
 
61
- rset = Rye::Set.new('set-name', :parallel => true)
62
- OR
63
- rset.parallel = true
99
+ rset = Rye::Set.new "SETNAME", :parallel => true
100
+ OR
101
+ rset.parallel = true
64
102
 
65
103
 
66
- == EXAMPLE 4 -- File Transfers
104
+ == Example 6 -- File Transfers
67
105
 
68
- rbox = Rye::Box.new("localhost", :info => true)
106
+ rbox = Rye::Box.new "localhost"
69
107
 
70
- dir_upload = "#{Rye.sysinfo.tmpdir}/rye-upload/"
71
- dir_download = "#{Rye.sysinfo.tmpdir}/rye-download/"
72
-
73
- rbox.file_upload("#{RYE_HOME}/README.rdoc", "#{RYE_HOME}/LICENSE.txt", dir_upload)
108
+ rbox.file_upload "README.rdoc", "/tmp"
74
109
 
75
- applejack = StringIO.new("Some in-memory content")
76
- rbox.file_upload(applejack, "#{dir_upload}/applejack.txt")
110
+ applejack = StringIO.new "Some in-memory content"
111
+ rbox.file_upload applejack, "/tmp/applejack.txt"
77
112
 
78
- p rbox.ls(dir_upload) # => [README.rdoc, LICENSE.txt, applejack.txt]
79
- p rbox.cat("#{dir_upload}/applejack.txt") # => "Some in-memory content"
113
+ rbox.ls "/tmp/" # => [README.rdoc, applejack.txt]
114
+ rbox.cat "/tmp/applejack.txt" # => "Some in-memory content"
80
115
 
81
116
  filecontent = StringIO.new
82
- rbox.file_download("#{dir_upload}/applejack.txt", filecontent)
117
+ rbox.file_download "/tmp/applejack.txt", filecontent
118
+
119
+ filecontent.read # => "Some in-memory content"
83
120
 
84
- p filecontent.read
85
121
 
86
- == EXAMPLE 5 -- Local processes
122
+ == Example 7 -- Local processes
87
123
 
88
124
  For local processes, you can bypass <tt>Rye::Box</tt> and execute commands directly with <tt>Rye.shell</tt>:
89
125
 
@@ -104,6 +140,18 @@ The return value is a Rye::Rap object (just like with Rye::Box) so you have acce
104
140
  ret.class # => Rye::Rap
105
141
 
106
142
 
143
+ == Example 8 -- SSH Authorization
144
+
145
+ Does it annoy you to manually authorize remote SSH accounts? Rye can help!
146
+
147
+ Enable passwordless logins to HOST1 and HOST2:
148
+
149
+ $ rye authorize HOST1 HOST2
150
+
151
+ This will copy your public SSH keys to the <tt>~/.ssh/authorized_keys</tt> and <tt>~/.ssh/authorized_keys2</tt> files on the remote machine(s).
152
+
153
+ See <tt>rye -h</tt> for more info.
154
+
107
155
 
108
156
  == About Safe-Mode
109
157
 
@@ -125,6 +173,7 @@ Rye permits only a limited number of system commands to be run. This default whi
125
173
 
126
174
  == Dependencies
127
175
 
176
+ * OpenSSH[http://www.openssh.com/]
128
177
  * OpenSSL[http://www.openssl.org] (The C library)
129
178
  * Ruby Gems:
130
179
  * net-ssh
@@ -135,34 +184,54 @@ Rye permits only a limited number of system commands to be run. This default whi
135
184
  * storable
136
185
 
137
186
 
138
- == Known Issues
187
+ == Installation
188
+
189
+ Via Rubygems, one of:
139
190
 
140
- This list will grow. If you find one let me know!
191
+ $ gem install rye
192
+ $ gem install delano-rye --source http://gems.github.com/
193
+
194
+ or via download:
195
+
196
+ * rye-latest.tar.gz[http://github.com/delano/rye/tarball/latest]
197
+ * rye-latest.zip[http://github.com/delano/rye/zipball/latest]
198
+
199
+
200
+ == Known Issues
141
201
 
142
202
  * Rye doesn't read the ~/.ssh/config file yet
143
- * 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.
203
+ * Rye uses OpenSSH'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.
204
+ * No support for STDIN.
205
+
206
+ If you find one let me know!
144
207
 
145
208
 
146
209
  == Thanks
147
210
 
148
- * Solutious Incorporated (http://solutious.com) for all the orange juice.
149
211
  * Kalin Harvey (http://rely.ca)
150
- * Rush[http://github.com/adamwiggins/rush]
151
- * Capistrano[http://github.com/jamis/capistrano/blob/master/lib/capistrano/shell.rb]
212
+ * Rush[http://github.com/adamwiggins/rush] and Capistrano[http://github.com/jamis/capistrano/blob/master/lib/capistrano/shell.rb] for the inspiration.
213
+ * Mike Cline for giving the okay to use the Rye name.
152
214
 
153
215
 
154
216
  == More Info
155
217
 
156
- * GitHub[http://github.com/delano/rye]
218
+ * Codes[http://github.com/delano/rye]
157
219
  * Rdocs[http://delano.github.com/rye]
158
220
  * Inspiration[http://www.youtube.com/watch?v=_StUVh6ENuw]
159
221
 
222
+
223
+ == Related Projects
224
+
225
+ * Rush[http://github.com/adamwiggins/rush]
226
+
227
+
160
228
  == Credits
161
229
 
162
- * Delano Mandelbaum (delano@solutious.com)
230
+ * Delano (@solutious.com)
163
231
  * Escape, Copyright (C) 2006,2007 Tanaka Akira <akr@fsij.org>
164
232
  * Rye::Box#instance_exec (for Ruby 1.8) Mauricio Fernandez
165
233
 
234
+
166
235
  == License
167
236
 
168
237
  See: LICENSE.txt
data/lib/rye.rb CHANGED
@@ -43,7 +43,7 @@ module Rye
43
43
  extend self
44
44
 
45
45
  unless defined?(SYSINFO)
46
- VERSION = "0.8.4".freeze
46
+ VERSION = "0.8.5".freeze
47
47
  SYSINFO = SysInfo.new.freeze
48
48
  end
49
49
 
@@ -277,8 +277,7 @@ module Rye
277
277
  # $ SSH_AUTH_SOCK=/tmp/ssh-tGvaOXIXSr/agent.12951; export SSH_AUTH_SOCK;
278
278
  # $ SSH_AGENT_PID=12952; export SSH_AGENT_PID;
279
279
  #
280
- # NOTE: The OpenSSL library (The C one, not the Ruby one)
281
- # must be installed for this to work.
280
+ # NOTE: The OpenSSH library must be installed for this to work.
282
281
  #
283
282
  def start_sshagent_environment
284
283
  return if @@agent_env["SSH_AGENT_PID"]
@@ -322,7 +321,7 @@ module Rye
322
321
  }
323
322
 
324
323
  rescue => ex
325
- STDERR.puts "Error initializing the SSH Agent (is OpenSSL installed?):"
324
+ STDERR.puts "Error initializing the SSH Agent (is OpenSSH installed?):"
326
325
  STDERR.puts ex.message
327
326
  STDERR.puts ex.backtrace
328
327
  exit 1
data/lib/rye/box.rb CHANGED
@@ -48,6 +48,7 @@ module Rye
48
48
 
49
49
  def enable_safe_mode; @rye_safe = true; end
50
50
  def disable_safe_mode; @rye_safe = false; end
51
+ def safe?; @rye_safe == true; end
51
52
 
52
53
  def enable_quiet_mode; @rye_quiet = true; end
53
54
  def disable_quiet_mode; @rye_quiet = false; end
@@ -253,7 +254,7 @@ module Rye
253
254
  # NOTE: This method should not raise an exception under normal
254
255
  # circumstances.
255
256
  #
256
- def getenv
257
+ def getenv(key=nil)
257
258
  if @rye_getenv && @rye_getenv.empty? && self.can?(:env)
258
259
  vars = self.quietly { env } rescue []
259
260
  vars.each do |nvpair|
@@ -263,7 +264,7 @@ module Rye
263
264
  @rye_getenv[n] = v
264
265
  end
265
266
  end
266
- @rye_getenv
267
+ key.nil? ? @rye_getenv : @rye_getenv[key.to_s]
267
268
  end
268
269
 
269
270
  # Add an environment variable. +n+ and +v+ are the name and value.
@@ -429,12 +430,22 @@ module Rye
429
430
 
430
431
  # A handler for undefined commands.
431
432
  # Raises Rye::CommandNotFound exception.
432
- def method_missing(meth, *args, &block)
433
- ex = Rye::CommandNotFound.new(meth.to_s)
434
- raise ex unless @rye_exception_hook.has_key? ex.class
435
- @rye_exception_hook[Rye::CommandNotFound].call ex
433
+ def method_missing(cmd, *args, &block)
434
+ if @rye_safe
435
+ ex = Rye::CommandNotFound.new(cmd.to_s)
436
+ raise ex unless @rye_exception_hook.has_key? ex.class
437
+ @rye_exception_hook[Rye::CommandNotFound].call ex
438
+ else
439
+ if block.nil?
440
+ run_command cmd, *args
441
+ else
442
+ ex = Rye::CommandNotFound.new(cmd.to_s)
443
+ raise ex unless @rye_exception_hook.has_key? ex.class
444
+ end
445
+ end
436
446
  end
437
-
447
+ alias :execute :method_missing
448
+
438
449
  # Returns the command an arguments as a String.
439
450
  def preview_command(*args)
440
451
  prep_args(*args).join(' ')
@@ -484,6 +495,13 @@ module Rye
484
495
  # OR
485
496
  # rbox.batch(&block)
486
497
  #
498
+ # The batch can also accept arguments.
499
+ #
500
+ # rbox.batch('path/2/file') do |file|
501
+ # ls :l file
502
+ # end
503
+ #
504
+ # Returns the return value of the block.
487
505
  #
488
506
  def batch(*args, &block)
489
507
  self.instance_exec *args, &block
@@ -736,7 +754,7 @@ module Rye
736
754
  elsif choice == :skip
737
755
  # do nothing
738
756
  else
739
- raise ex
757
+ raise ex, ex.message
740
758
  end
741
759
  end
742
760
 
data/rye.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "rye"
3
3
  s.rubyforge_project = "rye"
4
- s.version = "0.8.4"
4
+ s.version = "0.8.5"
5
5
  s.summary = "Rye: Safely run SSH commands on a bunch of machines at the same time (from Ruby)."
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delano-rye
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.4
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum