### Home Classes Methods

### In Files

- lib/rye/hop.rb

### Parent

Object

### Methods

- ::new
- #==
- #add_key
- #add_keys
- #connect
- #debug?
- #disconnect
- #error?
- #exception_hook=
- #fetch_port
- #host
- #host=
- #host_key
- #info?
- #inspect
- #keys
- #nickname
- #nickname=
- #opts
- #opts=
- #remove_hops!
- #remove_key
- #remove_keys
- #root?
- #ssh_config_options
- #switch_user
- #to_s
- #user
- #via
- #via?
- #via_hop

### Files

- LICENSE.txt
- README.rdoc

### Class/Module Index

Quicksearch

- Rye
- Rye::Box
- Rye::Box::InstanceExecHelper
- Rye::Cmd
- Rye::CommandNotFound
- Rye::Err
- Rye::Hop
- Rye::Key
- Rye::Key::BadFile
- Rye::Key::BadPerm
- Rye::NoBoxes
- Rye::NoHost
- Rye::NoPassword
- Rye::NoPty
- Rye::NotConnected
- Rye::Rap
- Rye::RyeError
- Rye::Set
- Rye::Tpl
- Rye::VERSION
- Object

No matching classes.

# Rye::Hop

The Rye::Hop class represents a machine. This class allows boxes to by accessed via it.

    rhop = Rye::Hop.new('firewall.lan')
    rbox = Rye::Box.new('filibuster', :via => rhop)
    rbox.uptime     # => 20:53  up 1 day,  1:52, 4 users

Or

    rbox = Rye::Box.new('filibuster', :via => 'firewall.lan')

### Constants

MAX_PORT

  The maximum port number that the gateway will attempt to use to forward connections from.

MIN_PORT

  The minimum port number that the gateway will attempt to use to forward connections from.

### Public Class Methods

new(host, opts={}) click to toggle source

- `host` The hostname to connect to. Default: localhost.

- `user` The username to connect as. Default: SSH config file or current shell user.

- `opts` a hash of optional arguments.

The `opts` hash excepts the following keys:

- :port => remote server ssh port. Default: SSH config file or 22

- :keys => one or more private key file paths (passwordless login)

- :via => the Rye::Hop to access this host through

- :info => an IO object to print Rye::Box command info to. Default: nil

- :debug => an IO object to print Rye::Box debugging info to. Default: nil

- :error => an IO object to print Rye::Box errors to. Default: STDERR

- :getenv => pre-fetch `host` environment variables? (default: true)

- :password => the user's password (ignored if there's a valid private key)

- :templates => the template engine to use for uploaded files. One of: :erb (default)

- :sudo => Run all commands via sudo (default: false)

