rye 0.4.3 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -4,6 +4,14 @@ TODO
4
4
 
5
5
  * Fingerprints: ssh-keygen -l -f id_rsa_repos.pub
6
6
 
7
+ #### 0.5.0 (2009-04-18) #############################
8
+
9
+ * ADDED: Rye::Box.switch_user
10
+ * ADDED: Several new commands to Rye::Cmd
11
+ * ADDED: Rye::Box.authorize_keys_local and "rye authorize-local
12
+ * FIXED: Bug in connect which prevented key-based logins for reconnections
13
+ * FIXED: Method errors in JRuby
14
+ * FIXED: Bug in Rye::Set.add_boxes pushing nils into the list of boxes
7
15
 
8
16
  #### 0.4.3 (2009-04-14) #############################
9
17
 
data/README.rdoc CHANGED
@@ -1,8 +1,8 @@
1
- = Rye - v0.4
1
+ = Rye - v0.5
2
2
 
3
3
  Safely run SSH commands on a bunch of machines at the same time (from Ruby).
4
4
 
5
- Rye is similar to Rush[http://rush.heroku.com] but everything happens over SSH (no HTTP daemon) and the default settings are less powerful (for safety). For example, file globs are disabled so unless otherwise specified, you can't do this: <tt>rbox.rm('-rf', '/etc/**/*')</tt>.
5
+ Rye is similar to Rush[http://rush.heroku.com] but everything happens over SSH (no HTTP daemon) and the default settings are less powerful (for safety). For example, file globs and the "rm" command are disabled so unless otherwise specified, you can't do this: <tt>rbox.rm('-rf', '/etc/**/*')</tt>.
6
6
 
7
7
  See the examples below (which are taken from bin/try).
8
8
 
data/bin/rye CHANGED
@@ -43,8 +43,8 @@ command :authorize do |obj|
43
43
 
44
44
  obj.argv.each do |hostname|
45
45
 
46
- rbox = Rye::Box.new(hostname, opts).connect
47
46
  puts "Authorizing #{rbox.opts[:user]}@#{hostname}"
47
+ rbox = Rye::Box.new(hostname, opts).connect
48
48
  puts "Added public keys for: ", rbox.authorize_keys
49
49
  puts "Now try: " << "ssh #{rbox.opts[:user]}@#{hostname}"
50
50
 
@@ -53,6 +53,17 @@ command :authorize do |obj|
53
53
  end
54
54
  command_alias :authorize, :authorise
55
55
 
56
+ desc "Add your public keys to your current account on this machine"
57
+ command :authorize_local do |obj|
58
+ user = Rye.sysinfo.user
59
+ puts "Authorizing #{user}@localhost"
60
+ rbox = Rye::Box.new('localhost').connect
61
+ puts "Added public keys for: ", rbox.authorize_keys_local
62
+ puts "Now try: " << "ssh #{user}@localhost"
63
+
64
+ end
65
+ command_alias :local_authorize, :local_authorise
66
+
56
67
 
57
68
  desc "Generate a public key from a private key"
58
69
 
data/bin/try CHANGED
@@ -107,9 +107,10 @@ puts %Q(
107
107
 
108
108
  rset = Rye::Set.new('default', :parallel => true)
109
109
  rbox = Rye::Box.new
110
+ p rbox
110
111
 
111
112
  rset.add_keys('/private/key/path') # For passwordless logins
112
- rset.add_boxes(rbox, 'localhost') # Add boxes as hostnames or objects
113
+ rset.add_boxes(rbox, '127.0.0.1') # Add boxes as hostnames or objects
113
114
 
114
115
  # Calling methods on Rye::Set objects is very similar to calling them on
115
116
  # Rye::Box objects. In fact, it's identical:
data/lib/rye/box.rb CHANGED
@@ -123,8 +123,12 @@ module Rye
123
123
  @current_working_directory = key
124
124
  self
125
125
  end
126
- alias :cd :'[]'
127
-
126
+ # alias :cd :'[]' # fix for jruby
127
+ def cd(key=nil);
128
+ @current_working_directory = key
129
+ self
130
+ end
131
+
128
132
  # Open an SSH session with +@host+. This called automatically
129
133
  # when you the first comamnd is run if it's not already connected.
130
134
  # Raises a Rye::NoHost exception if +@host+ is not specified.
@@ -133,9 +137,10 @@ module Rye
133
137
  def connect
134
138
  raise Rye::NoHost unless @host
135
139
  disconnect if @ssh
136
- debug "Opening connection to #{@host}"
140
+ debug "Opening connection to #{@host} as #{@opts[:user]}"
137
141
  highline = HighLine.new # Used for password prompt
138
142
  retried = 0
143
+
139
144
  begin
140
145
  @ssh = Net::SSH.start(@host, @opts[:user], @opts || {})
141
146
  rescue Net::SSH::AuthenticationFailed => ex
@@ -143,7 +148,7 @@ module Rye
143
148
  if STDIN.tty? && retried <= 3
144
149
  @opts[:password] = highline.ask("Password: ") { |q| q.echo = '' }
145
150
  @opts[:auth_methods] ||= []
146
- @opts[:auth_methods] = %w(password)
151
+ @opts[:auth_methods] << 'password'
147
152
  retry
148
153
  else
149
154
  STDERR.puts "Authentication failed."
@@ -151,10 +156,38 @@ module Rye
151
156
  end
152
157
  end
153
158
 
159
+ # We add :auth_methods (a Net::SSH joint) to force asking for a
160
+ # password if the initial (key-based) authentication fails. We
161
+ # need to delete the key from @opts otherwise it lingers until
162
+ # the next connection (if we switch_user is called for example).
163
+ @opts.delete :auth_methods if @opts.has_key?(:auth_methods)
164
+
154
165
  @ssh.is_a?(Net::SSH::Connection::Session) && !@ssh.closed?
155
166
  self
156
167
  end
157
168
 
169
+ # Close the SSH session with +@host+. This is called
170
+ # automatically at exit if the connection is open.
171
+ def disconnect
172
+ return unless @ssh && !@ssh.closed?
173
+ @ssh.loop(0.1) { @ssh.busy? }
174
+ debug "Closing connection to #{@ssh.host}"
175
+ @ssh.close
176
+ end
177
+
178
+ # Reconnect as another user
179
+ # * +newuser+ The username to reconnect as
180
+ #
181
+ # NOTE: if there is an open connection, it's disconnected
182
+ # and a new one is opened for the given user.
183
+ def switch_user(newuser)
184
+ return if newuser.to_s == self.user.to_s
185
+ @opts ||= {}
186
+ @opts[:user] = newuser
187
+ disconnect
188
+ connect
189
+ end
190
+
158
191
  # Open an interactive SSH session. This only works if STDIN.tty?
159
192
  # returns true. Otherwise it returns the SSH command that would
160
193
  # have been run. This requires the SSH command-line executable (ssh).
@@ -169,15 +202,6 @@ module Rye
169
202
  system(cmd)
170
203
  end
171
204
 
172
- # Close the SSH session with +@host+. This is called
173
- # automatically at exit if the connection is open.
174
- def disconnect
175
- return unless @ssh && !@ssh.closed?
176
- @ssh.loop(0.1) { @ssh.busy? }
177
- debug "Closing connection to #{@ssh.host}"
178
- @ssh.close
179
- end
180
-
181
205
  # Add one or more private keys to the SSH Agent.
182
206
  # * +additional_keys+ is a list of file paths to private keys
183
207
  # Returns the instance of Box
@@ -190,7 +214,7 @@ module Rye
190
214
  debug "ssh-add stdout: #{ret.stdout}"
191
215
  debug "ssh-add stderr: #{ret.stderr}"
192
216
  end
193
- self
217
+ self #MUST RETURN itself
194
218
  end
195
219
  alias :add_key :add_keys
196
220
 
@@ -203,6 +227,10 @@ module Rye
203
227
  end
204
228
  alias :add_environment_variable :add_env
205
229
 
230
+ def user
231
+ (@opts || {})[:user]
232
+ end
233
+
206
234
  # See Rye.keys
207
235
  def keys
208
236
  Rye.keys
@@ -236,7 +264,9 @@ module Rye
236
264
  # this box into ~/.ssh/authorized_keys and ~/.ssh/authorized_keys2.
237
265
  # Returns an Array of the private keys files used to generate the public keys.
238
266
  #
239
- # NOTE: authorize_keys disables safe-mode for this box while it runs.
267
+ # NOTE: authorize_keys disables safe-mode for this box while it runs
268
+ # which will hit you funky style if your using a single instance
269
+ # of Rye::Box in a multithreaded situation.
240
270
  #
241
271
  def authorize_keys
242
272
  added_keys = []
@@ -255,11 +285,32 @@ module Rye
255
285
  added_keys
256
286
  end
257
287
 
288
+ # Authorize the current user to login to the local machine via
289
+ # SSH without a password. This is the same functionality as
290
+ # authorize_keys except run with local shell commands.
291
+ def authorize_keys_local
292
+ added_keys = []
293
+ Rye.keys.each do |key|
294
+ path = key[2]
295
+ debug "# Public key for #{path}"
296
+ k = Rye::Key.from_file(path).public_key.to_ssh2
297
+ Rye.shell(:mkdir, :p, :m, '700', '$HOME/.ssh') # Silently create dir if it doesn't exist
298
+ Rye.shell(:echo, "'#{k}' >> $HOME/.ssh/authorized_keys")
299
+ Rye.shell(:echo, "'#{k}' >> $HOME/.ssh/authorized_keys2")
300
+ Rye.shell(:chmod, '-R', '0600', '$HOME/.ssh/authorized_keys*')
301
+ added_keys << path
302
+ end
303
+ added_keys
304
+ end
305
+
258
306
  # A handler for undefined commands.
259
307
  # Raises Rye::CommandNotFound exception.
260
308
  def method_missing(meth, *args, &block)
261
309
  raise Rye::CommandNotFound, "#{meth.to_s} (args: #{args.join(' ')})"
262
310
  end
311
+ def preview_command(*args)
312
+ prep_args(*args).join(' ')
313
+ end
263
314
 
264
315
  private
265
316
 
@@ -300,18 +351,9 @@ module Rye
300
351
  def run_command(*args)
301
352
  debug "run_command with keys: #{Rye.keys.inspect}"
302
353
 
303
- connect if !@ssh || @ssh.closed?
304
- args = args.flatten.compact
305
- args = args.first.split(/\s+/) if args.size == 1
306
- cmd = args.shift
307
-
308
- # Symbols to switches. :l -> -l, :help -> --help
309
- args.collect! do |a|
310
- a = "-#{a}" if a.is_a?(Symbol) && a.to_s.size == 1
311
- a = "--#{a}" if a.is_a?(Symbol)
312
- a
313
- end
354
+ cmd, args = prep_args(*args)
314
355
 
356
+ connect if !@ssh || @ssh.closed?
315
357
  raise Rye::NotConnected, @host unless @ssh && !@ssh.closed?
316
358
 
317
359
  cmd_clean = Rye.escape(@safe, cmd, args)
@@ -336,6 +378,24 @@ module Rye
336
378
  end
337
379
  alias :cmd :run_command
338
380
 
381
+
382
+
383
+ # Takes a list of arguments appropriate for run_command or
384
+ # preview_command and returns: [cmd, args]
385
+ def prep_args(*args)
386
+ args = args.flatten.compact
387
+ args = args.first.to_s.split(/\s+/) if args.size == 1
388
+ cmd = args.shift
389
+
390
+ # Symbols to switches. :l -> -l, :help -> --help
391
+ args.collect! do |a|
392
+ a = "-#{a}" if a.is_a?(Symbol) && a.to_s.size == 1
393
+ a = "--#{a}" if a.is_a?(Symbol)
394
+ a
395
+ end
396
+ [cmd, args]
397
+ end
398
+
339
399
  # Executes +command+ via SSH
340
400
  # Returns an Array with 4 elements: [stdout, stderr, exit code, exit signal]
341
401
  def net_ssh_exec!(command)
data/lib/rye/cmd.rb CHANGED
@@ -25,6 +25,8 @@ module Rye;
25
25
  #def rm(*args); cmd('rm', args); end
26
26
  def ps(*args); cmd('ps', args); end
27
27
  def sh(*args); cmd('sh', args); end
28
+ def df(*args); cmd('df', args); end
29
+ def du(*args); cmd('du', args); end
28
30
 
29
31
  def env(*args); cmd "env"; end
30
32
  def pwd(*args); cmd "pwd"; end
@@ -44,16 +46,19 @@ module Rye;
44
46
  def bash(*args); cmd('bash', args); end
45
47
  def echo(*args); cmd('echo', args); end
46
48
  def test(*args); cmd('test', args); end
49
+ def mkfs(*args); cmd('mkfs', args); end
47
50
 
48
- def mount(*args); cmd("mount"); end
51
+ def mount(*args); cmd("mount", args); end
49
52
  def sleep(seconds=1); cmd("sleep", seconds); end
50
53
  def mkdir(*args); cmd('mkdir', args); end
51
54
  def touch(*args); cmd('touch', args); end
52
55
  def uname(*args); cmd('uname', args); end
53
56
  def chmod(*args); cmd('chmod', args); end
54
57
 
55
- def uptime(*args); cmd("uptime"); end
58
+ def umount(*args); cmd("umount", args); end
59
+ def uptime(*args); cmd("uptime", args); end
56
60
  def python(*args); cmd('python', args); end
61
+ def history(*args); cmd('history', args); end
57
62
  def printenv(*args); cmd('printenv', args); end
58
63
  def hostname(*args); cmd('hostname', args); end
59
64
 
data/lib/rye/set.rb CHANGED
@@ -48,7 +48,9 @@ module Rye
48
48
  def add_box(*boxes)
49
49
  boxes = boxes.flatten.compact
50
50
  @boxes += boxes.collect do |box|
51
- box.is_a?(Rye::Box) ? box.add_keys(@keys) : Rye::Box.new(box, @opts)
51
+ b = box.is_a?(String) ? Rye::Box.new(box, @opts) : box
52
+ b.add_keys(@keys)
53
+ b
52
54
  end
53
55
  self
54
56
  end
@@ -90,8 +92,12 @@ module Rye
90
92
  run_command(:cd, key)
91
93
  self
92
94
  end
93
- alias :cd :'[]'
94
-
95
+ # alias :cd :'[]' # fix for jruby
96
+ def cd(key=nil)
97
+ run_command(:cd, key)
98
+ self
99
+ end
100
+
95
101
  # Catches calls to Rye::Box commands. If +meth+ is the name of an
96
102
  # instance method defined in Rye::Cmd then we call it against all
97
103
  # the boxes in +@boxes+. Otherwise this method raises a
@@ -118,6 +124,7 @@ module Rye
118
124
 
119
125
  # Run the command on all boxes in parallel
120
126
  def run_command_parallel(meth, *args)
127
+ p @boxes
121
128
  debug "P: #{meth} on #{@boxes.size} boxes (#{@boxes.collect {|b| b.host }.join(', ')})"
122
129
  threads = []
123
130
 
data/lib/rye.rb CHANGED
@@ -18,9 +18,9 @@ require 'sys'
18
18
  #
19
19
  # Rye is similar to Rush[http://rush.heroku.com] but everything
20
20
  # happens over SSH (no HTTP daemon) and the default settings are
21
- # less dangerous (for safety). For example, file globs are
22
- # disabled so unless otherwise specified, you can't do this:
23
- # <tt>rbox.rm('/etc/**/*')</tt>.
21
+ # less dangerous (for safety). For example, file globs and the
22
+ # "rm" command are disabled so unless otherwise specified, you
23
+ # can't do this: <tt>rbox.rm('/etc/**/*')</tt>.
24
24
  #
25
25
  # However, you can do this:
26
26
  #
@@ -35,7 +35,7 @@ module Rye
35
35
  extend self
36
36
 
37
37
  unless defined?(SYSINFO)
38
- VERSION = 0.4.freeze
38
+ VERSION = 0.5.freeze
39
39
  SYSINFO = SystemInfo.new.freeze
40
40
  end
41
41
 
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.4.3"
4
+ s.version = "0.5.1"
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.4.3
4
+ version: 0.5.1
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-04-14 00:00:00 -04:00
12
+ date: 2009-04-19 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -87,6 +87,8 @@ files:
87
87
  - tst/50_rye_test.rb
88
88
  has_rdoc: true
89
89
  homepage: http://solutious.com/
90
+ licenses: []
91
+
90
92
  post_install_message:
91
93
  rdoc_options:
92
94
  - --line-numbers
@@ -111,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
113
  requirements: []
112
114
 
113
115
  rubyforge_project: rye
114
- rubygems_version: 1.3.1
116
+ rubygems_version: 1.3.2
115
117
  signing_key:
116
118
  specification_version: 2
117
119
  summary: "Rye: Safely run SSH commands on a bunch of machines at the same time (from Ruby)."