lib/rye/box.rb in rye-0.4.3 vs lib/rye/box.rb in rye-0.5.1
- old
+ new
@@ -121,42 +121,75 @@
#
def [](key=nil)
@current_working_directory = key
self
end
- alias :cd :'[]'
-
+# alias :cd :'[]' # fix for jruby
+ def cd(key=nil);
+ @current_working_directory = key
+ self
+ end
+
# Open an SSH session with +@host+. This called automatically
# when you the first comamnd is run if it's not already connected.
# Raises a Rye::NoHost exception if +@host+ is not specified.
# Will attempt a password login up to 3 times if the initial
# authentication fails.
def connect
raise Rye::NoHost unless @host
disconnect if @ssh
- debug "Opening connection to #{@host}"
+ debug "Opening connection to #{@host} as #{@opts[:user]}"
highline = HighLine.new # Used for password prompt
retried = 0
+
begin
@ssh = Net::SSH.start(@host, @opts[:user], @opts || {})
rescue Net::SSH::AuthenticationFailed => ex
retried += 1
if STDIN.tty? && retried <= 3
@opts[:password] = highline.ask("Password: ") { |q| q.echo = '' }
@opts[:auth_methods] ||= []
- @opts[:auth_methods] = %w(password)
+ @opts[:auth_methods] << 'password'
retry
else
STDERR.puts "Authentication failed."
exit 0
end
end
+ # We add :auth_methods (a Net::SSH joint) to force asking for a
+ # password if the initial (key-based) authentication fails. We
+ # need to delete the key from @opts otherwise it lingers until
+ # the next connection (if we switch_user is called for example).
+ @opts.delete :auth_methods if @opts.has_key?(:auth_methods)
+
@ssh.is_a?(Net::SSH::Connection::Session) && !@ssh.closed?
self
end
+ # Close the SSH session with +@host+. This is called
+ # automatically at exit if the connection is open.
+ def disconnect
+ return unless @ssh && !@ssh.closed?
+ @ssh.loop(0.1) { @ssh.busy? }
+ debug "Closing connection to #{@ssh.host}"
+ @ssh.close
+ end
+
+ # Reconnect as another user
+ # * +newuser+ The username to reconnect as
+ #
+ # NOTE: if there is an open connection, it's disconnected
+ # and a new one is opened for the given user.
+ def switch_user(newuser)
+ return if newuser.to_s == self.user.to_s
+ @opts ||= {}
+ @opts[:user] = newuser
+ disconnect
+ connect
+ end
+
# Open an interactive SSH session. This only works if STDIN.tty?
# returns true. Otherwise it returns the SSH command that would
# have been run. This requires the SSH command-line executable (ssh).
# * +run+ when set to false, it will return the SSH command as a String
# and not open an SSH session.
@@ -167,19 +200,10 @@
cmd = Rye.prepare_command("ssh", "#{@opts[:user]}@#{@host}")
return cmd unless run
system(cmd)
end
- # Close the SSH session with +@host+. This is called
- # automatically at exit if the connection is open.
- def disconnect
- return unless @ssh && !@ssh.closed?
- @ssh.loop(0.1) { @ssh.busy? }
- debug "Closing connection to #{@ssh.host}"
- @ssh.close
- end
-
# Add one or more private keys to the SSH Agent.
# * +additional_keys+ is a list of file paths to private keys
# Returns the instance of Box
def add_keys(*additional_keys)
additional_keys = [additional_keys].flatten.compact || []
@@ -188,11 +212,11 @@
if ret.is_a?(Rye::Rap)
debug "ssh-add exit_code: #{ret.exit_code}"
debug "ssh-add stdout: #{ret.stdout}"
debug "ssh-add stderr: #{ret.stderr}"
end
- self
+ self #MUST RETURN itself
end
alias :add_key :add_keys
# Add an environment variable. +n+ and +v+ are the name and value.
# Returns the instance of Rye::Box
@@ -201,10 +225,14 @@
(@current_environment_variables ||= {})[n] = v
self
end
alias :add_environment_variable :add_env
+ def user
+ (@opts || {})[:user]
+ end
+
# See Rye.keys
def keys
Rye.keys
end
@@ -234,11 +262,13 @@
# Copy the local public keys (as specified by Rye.keys) to
# this box into ~/.ssh/authorized_keys and ~/.ssh/authorized_keys2.
# Returns an Array of the private keys files used to generate the public keys.
#
- # NOTE: authorize_keys disables safe-mode for this box while it runs.
+ # NOTE: authorize_keys disables safe-mode for this box while it runs
+ # which will hit you funky style if your using a single instance
+ # of Rye::Box in a multithreaded situation.
#
def authorize_keys
added_keys = []
@safe= false
Rye.keys.each do |key|
@@ -253,15 +283,36 @@
end
@safe = true
added_keys
end
+ # Authorize the current user to login to the local machine via
+ # SSH without a password. This is the same functionality as
+ # authorize_keys except run with local shell commands.
+ def authorize_keys_local
+ added_keys = []
+ Rye.keys.each do |key|
+ path = key[2]
+ debug "# Public key for #{path}"
+ k = Rye::Key.from_file(path).public_key.to_ssh2
+ Rye.shell(:mkdir, :p, :m, '700', '$HOME/.ssh') # Silently create dir if it doesn't exist
+ Rye.shell(:echo, "'#{k}' >> $HOME/.ssh/authorized_keys")
+ Rye.shell(:echo, "'#{k}' >> $HOME/.ssh/authorized_keys2")
+ Rye.shell(:chmod, '-R', '0600', '$HOME/.ssh/authorized_keys*')
+ added_keys << path
+ end
+ added_keys
+ end
+
# A handler for undefined commands.
# Raises Rye::CommandNotFound exception.
def method_missing(meth, *args, &block)
raise Rye::CommandNotFound, "#{meth.to_s} (args: #{args.join(' ')})"
end
+ def preview_command(*args)
+ prep_args(*args).join(' ')
+ end
private
def debug(msg="unknown debug msg"); @debug.puts msg if @debug; end
@@ -298,22 +349,13 @@
# but if it fails it will raise a Rye::NotConnected exception.
#
def run_command(*args)
debug "run_command with keys: #{Rye.keys.inspect}"
- connect if !@ssh || @ssh.closed?
- args = args.flatten.compact
- args = args.first.split(/\s+/) if args.size == 1
- cmd = args.shift
+ cmd, args = prep_args(*args)
- # Symbols to switches. :l -> -l, :help -> --help
- args.collect! do |a|
- a = "-#{a}" if a.is_a?(Symbol) && a.to_s.size == 1
- a = "--#{a}" if a.is_a?(Symbol)
- a
- end
-
+ connect if !@ssh || @ssh.closed?
raise Rye::NotConnected, @host unless @ssh && !@ssh.closed?
cmd_clean = Rye.escape(@safe, cmd, args)
cmd_clean = prepend_env(cmd_clean)
if @current_working_directory
@@ -333,9 +375,27 @@
raise Rye::CommandError.new(rap) if ecode > 0
rap
end
alias :cmd :run_command
+
+
+
+ # Takes a list of arguments appropriate for run_command or
+ # preview_command and returns: [cmd, args]
+ def prep_args(*args)
+ args = args.flatten.compact
+ args = args.first.to_s.split(/\s+/) if args.size == 1
+ cmd = args.shift
+
+ # Symbols to switches. :l -> -l, :help -> --help
+ args.collect! do |a|
+ a = "-#{a}" if a.is_a?(Symbol) && a.to_s.size == 1
+ a = "--#{a}" if a.is_a?(Symbol)
+ a
+ end
+ [cmd, args]
+ end
# Executes +command+ via SSH
# Returns an Array with 4 elements: [stdout, stderr, exit code, exit signal]
def net_ssh_exec!(command)
block ||= Proc.new do |channel, type, data|