NOTE: `opts` can also contain any parameter supported by Net::SSH.start that is not already mentioned above.

    # File lib/rye/hop.rb, line 81
    def initialize(host, opts={})
      ssh_opts = ssh_config_options(host)
      @rye_exception_hook = {}
      @rye_host = host

      if opts[:user]
        @rye_user = opts[:user]
      else
        @rye_user = ssh_opts[:user] || Rye.sysinfo.user
      end

      # These opts are use by Rye::Box and also passed to
      # Net::SSH::Gateway (and Net::SSH)
      @rye_opts = {
        :port => ssh_opts[:port],
        :keys => Rye.keys,
        :via => nil,
        :info => nil,
        :debug => nil,
        :error => STDERR,
        :getenv => true,
        :templates => :erb,
        :quiet => false
      }.merge(opts)

      @next_port = MAX_PORT

      # Close the SSH session before Ruby exits. This will do nothing
      # if disconnect has already been called explicitly.
      at_exit { self.disconnect }

      # Properly handle whether the opt :via is a +Rye::Hop+ or a +String+
      # and does nothing if nil
      via_hop(@rye_opts.delete(:via))

      # @rye_opts gets sent to Net::SSH so we need to remove the keys
      # that are not meant for it.
      @rye_safe, @rye_debug = @rye_opts.delete(:safe), @rye_opts.delete(:debug)
      @rye_info, @rye_error = @rye_opts.delete(:info), @rye_opts.delete(:error)
      @rye_getenv = {} if @rye_opts.delete(:getenv) # Enable getenv with a hash
      @rye_ostype, @rye_impltype = @rye_opts.delete(:ostype), @rye_opts.delete(:impltype)
      @rye_quiet, @rye_sudo = @rye_opts.delete(:quiet), @rye_opts.delete(:sudo)
      @rye_templates = @rye_opts.delete(:templates)

      # Store the state of the terminal
      @rye_stty_save = `stty -g`.chomp rescue nil

      unless @rye_templates.nil?
        require @rye_templates.to_s   # should be :erb
      end

      @rye_opts[:logger] = Logger.new(@rye_debug) if @rye_debug # Enable Net::SSH debugging
      @rye_opts[:keys] = [@rye_opts[:keys]].flatten.compact

      # Just in case someone sends a true value rather than IO object
      @rye_debug = STDERR if @rye_debug == true || DEBUG
      @rye_error = STDERR if @rye_error == true
      @rye_info = STDOUT if @rye_info == true

      # Add the given private keys to the keychain that will be used for @rye_host
      add_keys(@rye_opts[:keys])

      # From: capistrano/lib/capistrano/cli.rb
      STDOUT.sync = true # so that Net::SSH prompts show up

      debug "ssh-agent info: #{Rye.sshagent_info.inspect}"
      debug @rye_opts.inspect
    end

### Public Instance Methods

==(other) click to toggle source

Compares itself with the `other` box. If the hostnames are the same, this will return true. Otherwise false.

    # File lib/rye/hop.rb, line 361
    def ==(other)
      @rye_host == other.host
    end

add_key(*keys) click to toggle source
Alias for: add_keys
add_keys(*keys) click to toggle source

Add one or more private keys to the list of key paths.

- `keys` is a list of file paths to private keys

Returns the instance of Box

    # File lib/rye/hop.rb, line 204
    def add_keys(*keys)
      @rye_opts[:keys] ||= []
      @rye_opts[:keys] += keys.flatten.compact
      @rye_opts[:keys].uniq!
      self # MUST RETURN self
    end

Also aliased as: add_key
connect(reconnect=true) click to toggle source

Open an SSH session with +@rye_host+. This called automatically when you the first comamnd is run if it's not already connected. Raises a Rye::NoHost exception if +@rye_host+ is not specified. Will attempt a password login up to 3 times if the initial authentication fails.

- `reconnect` Disconnect first if already connected. The default

is true. When set to false, connect will do nothing if already connected.

    # File lib/rye/hop.rb, line 246
    def connect(reconnect=true)
      raise Rye::NoHost unless @rye_host
      return if @rye_ssh && !reconnect
      disconnect if @rye_ssh
      if @rye_via
        debug "Opening connection to #{@rye_host} as #{@rye_user}, via #{@rye_via.host}"
      else
        debug "Opening connection to #{@rye_host} as #{@rye_user}"
      end
      highline = HighLine.new # Used for password prompt
      retried = 0
      @rye_opts[:keys].compact!  # A quick fix in Windows. TODO: Why is there a nil?
      begin
        if @rye_via
          # tell the +Rye::Hop+ what and where to setup,
          # it returns the local port used
          @rye_localport = @rye_via.fetch_port(@rye_host, @rye_opts[:port].nil? ? 22 : @rye_opts[:port] )
          @rye_ssh = Net::SSH.start("localhost", @rye_user, @rye_opts.merge(:port => @rye_localport) || {})
        else
          @rye_ssh = Net::SSH.start(@rye_host, @rye_user, @rye_opts || {})
        end
        debug "starting the port forward thread"
        port_loop
      rescue Net::SSH::HostKeyMismatch => ex
        STDERR.puts ex.message
        print "\a" if @rye_info # Ring the bell
        if highline.ask("Continue? ").strip.match(/\Ay|yes|sure|ya\z/)
          @rye_opts[:paranoid] = false
          retry
        else
          raise Net::SSH::HostKeyMismatch
        end
      rescue Net::SSH::AuthenticationFailed => ex
        print "\a" if retried == 0 && @rye_info # Ring the bell once
        retried += 1
        if STDIN.tty? && retried <= 3
          STDERR.puts "Passwordless login failed for #{@rye_user}"
          @rye_opts[:password] = highline.ask("Password: ") { |q| q.echo = '' }.strip
          @rye_opts[:auth_methods] ||= []
          @rye_opts[:auth_methods].push *['keyboard-interactive', 'password']
          retry
        else
          raise Net::SSH::AuthenticationFailed
        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 @rye_opts otherwise it lingers until
      # the next connection (if we switch_user is called for example).
      @rye_opts.delete :auth_methods if @rye_opts.has_key?(:auth_methods)

      self
    end

