rye 0.8.5 → 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +5 -2
- data/README.rdoc +34 -18
- data/bin/rye +17 -3
- data/lib/rye.rb +22 -21
- data/lib/rye/box.rb +13 -8
- data/lib/rye/set.rb +11 -4
- data/rye.gemspec +1 -1
- metadata +2 -2
data/CHANGES.txt
CHANGED
@@ -6,6 +6,11 @@ TODO
|
|
6
6
|
* Fingerprints: ssh-keygen -l -f id_rsa_repos.pub
|
7
7
|
|
8
8
|
|
9
|
+
#### 0.8.6 (2009-08-04) #############################
|
10
|
+
|
11
|
+
* FIXED: SystemCallError / "Broken Pipe" error when disconnecting in JRuby 1.3
|
12
|
+
* FIXED: CommandNotFound: nil error in Windows
|
13
|
+
|
9
14
|
#### 0.8.5 (2009-07-14) #############################
|
10
15
|
|
11
16
|
* CHANGE: Rye::Box#getenv now accepts an option key name
|
@@ -19,13 +24,11 @@ TODO
|
|
19
24
|
|
20
25
|
* FIXED: Reference to (still) non-existent net-ssh 2.0.12 is now 2.0.11
|
21
26
|
|
22
|
-
|
23
27
|
#### 0.8.3 (2009-06-30) #############################
|
24
28
|
|
25
29
|
* ADDED: JRuby 1.3 support
|
26
30
|
* ADDED: Tryouts (i.e. better testing)
|
27
31
|
|
28
|
-
|
29
32
|
#### 0.8.2 (2009-06-23) #############################
|
30
33
|
|
31
34
|
* FIXED: Rye::Box.switch_user will disconnect but not create a new connection.
|
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Rye - v0.8
|
2
2
|
|
3
|
-
<
|
3
|
+
<b>Safely run SSH commands on a bunch of machines at the same time (from Ruby)</b>.
|
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
|
|
@@ -11,7 +11,34 @@ Rye is a Ruby abstraction for executing shell commands via SSH. By default, Rye
|
|
11
11
|
|
12
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.
|
13
13
|
|
14
|
-
|
14
|
+
=== SSH keys
|
15
|
+
|
16
|
+
You need SSH keys to use Rye. After installing Rye, you can check if you have any by running:
|
17
|
+
|
18
|
+
$ rye
|
19
|
+
|
20
|
+
If you get the message <i>"The agent has no identities"</i> you will need to generate a keypair.
|
21
|
+
|
22
|
+
$ ssh-keygen
|
23
|
+
|
24
|
+
|
25
|
+
=== Passwordless SSH authorization
|
26
|
+
|
27
|
+
The easiest way to work with Rye is to authorize your remote accounts for passwordless logins (otherwise you'll be prompted for a password for every connection).
|
28
|
+
|
29
|
+
Enable passwordless logins to remote HOST1 and HOST2:
|
30
|
+
|
31
|
+
$ rye authorize HOST1 HOST2
|
32
|
+
|
33
|
+
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).
|
34
|
+
|
35
|
+
Enable passwordless logins to the local machine:
|
36
|
+
|
37
|
+
$ rye authorize-local
|
38
|
+
|
39
|
+
See <tt>rye -h</tt> for more info.
|
40
|
+
|
41
|
+
|
15
42
|
== Example 1 -- Execute commands on a remote machine
|
16
43
|
|
17
44
|
Shell commands are executed by calling methods on a Rye::Box object.
|
@@ -82,15 +109,14 @@ See the "About Safe Mode" section below for more information.
|
|
82
109
|
|
83
110
|
Shell commands can be executed on multiple machines using a Rye::Set object. Create a "set" of machines.
|
84
111
|
|
85
|
-
rbox = Rye::Box.new 'HOST1
|
112
|
+
rbox = Rye::Box.new 'HOST1'
|
86
113
|
rset = Rye::Set.new
|
87
|
-
rset.add_boxes
|
114
|
+
rset.add_boxes rbox, 'HOST2' # Add boxes as hostnames or objects
|
88
115
|
|
89
116
|
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.
|
90
117
|
|
91
118
|
rset.hostname # => [["HOST1"], ["HOST2"]]
|
92
119
|
rset.uname # => [["Darwin"], ["Linux"]]
|
93
|
-
rset.
|
94
120
|
|
95
121
|
== Example 5b -- Accessing Multiple Machines in Parallel
|
96
122
|
|
@@ -140,18 +166,6 @@ The return value is a Rye::Rap object (just like with Rye::Box) so you have acce
|
|
140
166
|
ret.class # => Rye::Rap
|
141
167
|
|
142
168
|
|
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
|
-
|
155
169
|
|
156
170
|
== About Safe-Mode
|
157
171
|
|
@@ -197,11 +211,13 @@ or via download:
|
|
197
211
|
* rye-latest.zip[http://github.com/delano/rye/zipball/latest]
|
198
212
|
|
199
213
|
|
214
|
+
|
200
215
|
== Known Issues
|
201
216
|
|
202
217
|
* Rye doesn't read the ~/.ssh/config file yet
|
203
218
|
* 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.
|
219
|
+
* No support for STDIN for commands.
|
220
|
+
* Limited support for interactive shells.
|
205
221
|
|
206
222
|
If you find one let me know!
|
207
223
|
|
data/bin/rye
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
#
|
10
10
|
|
11
11
|
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
12
|
-
|
12
|
+
%w{net-ssh net-scp sysinfo drydock}.each { |dir| $:.unshift File.join(File.dirname(__FILE__), '..', '..', dir, 'lib') }
|
13
13
|
|
14
14
|
require 'stringio'
|
15
15
|
require 'yaml'
|
@@ -36,6 +36,20 @@ after do
|
|
36
36
|
|
37
37
|
end
|
38
38
|
|
39
|
+
option :u, :user, String, "User name to connect as"
|
40
|
+
option :i, :identity, String, "Private key"
|
41
|
+
argv :host
|
42
|
+
command :ssh do |obj|
|
43
|
+
raise "No host supplied" if obj.argv.empty?
|
44
|
+
opts = { :debug => true }
|
45
|
+
opts[:user] = obj.option.user || Rye.sysinfo.user
|
46
|
+
opts[:keys] = [obj.option.identity] || []
|
47
|
+
obj.argv.each do |host|
|
48
|
+
rbox = Rye::Box.new host, opts
|
49
|
+
p rbox.connect
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
39
53
|
about "Add your public keys to one or more remote machines"
|
40
54
|
usage "rye authorize [-u username] host"
|
41
55
|
option :u, :user, String, "Username"
|
@@ -92,7 +106,7 @@ command_alias :hostkeys, :hostkey
|
|
92
106
|
about "Display your private keys"
|
93
107
|
command :keys do |obj|
|
94
108
|
Rye.keys.each do |key|
|
95
|
-
puts key
|
109
|
+
puts key
|
96
110
|
end
|
97
111
|
end
|
98
112
|
|
@@ -112,7 +126,7 @@ command_alias :pubkeys, :pubkey
|
|
112
126
|
|
113
127
|
|
114
128
|
default :keys
|
115
|
-
debug :
|
129
|
+
debug :on
|
116
130
|
|
117
131
|
# We call Drydock specifically otherwise it will run at_exit. Rye also
|
118
132
|
# uses at_exit for shutting down the ssh-agent. Ruby executes at_exit
|
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.6".freeze
|
47
47
|
SYSINFO = SysInfo.new.freeze
|
48
48
|
end
|
49
49
|
|
@@ -134,11 +134,12 @@ module Rye
|
|
134
134
|
def keys
|
135
135
|
# 2048 76:cb:d7:82:90:92:ad:75:3d:68:6c:a9:21:ca:7b:7f /Users/rye/.ssh/id_rsa (RSA)
|
136
136
|
# 2048 7b:a6:ba:55:b1:10:1d:91:9f:73:3a:aa:0c:d4:88:0e /Users/rye/.ssh/id_dsa (DSA)
|
137
|
-
keystr = Rye.shell("ssh-add", '-l')
|
138
|
-
return nil unless keystr
|
139
|
-
keystr.collect do |key|
|
140
|
-
|
141
|
-
end
|
137
|
+
#keystr = Rye.shell("ssh-add", '-l')
|
138
|
+
#return nil unless keystr
|
139
|
+
#keystr.collect do |key|
|
140
|
+
# key.split(/\s+/)
|
141
|
+
#end
|
142
|
+
Dir.glob(File.join(Rye.sysinfo.home, '.ssh', 'id_*sa'))
|
142
143
|
end
|
143
144
|
|
144
145
|
def remote_host_keys(*hostnames)
|
@@ -165,15 +166,15 @@ module Rye
|
|
165
166
|
#
|
166
167
|
def prepare_command(cmd, *args)
|
167
168
|
args &&= [args].flatten.compact
|
168
|
-
|
169
|
-
raise CommandNotFound.new(cmd || '
|
169
|
+
found_cmd = Rye.which(cmd)
|
170
|
+
raise CommandNotFound.new(cmd || '[unknown]') unless found_cmd
|
170
171
|
# Symbols to switches. :l -> -l, :help -> --help
|
171
172
|
args.collect! do |a|
|
172
173
|
a = "-#{a}" if a.is_a?(Symbol) && a.to_s.size == 1
|
173
174
|
a = "--#{a}" if a.is_a?(Symbol)
|
174
175
|
a
|
175
176
|
end
|
176
|
-
Rye.escape(@safe,
|
177
|
+
Rye.escape(@safe, found_cmd, *args)
|
177
178
|
end
|
178
179
|
|
179
180
|
# An all ruby implementation of unix "which" command.
|
@@ -314,19 +315,19 @@ module Rye
|
|
314
315
|
|
315
316
|
Rye.reload
|
316
317
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
318
|
+
unless Rye.sysinfo.os == :win32
|
319
|
+
begin
|
320
|
+
@@mutex.synchronize { # One thread only
|
321
|
+
start_sshagent_environment # Run this now
|
322
|
+
at_exit { end_sshagent_environment } # Run this before Ruby exits
|
323
|
+
}
|
324
|
+
rescue => ex
|
325
|
+
STDERR.puts "Error initializing the SSH Agent (is OpenSSH installed?):"
|
326
|
+
STDERR.puts ex.message
|
327
|
+
STDERR.puts ex.backtrace
|
328
|
+
exit 1
|
329
|
+
end
|
328
330
|
end
|
329
|
-
|
330
331
|
end
|
331
332
|
|
332
333
|
|
data/lib/rye/box.rb
CHANGED
@@ -120,6 +120,7 @@ module Rye
|
|
120
120
|
|
121
121
|
@rye_opts[:logger] = Logger.new(@rye_debug) if @rye_debug # Enable Net::SSH debugging
|
122
122
|
@rye_opts[:paranoid] = true unless @rye_safe == false # See Net::SSH.start
|
123
|
+
@rye_opts[:keys] = [@rye_opts[:keys]].flatten.compact
|
123
124
|
|
124
125
|
# Add the given private keys to the keychain that will be used for @rye_host
|
125
126
|
add_keys(@rye_opts[:keys])
|
@@ -127,7 +128,7 @@ module Rye
|
|
127
128
|
# We don't want Net::SSH to handle the keypairs. This may change
|
128
129
|
# but for we're letting ssh-agent do it.
|
129
130
|
# TODO: Check if this should ot should not be enabled.
|
130
|
-
|
131
|
+
#@rye_opts.delete(:keys)
|
131
132
|
|
132
133
|
# From: capistrano/lib/capistrano/cli.rb
|
133
134
|
STDOUT.sync = true # so that Net::SSH prompts show up
|
@@ -220,9 +221,14 @@ module Rye
|
|
220
221
|
# * +additional_keys+ is a list of file paths to private keys
|
221
222
|
# Returns the instance of Box
|
222
223
|
def add_keys(*additional_keys)
|
224
|
+
if Rye.sysinfo.os == :win32
|
225
|
+
@rye_opts[:keys] ||= []
|
226
|
+
@rye_opts[:keys] += additional_keys.flatten
|
227
|
+
return @rye_opts[:keys]
|
228
|
+
end
|
223
229
|
additional_keys = [additional_keys].flatten.compact || []
|
224
230
|
return if additional_keys.empty?
|
225
|
-
ret = Rye.add_keys(additional_keys)
|
231
|
+
ret = Rye.add_keys(additional_keys)
|
226
232
|
if ret.is_a?(Rye::Rap)
|
227
233
|
debug "ssh-add exit_code: #{ret.exit_code}"
|
228
234
|
debug "ssh-add stdout: #{ret.stdout}"
|
@@ -383,8 +389,8 @@ module Rye
|
|
383
389
|
end
|
384
390
|
authorized_keys ||= StringIO.new
|
385
391
|
|
386
|
-
Rye.keys.each do |
|
387
|
-
|
392
|
+
Rye.keys.each do |path|
|
393
|
+
|
388
394
|
info "# Adding public key for #{path}"
|
389
395
|
k = Rye::Key.from_file(path).public_key.to_ssh2
|
390
396
|
authorized_keys.puts k
|
@@ -415,8 +421,7 @@ module Rye
|
|
415
421
|
# authorize_keys_remote except run with local shell commands.
|
416
422
|
def authorize_keys_local
|
417
423
|
added_keys = []
|
418
|
-
Rye.keys.each do |
|
419
|
-
path = key[2]
|
424
|
+
Rye.keys.each do |path|
|
420
425
|
debug "# Public key for #{path}"
|
421
426
|
k = Rye::Key.from_file(path).public_key.to_ssh2
|
422
427
|
Rye.shell(:mkdir, :p, :m, '700', '$HOME/.ssh') # Silently create dir if it doesn't exist
|
@@ -590,7 +595,7 @@ module Rye
|
|
590
595
|
debug "Opening connection to #{@rye_host} as #{@rye_opts[:user]}"
|
591
596
|
highline = HighLine.new # Used for password prompt
|
592
597
|
retried = 0
|
593
|
-
|
598
|
+
@rye_opts[:keys].compact! # A quick fix in Windows. TODO: Why is there a nil?
|
594
599
|
begin
|
595
600
|
@rye_ssh = Net::SSH.start(@rye_host, @rye_opts[:user], @rye_opts || {})
|
596
601
|
rescue Net::SSH::HostKeyMismatch => ex
|
@@ -633,7 +638,7 @@ module Rye
|
|
633
638
|
Timeout::timeout(3) do
|
634
639
|
@rye_ssh.loop(0.3) { @rye_ssh.busy?; }
|
635
640
|
end
|
636
|
-
rescue Timeout::Error => ex
|
641
|
+
rescue SystemCallError, Timeout::Error => ex
|
637
642
|
error "Disconnect timeout (was something still running?)"
|
638
643
|
end
|
639
644
|
|
data/lib/rye/set.rb
CHANGED
@@ -42,7 +42,9 @@ module Rye
|
|
42
42
|
@safe = @opts.delete(:safe)
|
43
43
|
@debug = @opts.delete(:debug)
|
44
44
|
@error = @opts.delete(:error)
|
45
|
-
|
45
|
+
|
46
|
+
@opts[:keys] = [@opts[:keys]].flatten.compact
|
47
|
+
|
46
48
|
add_keys(@opts[:keys])
|
47
49
|
end
|
48
50
|
|
@@ -55,9 +57,9 @@ module Rye
|
|
55
57
|
def add_box(*boxes)
|
56
58
|
boxes = boxes.flatten.compact
|
57
59
|
@boxes += boxes.collect do |box|
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
box = Rye::Box.new(box, @opts) if box.is_a?(String)
|
61
|
+
box.add_keys(@keys)
|
62
|
+
box
|
61
63
|
end
|
62
64
|
self
|
63
65
|
end
|
@@ -67,6 +69,11 @@ module Rye
|
|
67
69
|
# * +additional_keys+ is a list of file paths to private keys
|
68
70
|
# Returns the instance of Rye::Set
|
69
71
|
def add_key(*additional_keys)
|
72
|
+
if Rye.sysinfo.os == :win32
|
73
|
+
@opts[:keys] ||= []
|
74
|
+
@opts[:keys] += additional_keys.flatten
|
75
|
+
return @opts[:keys]
|
76
|
+
end
|
70
77
|
additional_keys = [additional_keys].flatten.compact || []
|
71
78
|
Rye.add_keys(additional_keys)
|
72
79
|
self
|
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.6"
|
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: rye
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delano Mandelbaum
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-08-04 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|