delano-rye 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +8 -0
- data/README.rdoc +1 -1
- data/bin/rye +12 -1
- data/bin/try +1 -0
- data/lib/rye.rb +1 -1
- data/lib/rye/box.rb +86 -26
- data/lib/rye/cmd.rb +6 -2
- data/lib/rye/set.rb +7 -2
- data/rye.gemspec +1 -1
- metadata +1 -1
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
|
+
|
7
15
|
|
8
16
|
#### 0.4.3 (2009-04-14) #############################
|
9
17
|
|
data/README.rdoc
CHANGED
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
data/lib/rye.rb
CHANGED
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]
|
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
|
-
|
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.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,15 +46,17 @@ 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
|
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
|
57
61
|
def printenv(*args); cmd('printenv', args); end
|
58
62
|
def hostname(*args); cmd('hostname', args); end
|
data/lib/rye/set.rb
CHANGED
@@ -90,8 +90,12 @@ module Rye
|
|
90
90
|
run_command(:cd, key)
|
91
91
|
self
|
92
92
|
end
|
93
|
-
alias :cd :'[]'
|
94
|
-
|
93
|
+
# alias :cd :'[]' # fix for jruby
|
94
|
+
def cd(key=nil)
|
95
|
+
run_command(:cd, key)
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
95
99
|
# Catches calls to Rye::Box commands. If +meth+ is the name of an
|
96
100
|
# instance method defined in Rye::Cmd then we call it against all
|
97
101
|
# the boxes in +@boxes+. Otherwise this method raises a
|
@@ -118,6 +122,7 @@ module Rye
|
|
118
122
|
|
119
123
|
# Run the command on all boxes in parallel
|
120
124
|
def run_command_parallel(meth, *args)
|
125
|
+
p @boxes
|
121
126
|
debug "P: #{meth} on #{@boxes.size} boxes (#{@boxes.collect {|b| b.host }.join(', ')})"
|
122
127
|
threads = []
|
123
128
|
|
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
|
+
s.version = "0.5.0"
|
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"
|