Class: Capistrano::Gateway

Inherits:
Object
  • Object
show all
Defined in:
lib/capistrano/gateway.rb

Overview

Black magic. It uses threads and Net::SSH to set up a connection to a gateway server, through which connections to other servers may be tunnelled.

It is used internally by Actor, but may be useful on its own, as well.

Usage:

config = Capistrano::Configuration.new
gateway = Capistrano::Gateway.new('gateway.example.com', config)

sess1 = gateway.connect_to('hidden.example.com')
sess2 = gateway.connect_to('other.example.com')

Constant Summary collapse

MAX_PORT =
65535
MIN_PORT =
1024

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server, config) ⇒ Gateway

:nodoc:



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/capistrano/gateway.rb', line 31

def initialize(server, config) #:nodoc:
  @config = config
  @next_port = MAX_PORT
  @terminate_thread = false
  @port_guard = Mutex.new

  mutex = Mutex.new
  waiter = ConditionVariable.new

  @thread = Thread.new do
    @config.logger.trace "starting connection to gateway #{server}"
    SSH.connect(server, @config) do |@session|
      @config.logger.trace "gateway connection established"
      mutex.synchronize { waiter.signal }
      @session.loop { !@terminate_thread }
    end
  end

  mutex.synchronize { waiter.wait(mutex) }
end

Instance Attribute Details

#sessionObject (readonly)

The Net::SSH session representing the gateway connection.



26
27
28
# File 'lib/capistrano/gateway.rb', line 26

def session
  @session
end

#threadObject (readonly)

The thread inside which the gateway connection itself is running.



23
24
25
# File 'lib/capistrano/gateway.rb', line 23

def thread
  @thread
end

Instance Method Details

#connect_to(server) ⇒ Object

Connects to the given server by opening a forwarded port from the local host to the server, via the gateway, and then opens and returns a new Net::SSH connection via that port.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/capistrano/gateway.rb', line 69

def connect_to(server)
  connection = nil
  @config.logger.trace "establishing connection to #{server} via gateway"
  local_port = next_port

  thread = Thread.new do
    begin
      user, server_stripped, port = SSH.parse_server(server)   
      @config.ssh_options[:username] = user if user
      remote_port = port || 22
      @session.forward.local(local_port, server_stripped, remote_port)
      connection = SSH.connect('127.0.0.1', @config, local_port)
      @config.logger.trace "connection to #{server} via gateway established"
    rescue Errno::EADDRINUSE
      local_port = next_port
      retry
    rescue Exception => e
      puts e.class.name
      puts e.backtrace.join("\n")
    end
  end

  thread.join
  connection or raise "Could not establish connection to #{server}"
end

#shutdown!Object

Shuts down all forwarded connections and terminates the gateway.



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/capistrano/gateway.rb', line 53

def shutdown!
  # cancel all active forward channels
  @session.forward.active_locals.each do |lport, host, port|
    @session.forward.cancel_local(lport)
  end

  # terminate the gateway thread
  @terminate_thread = true

  # wait for the gateway thread to stop
  @thread.join
end