rye 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -7,7 +7,20 @@ TODO
7
7
  * Add S3 support for Rye::Box.upload / download
8
8
 
9
9
 
10
- #### 0.7.5 (2009-06-14) #############################
10
+ #### 0.7.6 (2009-06-19) #############################
11
+
12
+ * FIXED: Raise Rye::NoPty exception when Net::SSH returns message
13
+ "Pseudo-terminal will not be allocated because stdin is not a terminal."
14
+ * FIXED: Rye::Box#disconnect would hang in some instances. Now waits 3 seconds.
15
+ * FIXED: Bug in net_ssh_exec which was causing it to not return an exit code
16
+ * CHANGE: All exceptions now inherit from Rye::Error (Runtimerror)
17
+ * CHANGE: A NoPassword exception is raised when a password prompt returns nil.
18
+ * CHANGE: pre_command_hook block arguments have changed:
19
+ NEW: complete command, user, host, nickname
20
+ OLD: command, args, user, host, nickname
21
+
22
+
23
+ #### 0.7.5 (2009-06-13) #############################
11
24
 
12
25
  * FIXED: Rye::Set methods were not accepting or passing blocks.
13
26
  * ADDED: Rye::Set#user and Rye::Set#opts methods
data/lib/rye.rb CHANGED
@@ -11,6 +11,7 @@ require 'net/scp'
11
11
  require 'openssl'
12
12
  require 'tempfile'
13
13
  require 'highline'
14
+ require 'timeout'
14
15
 
15
16
  require 'storable'
16
17
  require 'sysinfo'
@@ -59,21 +60,25 @@ module Rye
59
60
  # Accessor for an instance of SystemInfo
60
61
  def sysinfo; SYSINFO; end
61
62
 
62
- class NoBoxes < RuntimeError; end
63
- class NoHost < RuntimeError; end
64
- class NotConnected < RuntimeError; end
65
- class CommandNotFound < RuntimeError; end
66
- class NoPty < RuntimeError
63
+ class RyeError < RuntimeError; end
64
+ class NoBoxes < RyeError; end
65
+ class NoPassword < RyeError
66
+ def message; "Password prompt did not return a value"; end
67
+ end
68
+ class NoHost < RyeError; end
69
+ class NotConnected < RyeError; end
70
+ class CommandNotFound < RyeError; end
71
+ class NoPty < RyeError
67
72
  def message; "Could not obtain pty (i.e. an interactive ssh session)"; end
68
73
  end
69
- class CommandError < RuntimeError
74
+ class CommandError < RyeError
70
75
  attr_reader :rap
71
76
  # * +rap+ a Rye::Rap object
72
77
  def initialize(rap)
73
78
  @rap = rap
74
79
  end
75
80
  def message
76
- "(code: %s) %s" % [@rap.exit_code, @rap.stderr.join($/)]
81
+ "%s (code: %s)" % [@rap.stderr.join($/), @rap.exit_code]
77
82
  end
78
83
  def stderr; @rap.stderr if @rap; end
79
84
  def stdout; @rap.stdout if @rap; end
data/lib/rye/box.rb CHANGED
@@ -194,17 +194,7 @@ module Rye
194
194
  disconnect
195
195
  connect
196
196
  end
197
-
198
-
199
- # Close the SSH session with +@rye_host+. This is called
200
- # automatically at exit if the connection is open.
201
- def disconnect
202
- return unless @rye_ssh && !@rye_ssh.closed?
203
- @rye_ssh.loop(0.1) { @rye_ssh.busy? }
204
- debug "Closing connection to #{@rye_ssh.host}"
205
- @rye_ssh.close
206
- end
207
-
197
+
208
198
 
209
199
  # Open an interactive SSH session. This only works if STDIN.tty?
210
200
  # returns true. Otherwise it returns the SSH command that would
@@ -594,6 +584,22 @@ module Rye
594
584
  self
595
585
  end
596
586
 
587
+ # Close the SSH session with +@rye_host+. This is called
588
+ # automatically at exit if the connection is open.
589
+ def disconnect
590
+ return unless @rye_ssh && !@rye_ssh.closed?
591
+ begin
592
+ Timeout::timeout(3) do
593
+ @rye_ssh.loop(0.3) { @rye_ssh.busy?; }
594
+ end
595
+ rescue Timeout::Error => ex
596
+ error "Disconnect timeout (was something still running?)"
597
+ end
598
+
599
+ debug "Closing connection to #{@rye_ssh.host}"
600
+ @rye_ssh.close
601
+ end
602
+
597
603
 
598
604
  private
599
605
 
@@ -655,12 +661,6 @@ module Rye
655
661
  cmd_clean = [cwd, cmd_clean].join(' && ')
656
662
  end
657
663
 
658
- info "COMMAND: #{cmd_clean}"
659
- debug "Executing: %s" % cmd_clean
660
-
661
- if @rye_pre_command_hook.is_a?(Proc)
662
- @rye_pre_command_hook.call(cmd, args, user, host, nickname)
663
- end
664
664
 
665
665
  ## NOTE: Do not raise a CommandNotFound exception in this method.
666
666
  # We want it to be possible to define methods to a single instance
@@ -672,6 +672,13 @@ module Rye
672
672
  ## raise Rye::CommandNotFound unless self.can?(cmd)
673
673
 
674
674
  begin
675
+ info "COMMAND: #{cmd_clean}"
676
+ debug "Executing: %s" % cmd_clean
677
+
678
+ if @rye_pre_command_hook.is_a?(Proc)
679
+ @rye_pre_command_hook.call(cmd_clean, user, host, nickname)
680
+ end
681
+
675
682
  stdout, stderr, ecode, esignal = net_ssh_exec!(cmd_clean)
