rye 0.8.5 → 0.8.6
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 +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
|