rye 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.
@@ -1,6 +1,6 @@
1
1
  = Rye - v0.8
2
2
 
3
- <strong>Safely run SSH commands on a bunch of machines at the same time (from Ruby).</strong>
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(rbox, 'HOST2') # Add boxes as hostnames or objects
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
- #%w{net-ssh sysinfo drydock}.each { |dir| $:.unshift File.join(File.dirname(__FILE__), '..', '..', dir, 'lib') }
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.join(' ')
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 :off
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.5".freeze
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
- key.split(/\s+/)
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
- cmd = Rye.which(cmd)
169
- raise CommandNotFound.new(cmd || 'nil') unless 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, cmd, *args)
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
- begin
318
- @@mutex.synchronize { # One thread only
319
- start_sshagent_environment # Run this now
320
- at_exit { end_sshagent_environment } # Run this before Ruby exits
321
- }
322
-
323
- rescue => ex
324
- STDERR.puts "Error initializing the SSH Agent (is OpenSSH installed?):"
325
- STDERR.puts ex.message
326
- STDERR.puts ex.backtrace
327
- exit 1
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
 
@@ -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
- @rye_opts.delete(:keys)
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 |key|
387
- path = key[2]
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 |key|
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
 
@@ -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
- b = box.is_a?(String) ? Rye::Box.new(box, @opts) : box
59
- b.add_keys(@keys)
60
- b
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
@@ -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.5"
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.5
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-07-15 00:00:00 -04:00
12
+ date: 2009-08-04 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency