delano-rye 0.8.4 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES.txt +10 -1
- data/README.rdoc +127 -58
- data/lib/rye.rb +3 -4
- data/lib/rye/box.rb +26 -8
- data/rye.gemspec +1 -1
- 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
|
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
|
-
|
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
|
-
==
|
9
|
-
|
10
|
-
One of:
|
8
|
+
== Overview
|
11
9
|
|
12
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
35
|
+
== Example 2 -- Paths and environment variables
|
27
36
|
|
28
|
-
|
37
|
+
You can change directories.
|
29
38
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
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(
|
42
|
-
rbox.
|
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
|
-
|
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
|
87
|
+
rset.add_boxes(rbox, 'HOST2') # Add boxes as hostnames or objects
|
49
88
|
|
50
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
p rset['/etc'].ls # => [['file1', 'file2', ...], ['life1', 'life2', ...]]
|
91
|
+
rset.hostname # => [["HOST1"], ["HOST2"]]
|
92
|
+
rset.uname # => [["Darwin"], ["Linux"]]
|
93
|
+
rset.
|
56
94
|
|
57
|
-
==
|
95
|
+
== Example 5b -- Accessing Multiple Machines in Parallel
|
58
96
|
|
59
|
-
By default, Rye
|
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
|
-
|
62
|
-
|
63
|
-
|
99
|
+
rset = Rye::Set.new "SETNAME", :parallel => true
|
100
|
+
OR
|
101
|
+
rset.parallel = true
|
64
102
|
|
65
103
|
|
66
|
-
==
|
104
|
+
== Example 6 -- File Transfers
|
67
105
|
|
68
|
-
rbox = Rye::Box.new
|
106
|
+
rbox = Rye::Box.new "localhost"
|
69
107
|
|
70
|
-
|
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
|
76
|
-
rbox.file_upload
|
110
|
+
applejack = StringIO.new "Some in-memory content"
|
111
|
+
rbox.file_upload applejack, "/tmp/applejack.txt"
|
77
112
|
|
78
|
-
|
79
|
-
|
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
|
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
|
-
==
|
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
|
-
==
|
187
|
+
== Installation
|
188
|
+
|
189
|
+
Via Rubygems, one of:
|
139
190
|
|
140
|
-
|
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
|
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
|
-
*
|
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
|
-
*
|
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
|
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.
|
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
|
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
|
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(
|
433
|
-
|
434
|
-
|
435
|
-
|
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
|
+
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"
|