debug?() click to toggle source

    # File lib/rye/hop.rb, line 54
    def debug?; !@rye_debug.nil?; end

disconnect() click to toggle source

Close the SSH session with +@rye_host+. This is called automatically at exit if the connection is open.

    # File lib/rye/hop.rb, line 317
    def disconnect
      return unless @rye_ssh && !@rye_ssh.closed?
      begin
        debug "removing active forwards"
        remove_hops!
        debug "killing port_loop @rye_port_thread"
        @rye_port_thread.kill
        if @rye_ssh.busy?;
          info "Is something still running? (ctrl-C to exit)"
          Timeout::timeout(10) do
            @rye_ssh.loop(0.3) { @rye_ssh.busy?; }
          end
        end
        debug "Closing connection to #{@rye_ssh.host}"
        @rye_ssh.close
        if @rye_via
          debug "disconnecting Hop #{@rye_via.host}"
          @rye_via.disconnect
        end
      rescue SystemCallError, Timeout::Error => ex
        error "Rye::Hop: Disconnect timeout (#{ex.message})"
        debug ex.backtrace
      rescue Interrupt
        debug "Exiting..."
      end
    end

error?() click to toggle source

    # File lib/rye/hop.rb, line 55
    def error?; !@rye_error.nil?; end

exception_hook=(val) click to toggle source

A Hash. The keys are exception classes, the values are Procs to execute

    # File lib/rye/hop.rb, line 59
    def exception_hook=(val); @rye_exception_hook = val; end

fetch_port(host, port = 22, localport = nil) click to toggle source

instance method, that will setup a forward, and return the port used

    # File lib/rye/hop.rb, line 181
    def fetch_port(host, port = 22, localport = nil)
      connect unless @rye_ssh
      if localport.nil?
        port_used = next_port
      else
        port_used = localport
      end
      # i would like to check if the port and host
      # are already an active_locals forward, but that
      # info does not get returned, and trusting the localport
      # is not enough information, so lets just set up a new one
      @rye_ssh.forward.local(port_used, host, port)
      return port_used
    end

host() click to toggle source

    # File lib/rye/hop.rb, line 39
    def host; @rye_host; end

host=(val) click to toggle source

    # File lib/rye/hop.rb, line 48
    def host=(val); @rye_host = val; end

host_key() click to toggle source

Returns the host SSH keys for this box

    # File lib/rye/hop.rb, line 366
    def host_key
      raise "No host" unless @rye_host
      Rye.remote_host_keys(@rye_host)
    end

info?() click to toggle source

    # File lib/rye/hop.rb, line 53
    def info?; !@rye_info.nil?; end

