rye 0.7.4 → 0.7.5
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 +10 -0
- data/lib/rye.rb +3 -0
- data/lib/rye/box.rb +58 -21
- data/lib/rye/cmd.rb +1 -0
- data/lib/rye/set.rb +18 -11
- data/rye.gemspec +1 -1
- metadata +2 -2
data/CHANGES.txt
CHANGED
|
@@ -7,6 +7,16 @@ TODO
|
|
|
7
7
|
* Add S3 support for Rye::Box.upload / download
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
#### 0.7.5 (2009-06-14) #############################
|
|
11
|
+
|
|
12
|
+
* FIXED: Rye::Set methods were not accepting or passing blocks.
|
|
13
|
+
* ADDED: Rye::Set#user and Rye::Set#opts methods
|
|
14
|
+
* ADDED: Rye::Box#nickname
|
|
15
|
+
* ADDED: exception hooks for Rye::Box.
|
|
16
|
+
* CHANGE: Rye::Set method missing now forwards to Rye::Box
|
|
17
|
+
methods instead of Rye::Cmd
|
|
18
|
+
|
|
19
|
+
|
|
10
20
|
#### 0.7.4 (2009-06-04) #############################
|
|
11
21
|
|
|
12
22
|
* FIXED: Bug in Rye::Box#interactive_ssh related to instance variable renaming from 0.7.0.
|
data/lib/rye.rb
CHANGED
|
@@ -63,6 +63,9 @@ module Rye
|
|
|
63
63
|
class NoHost < RuntimeError; end
|
|
64
64
|
class NotConnected < RuntimeError; end
|
|
65
65
|
class CommandNotFound < RuntimeError; end
|
|
66
|
+
class NoPty < RuntimeError
|
|
67
|
+
def message; "Could not obtain pty (i.e. an interactive ssh session)"; end
|
|
68
|
+
end
|
|
66
69
|
class CommandError < RuntimeError
|
|
67
70
|
attr_reader :rap
|
|
68
71
|
# * +rap+ a Rye::Rap object
|
data/lib/rye/box.rb
CHANGED
|
@@ -34,9 +34,17 @@ module Rye
|
|
|
34
34
|
def safe; @rye_safe; end
|
|
35
35
|
def user; (@rye_opts || {})[:user]; end
|
|
36
36
|
|
|
37
|
+
# A storage area +@rye_stash+
|
|
38
|
+
def stash; @rye_stash; end
|
|
39
|
+
def nickname; @rye_nickname || host; end
|
|
40
|
+
|
|
37
41
|
def host=(val); @rye_host = val; end
|
|
38
42
|
def opts=(val); @rye_opts = val; end
|
|
39
43
|
|
|
44
|
+
# Returns the storage area +@rye_stash+
|
|
45
|
+
def stash=(val); @rye_stash = val; end
|
|
46
|
+
def nickname=(val); @rye_nickname = val; end
|
|
47
|
+
|
|
40
48
|
def enable_safe_mode; @rye_safe = true; end
|
|
41
49
|
def disable_safe_mode; @rye_safe = false; end
|
|
42
50
|
|
|
@@ -45,14 +53,15 @@ module Rye
|
|
|
45
53
|
|
|
46
54
|
# The most recent valud for umask (or 0022)
|
|
47
55
|
def current_umask; @rye_current_umask; end
|
|
48
|
-
|
|
49
|
-
def ssh; @rye_ssh; end
|
|
56
|
+
|
|
50
57
|
def info; @rye_info; end
|
|
51
58
|
def debug; @rye_debug; end
|
|
52
59
|
def error; @rye_error; end
|
|
53
60
|
|
|
54
61
|
def pre_command_hook=(val); @rye_pre_command_hook = val; end
|
|
55
62
|
def post_command_hook=(val); @rye_post_command_hook = val; end
|
|
63
|
+
# A Hash. The keys are exception classes, the values are Procs to execute
|
|
64
|
+
def exception_hook=(val); @rye_exception_hook = val; end
|
|
56
65
|
|
|
57
66
|
# * +host+ The hostname to connect to. The default is localhost.
|
|
58
67
|
# * +opts+ a hash of optional arguments.
|
|
@@ -72,6 +81,7 @@ module Rye
|
|
|
72
81
|
# Net::SSH.start that is not already mentioned above.
|
|
73
82
|
#
|
|
74
83
|
def initialize(host='localhost', opts={})
|
|
84
|
+
@rye_exception_hook = {}
|
|
75
85
|
@rye_host = host
|
|
76
86
|
|
|
77
87
|
# These opts are use by Rye::Box and also passed to Net::SSH
|
|
@@ -222,7 +232,7 @@ module Rye
|
|
|
222
232
|
debug "ssh-add stdout: #{ret.stdout}"
|
|
223
233
|
debug "ssh-add stderr: #{ret.stderr}"
|
|
224
234
|
end
|
|
225
|
-
self #MUST RETURN
|
|
235
|
+
self # MUST RETURN self
|
|
226
236
|
end
|
|
227
237
|
alias :add_key :add_keys
|
|
228
238
|
|
|
@@ -279,8 +289,8 @@ module Rye
|
|
|
279
289
|
def to_s; '%s@rye_%s' % [user, @rye_host]; end
|
|
280
290
|
|
|
281
291
|
def inspect
|
|
282
|
-
%q{#<%s:%s cwd=%s umask=%s env=%s safe=%s opts=%s>} %
|
|
283
|
-
[self.class.to_s, self.host,
|
|
292
|
+
%q{#<%s:%s name=%s cwd=%s umask=%s env=%s safe=%s opts=%s>} %
|
|
293
|
+
[self.class.to_s, self.host, self.nickname,
|
|
284
294
|
@rye_current_working_directory, @rye_current_umask,
|
|
285
295
|
(@rye_current_environment_variables || '').inspect,
|
|
286
296
|
self.safe, self.opts.inspect]
|
|
@@ -424,7 +434,9 @@ module Rye
|
|
|
424
434
|
# A handler for undefined commands.
|
|
425
435
|
# Raises Rye::CommandNotFound exception.
|
|
426
436
|
def method_missing(meth, *args, &block)
|
|
427
|
-
|
|
437
|
+
ex = Rye::CommandNotFound.new(meth.to_s)
|
|
438
|
+
raise ex unless @rye_exception_hook.has_key? ex.class
|
|
439
|
+
@rye_exception_hook[Rye::CommandNotFound].call ex
|
|
428
440
|
end
|
|
429
441
|
|
|
430
442
|
# Returns the command an arguments as a String.
|
|
@@ -444,6 +456,27 @@ module Rye
|
|
|
444
456
|
@rye_pre_command_hook
|
|
445
457
|
end
|
|
446
458
|
|
|
459
|
+
# Supply a block to be called whenever there's an Exception. It's called
|
|
460
|
+
# with 1 argument: the exception class. If the exception block returns
|
|
461
|
+
# :retry, the command will be executed again.
|
|
462
|
+
#
|
|
463
|
+
# e.g.
|
|
464
|
+
# rbox.exception_hook(CommandNotFound) do |ex|
|
|
465
|
+
# STDERR.puts "An error occurred: #{ex.class}"
|
|
466
|
+
# choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ')
|
|
467
|
+
# if choice == 'R'
|
|
468
|
+
# :retry
|
|
469
|
+
# elsif choice == 'S'
|
|
470
|
+
# # do nothing
|
|
471
|
+
# else
|
|
472
|
+
# exit # !
|
|
473
|
+
# end
|
|
474
|
+
# end
|
|
475
|
+
def exception_hook(klass, &block)
|
|
476
|
+
@rye_exception_hook[klass] = block if block
|
|
477
|
+
@rye_exception_hook[klass]
|
|
478
|
+
end
|
|
479
|
+
|
|
447
480
|
# Execute a block in the context of an instance of Rye::Box.
|
|
448
481
|
#
|
|
449
482
|
# rbox = Rye::Box.new
|
|
@@ -622,12 +655,11 @@ module Rye
|
|
|
622
655
|
cmd_clean = [cwd, cmd_clean].join(' && ')
|
|
623
656
|
end
|
|
624
657
|
|
|
625
|
-
|
|
626
658
|
info "COMMAND: #{cmd_clean}"
|
|
627
659
|
debug "Executing: %s" % cmd_clean
|
|
628
660
|
|
|
629
661
|
if @rye_pre_command_hook.is_a?(Proc)
|
|
630
|
-
@rye_pre_command_hook.call(cmd, args, user, host)
|
|
662
|
+
@rye_pre_command_hook.call(cmd, args, user, host, nickname)
|
|
631
663
|
end
|
|
632
664
|
|
|
633
665
|
## NOTE: Do not raise a CommandNotFound exception in this method.
|
|
@@ -639,25 +671,30 @@ module Rye
|
|
|
639
671
|
# this is good enough for now.
|
|
640
672
|
## raise Rye::CommandNotFound unless self.can?(cmd)
|
|
641
673
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
@rye_post_command_hook.call(rap)
|
|
653
|
-
else
|
|
674
|
+
begin
|
|
675
|
+
stdout, stderr, ecode, esignal = net_ssh_exec!(cmd_clean)
|
|
676
|
+
|
|
677
|
+
rap = Rye::Rap.new(self)
|
|
678
|
+
rap.add_stdout(stdout || '')
|
|
679
|
+
rap.add_stderr(stderr || '')
|
|
680
|
+
rap.add_exit_code(ecode)
|
|
681
|
+
rap.exit_signal = esignal
|
|
682
|
+
rap.cmd = cmd
|
|
683
|
+
|
|
654
684
|
# It seems a convention for various commands to return -1
|
|
655
685
|
# when something only mildly concerning happens. ls even
|
|
656
686
|
# returns -1 for apparently no reason sometimes. In any
|
|
657
687
|
# case, the real errors are the ones greater than zero
|
|
658
688
|
raise Rye::CommandError.new(rap) if ecode > 0
|
|
689
|
+
|
|
690
|
+
rescue Exception => ex
|
|
691
|
+
raise ex unless @rye_exception_hook.has_key? ex.class
|
|
692
|
+
ret = @rye_exception_hook[ex.class].call(ex)
|
|
693
|
+
retry if ret == :retry
|
|
659
694
|
end
|
|
660
695
|
|
|
696
|
+
@rye_post_command_hook.call(rap) if @rye_post_command_hook.is_a?(Proc)
|
|
697
|
+
|
|
661
698
|
rap
|
|
662
699
|
end
|
|
663
700
|
alias :cmd :run_command
|
|
@@ -722,7 +759,7 @@ module Rye
|
|
|
722
759
|
|
|
723
760
|
channel.wait # block until we get a response
|
|
724
761
|
channel.request_pty do |ch, success|
|
|
725
|
-
raise
|
|
762
|
+
raise Rye::NoPty if !success
|
|
726
763
|
end
|
|
727
764
|
|
|
728
765
|
channel[:exit_code] = 0 if channel[:exit_code] == nil
|
data/lib/rye/cmd.rb
CHANGED
|
@@ -67,6 +67,7 @@ module Rye;
|
|
|
67
67
|
def chown(*args); cmd('chown', args); end
|
|
68
68
|
def unzip(*args); cmd('unzip', args); end
|
|
69
69
|
def bzip2(*args); cmd('bzip2', args); end
|
|
70
|
+
def which(*args); cmd('which', args); end
|
|
70
71
|
|
|
71
72
|
def umount(*args); cmd("umount", args); end
|
|
72
73
|
def uptime(*args); cmd("uptime", args); end
|
data/lib/rye/set.rb
CHANGED
|
@@ -42,6 +42,9 @@ module Rye
|
|
|
42
42
|
add_keys(@opts[:keys])
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
def opts; @opts; end
|
|
46
|
+
def user; (@opts || {})[:user]; end
|
|
47
|
+
|
|
45
48
|
# * +boxes+ one or more boxes. Rye::Box objects will be added directly
|
|
46
49
|
# to the set. Hostnames will be used to create new instances of Rye::Box
|
|
47
50
|
# and those will be added to the list.
|
|
@@ -97,7 +100,12 @@ module Rye
|
|
|
97
100
|
run_command(:cd, key)
|
|
98
101
|
self
|
|
99
102
|
end
|
|
100
|
-
|
|
103
|
+
|
|
104
|
+
# Are there any boxes in this set?
|
|
105
|
+
def empty?
|
|
106
|
+
@boxes.nil? || @boxes.empty?
|
|
107
|
+
end
|
|
108
|
+
|
|
101
109
|
# Catches calls to Rye::Box commands. If +meth+ is the name of an
|
|
102
110
|
# instance method defined in Rye::Cmd then we call it against all
|
|
103
111
|
# the boxes in +@boxes+. Otherwise this method raises a
|
|
@@ -105,33 +113,32 @@ module Rye
|
|
|
105
113
|
# exception if this set has no boxes defined.
|
|
106
114
|
#
|
|
107
115
|
# Returns a Rye::Rap object containing the responses from each Rye::Box.
|
|
108
|
-
def method_missing(meth, *args)
|
|
116
|
+
def method_missing(meth, *args, &block)
|
|
109
117
|
# Ruby 1.8 populates Module.instance_methods with Strings. 1.9 uses Symbols.
|
|
110
118
|
meth = (Rye.sysinfo.ruby[1] == 8) ? meth.to_s : meth.to_sym
|
|
111
119
|
raise Rye::NoBoxes if @boxes.empty?
|
|
112
|
-
raise Rye::CommandNotFound, meth.to_s unless Rye::
|
|
113
|
-
run_command(meth, *args)
|
|
120
|
+
raise Rye::CommandNotFound, meth.to_s unless Rye::Box.instance_methods.member?(meth)
|
|
121
|
+
run_command(meth, *args, &block)
|
|
114
122
|
end
|
|
115
123
|
|
|
116
124
|
private
|
|
117
125
|
|
|
118
126
|
# Determines whether to call the serial or parallel method, then calls it.
|
|
119
|
-
def run_command(meth, *args)
|
|
127
|
+
def run_command(meth, *args, &block)
|
|
120
128
|
runner = @parallel ? :run_command_parallel : :run_command_serial
|
|
121
|
-
self.send(runner, meth, *args)
|
|
129
|
+
self.send(runner, meth, *args, &block)
|
|
122
130
|
end
|
|
123
131
|
|
|
124
132
|
|
|
125
133
|
# Run the command on all boxes in parallel
|
|
126
|
-
def run_command_parallel(meth, *args)
|
|
127
|
-
p @boxes
|
|
134
|
+
def run_command_parallel(meth, *args, &block)
|
|
128
135
|
debug "P: #{meth} on #{@boxes.size} boxes (#{@boxes.collect {|b| b.host }.join(', ')})"
|
|
129
136
|
threads = []
|
|
130
137
|
|
|
131
138
|
raps = Rye::Rap.new(self)
|
|
132
139
|
(@boxes || []).each do |box|
|
|
133
140
|
threads << Thread.new do
|
|
134
|
-
Thread.current[:rap] = box.send(meth, *args) # Store the result in the thread
|
|
141
|
+
Thread.current[:rap] = box.send(meth, *args, &block) # Store the result in the thread
|
|
135
142
|
end
|
|
136
143
|
end
|
|
137
144
|
|
|
@@ -148,11 +155,11 @@ module Rye
|
|
|
148
155
|
|
|
149
156
|
|
|
150
157
|
# Run the command on all boxes in serial
|
|
151
|
-
def run_command_serial(meth, *args)
|
|
158
|
+
def run_command_serial(meth, *args, &block)
|
|
152
159
|
debug "S: #{meth} on #{@boxes.size} boxes (#{@boxes.collect {|b| b.host }.join(', ')})"
|
|
153
160
|
raps = Rye::Rap.new(self)
|
|
154
161
|
(@boxes || []).each do |box|
|
|
155
|
-
raps << box.send(meth, *args)
|
|
162
|
+
raps << box.send(meth, *args, &block)
|
|
156
163
|
end
|
|
157
164
|
raps
|
|
158
165
|
end
|
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.7.
|
|
4
|
+
s.version = "0.7.5"
|
|
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.7.
|
|
4
|
+
version: 0.7.5
|
|
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-06-
|
|
12
|
+
date: 2009-06-13 00:00:00 -04:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|