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.
- 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"
|