inspect() click to toggle source

    # File lib/rye/hop.rb, line 350
    def inspect
      %{#<%s:%s name=%s cwd=%s umask=%s env=%s via=%s opts=%s keys=%s>} %
      [self.class.to_s, self.host, self.nickname,
       @rye_current_working_directory, @rye_current_umask,
       (@rye_current_environment_variables || '').inspect,
       (@rye_via || '').inspect,
       self.opts.inspect, self.keys.inspect]
    end

keys() click to toggle source

See Rye.keys

    # File lib/rye/hop.rb, line 345
    def keys; Rye.keys; end

nickname() click to toggle source

    # File lib/rye/hop.rb, line 44
    def nickname; @rye_nickname || host; end

nickname=(val) click to toggle source

    # File lib/rye/hop.rb, line 47
    def nickname=(val); @rye_nickname = val; end

opts() click to toggle source

    # File lib/rye/hop.rb, line 40
    def opts; @rye_opts; end

opts=(val) click to toggle source

    # File lib/rye/hop.rb, line 49
    def opts=(val); @rye_opts = val; end

remove_hops!() click to toggle source

Cancel the port forward on all active local forwards

    # File lib/rye/hop.rb, line 302
    def remove_hops!
      return unless @rye_ssh && @rye_ssh.forward.active_locals.count > 0
      @rye_ssh.forward.active_locals.each {|fport, fhost|
        @rye_ssh.forward.cancel_local(fport, fhost)
      }
      if !@rye_ssh.channels.empty?
        @rye_ssh.channels.each {|channel|
          channel[-1].close
        }
      end
      return @rye_ssh.forward.active_locals.count
    end

remove_key(*keys) click to toggle source
Alias for: remove_keys
remove_keys(*keys) click to toggle source

Remove one or more private keys fromt he list of key paths.

- `keys` is a list of file paths to private keys

Returns the instance of Box

    # File lib/rye/hop.rb, line 215
    def remove_keys(*keys)
      @rye_opts[:keys] ||= []
      @rye_opts[:keys] -= keys.flatten.compact
      @rye_opts[:keys].uniq!
      self # MUST RETURN self
    end

Also aliased as: remove_key
root?() click to toggle source

    # File lib/rye/hop.rb, line 42
    def root?; user.to_s == "root" end

ssh_config_options(host) click to toggle source

Parse SSH config files for use with Net::SSH

    # File lib/rye/hop.rb, line 197
    def ssh_config_options(host)
      return Net::SSH::Config.for(host)
    end

switch_user(newuser) click to toggle source

Reconnect as another user. This is different from su= which executes subsequent commands via +su -c COMMAND USER+.

- `newuser` The username to reconnect as

NOTE: if there is an open connection, it's disconnected but not reconnected because it's possible it wasn't connected yet in the first place (if you create the instance with default settings for example)

    # File lib/rye/hop.rb, line 231
    def switch_user(newuser)
      return if newuser.to_s == self.user.to_s
      @rye_opts ||= {}
      @rye_user = newuser
      disconnect
    end

to_s() click to toggle source

Returns +user@rye_host+

    # File lib/rye/hop.rb, line 348
    def to_s; '%s@rye_%s' % [user, @rye_host]; end

user() click to toggle source

    # File lib/rye/hop.rb, line 41
    def user; @rye_user; end

via() click to toggle source

    # File lib/rye/hop.rb, line 45
    def via; @rye_via; end

via?() click to toggle source

    # File lib/rye/hop.rb, line 52
    def via?; !@rye_via.nil?; end

via_hop(*hops) click to toggle source

- `hops` Rye::Hop objects will be added directly

to the set. Hostnames will be used to create new instances of Rye::Hop h1 = Rye::Hop.new "host1" h1.via_hop "host2", :user => "service_user"

OR

h1 = Rye::Hop.new "host1" h2 = Rye::Hop.new "host2" h1.via_hop h2

    # File lib/rye/hop.rb, line 161
    def via_hop(*hops)
      hops = hops.flatten.compact
      if hops.first.nil?
        return @rye_via
      elsif hops.first.is_a?(Rye::Hop)
        @rye_via = hops.first
      elsif hops.first.is_a?(String)
        hop = hops.shift
        if hops.first.is_a?(Hash)
          @rye_via = Rye::Hop.new(hop, hops.first)
        else
          @rye_via = Rye::Hop.new(hop)
        end
      end
      disconnect
      self
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.