676
683
 
677
684
  rap = Rye::Rap.new(self)
@@ -681,16 +688,30 @@ module Rye
681
688
  rap.exit_signal = esignal
682
689
  rap.cmd = cmd
683
690
 
691
+ #info "stdout: #{rap.stdout}"
692
+ #info "stderr: #{rap.stderr}"
693
+ #info "exit_code: #{rap.exit_code}"
694
+
684
695
  # It seems a convention for various commands to return -1
685
696
  # when something only mildly concerning happens. ls even
686
697
  # returns -1 for apparently no reason sometimes. In any
687
698
  # case, the real errors are the ones greater than zero
688
- raise Rye::CommandError.new(rap) if ecode > 0
699
+ raise Rye::CommandError.new(rap) if ecode != 0
689
700
 
690
701
  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
702
+ choice = nil
703
+ @rye_exception_hook.each_pair do |klass,act|
704
+ next unless ex.kind_of? klass
705
+ choice = @rye_exception_hook[klass].call(ex)
706
+ break
707
+ end
708
+ if choice == :retry
709
+ retry
710
+ elsif choice == :skip
711
+ # do nothing
712
+ else
713
+ raise ex
714
+ end
694
715
  end
695
716
 
696
717
  @rye_post_command_hook.call(rap) if @rye_post_command_hook.is_a?(Proc)
@@ -729,42 +750,63 @@ module Rye
729
750
  # http://www.ruby-forum.com/topic/169997
730
751
  #
731
752
  def net_ssh_exec!(command)
732
-
753
+
733
754
  block ||= Proc.new do |channel, type, data|
755
+
734
756
  channel[:stdout] ||= ""
735
757
  channel[:stderr] ||= ""
736
- channel[:exit_code] ||= 0
737
758
  channel[:stdout] << data if type == :stdout
759
+
738
760
  if type == :stderr
739
761
  # NOTE: Use sudo to test this since it prompts for a passwords.
740
762
  # Use sudo -K to kill the user's timestamp (ask for a password every time)
741
763
  if data =~ /Password:/
742
764
  ret = Annoy.get_user_input("Password: ", '*')
765
+ raise Rye::NoPassword if ret.nil?
743
766
  channel.send_data "#{ret}\n"
744
767
  else
745
768
  channel[:stderr] << data
746
769
  end
770
+
771
+ # If someone tries to open an interactive ssh session
772
+ # through a regular Rye::Box command, Net::SSH will
773
+ # return the following error and appear to hang. We
774
+ # catch it and raise the appropriate exception.
775
+ raise Rye::NoPty if data =~ /Pseudo-terminal will not/
776
+
747
777
  end
748
- channel.on_request("exit-status") do |ch, data|
749
- # Anything greater than 0 is an error
750
- channel[:exit_code] = data.read_long
751
- end
752
- channel.on_request("exit-signal") do |ch, data|
753
- # This should be the POSIX SIGNAL that ended the process
754
- channel[:exit_signal] = data.read_long
755
- end
778
+
756
779
  end
757
780
 
758
781
  channel = @rye_ssh.exec(command, &block)
759
782
 
783
+ channel.on_request("exit-status") do |ch, data|
784
+ # Anything greater than 0 is an error
785
+ channel[:exit_code] = data.read_long
786
+ end
787
+ channel.on_request("exit-signal") do |ch, data|
788
+ # This should be the POSIX SIGNAL that ended the process
789
+ channel[:exit_signal] = data.read_long
790
+ end
791
+
760
792
  channel.wait # block until we get a response
761
793
  channel.request_pty do |ch, success|
762
794
  raise Rye::NoPty if !success
763
795
  end
764
796
 
765
- channel[:exit_code] = 0 if channel[:exit_code] == nil
797
+ ## I'm getting weird behavior with exit codes. Sometimes
798
+ ## a command which usually returns an exit code will not
799
+ ## return one the next time it's run. The following crap
800
+ ## was from the debugging.
801
+ ##Kernel.sleep 5
802
+ ###channel.close
803
+ #channel.eof!
804
+ ##p [:active, channel.active?]
805
+ ##p [:closing, channel.closing?]
806
+ ##p [:eof, channel.eof?]
807
+
808
+ channel[:exit_code] ||= 0
766
809
  channel[:exit_code] &&= channel[:exit_code].to_i
767
-
768
810
  channel[:stderr].gsub!(/bash: line \d+:\s+/, '') if channel[:stderr]
769
811
 
770
812
  [channel[:stdout], channel[:stderr], channel[:exit_code], channel[:exit_signal]]
data/lib/rye/rap.rb CHANGED
@@ -76,13 +76,12 @@ module Rye;
76
76
  # it's just an exit code returned by Net::SSH.
77
77
  # Returns the exit code as an Integer.
78
78
  def add_exit_code(code)
79
- code = -1 unless code
79
+ code = 0 if code.nil?
80
80
  if code.is_a?(Process::Status)
81
81
  @exit_code, @pid = code.exitstatus.to_i, code.pid
82
82
  else
83
83
  @exit_code = code.to_i
84
84
  end
85
- @exit_code
86
85
  end
87
86
  def code; @exit_code; end
88
87
 
@@ -91,7 +90,7 @@ module Rye;
91
90
  def to_s
92
91
  return self.first if self.size == 1
93
92
  return "" if self.size == 0
94
- self
93
+ super
95
94
  end
96
95
 
97
96
  # Output STDOUT content to (remote) +path+
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.5"
4
+ s.version = "0.7.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.7.5
4
+ version: 0.7.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-06-13 00:00:00 -04:00
12
+ date: 2009-06-19 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency