foreman/lib/ws_proxy.rb @ develop
197e2dce | Ohad Levy | require 'open3'
|
|
cdd8424f | Lukas Zapletal | require 'socket'
|
|
require 'timeout'
|
|||
197e2dce | Ohad Levy | ||
class PortInUse < StandardError; end
|
|||
8ffd9aee | Ohad Levy | class WsProxy
|
|
attr_accessor :host, :host_port, :password, :timeout, :idle_timeout, :ssl_target
|
|||
197e2dce | Ohad Levy | attr_reader :proxy_port
|
|
# Allowed ports to communicate with our web sockets proxy
|
|||
PORTS = 5910..5930
|
|||
def initialize(attributes)
|
|||
# setup all attributes.
|
|||
defaults.merge(attributes).each do |k, v|
|
|||
c86ed9c6 | Michael Moll | send("#{k}=", v) if respond_to?("#{k}=")
|
|
197e2dce | Ohad Levy | end
|
|
end
|
|||
5f029ed6 | Daniel Lobato | def self.start(attributes)
|
|
8ffd9aee | Ohad Levy | proxy = WsProxy.new(attributes)
|
|
197e2dce | Ohad Levy | proxy.start_proxy
|
|
end
|
|||
f35f4a5f | Michael Moll | def free_port?(port)
|
|
cdd8424f | Lukas Zapletal | socket = Socket.new :INET, :STREAM
|
|
socket.bind(Socket.pack_sockaddr_in(port, '127.0.0.1'))
|
|||
5f5b13a9 | Michael Moll | true
|
|
cdd8424f | Lukas Zapletal | rescue Errno::EADDRINUSE
|
|
5f5b13a9 | Michael Moll | false
|
|
cdd8424f | Lukas Zapletal | ensure
|
|
b03dcd1b | Michael Moll | socket&.close
|
|
cdd8424f | Lukas Zapletal | end
|
|
197e2dce | Ohad Levy | def start_proxy
|
|
cdd8424f | Lukas Zapletal | # randomly preselect free tcp port from the range
|
|
port = 0
|
|||
8bbfa2c3 | David Davis | Timeout.timeout(5) do
|
|
cdd8424f | Lukas Zapletal | until free_port?(port = rand(PORTS)); end
|
|
end
|
|||
# execute websockify proxy
|
|||
197e2dce | Ohad Levy | begin
|
|
20f48047 | Ewoud Kohl van Wijngaarden | cmd = "websockify --daemon --idle-timeout=#{idle_timeout} --timeout=#{timeout} #{port} #{host}:#{host_port}"
|
|
8ffd9aee | Ohad Levy | cmd += " --ssl-target" if ssl_target
|
|
97c34475 | Lukas Zapletal | if Setting[:websockets_encrypt]
|
|
cmd += " --cert #{Setting[:websockets_ssl_cert]}" if Setting[:websockets_ssl_cert]
|
|||
cmd += " --key #{Setting[:websockets_ssl_key]}" if Setting[:websockets_ssl_key]
|
|||
end
|
|||
197e2dce | Ohad Levy | execute(cmd)
|
|
20f48047 | Ewoud Kohl van Wijngaarden | rescue Errno::ENOENT
|
|
raise ::Foreman::Exception.new(N_('Websockify was not found'))
|
|||
197e2dce | Ohad Levy | rescue PortInUse
|
|
cdd8424f | Lukas Zapletal | # fallback just in case of race condition
|
|
197e2dce | Ohad Levy | port += 1
|
|
cdd8424f | Lukas Zapletal | if port >= PORTS.last
|
|
75618724 | Dominic Cleal | raise ::Foreman::Exception.new(N_('No free ports available for websockify, try again later'))
|
|
cdd8424f | Lukas Zapletal | else
|
|
retry
|
|||
end
|
|||
197e2dce | Ohad Levy | end
|
|
@proxy_port = port
|
|||
c11b7561 | Shira Maximov | { :port => proxy_port, :password => password, :encrypt => Setting[:websockets_encrypt] }
|
|
197e2dce | Ohad Levy | end
|
|
private
|
|||
def defaults
|
|||
{
|
|||
8ffd9aee | Ohad Levy | :timeout => 120,
|
|
:idle_timeout => 120,
|
|||
:host_port => 5900,
|
|||
f2ee562e | Marek Hulan | :host => "0.0.0.0",
|
|
197e2dce | Ohad Levy | }
|
|
end
|
|||
def logger
|
|||
Rails.logger
|
|||
end
|
|||
5f029ed6 | Daniel Lobato | def execute(cmd)
|
|
197e2dce | Ohad Levy | logger.debug "Starting VNC Proxy: #{cmd}"
|
|
8bbfa2c3 | David Davis | Open3.popen3(cmd) do |stdin, stdout, stderr|
|
|
197e2dce | Ohad Levy | stdout.each do |line|
|
|
logger.debug "[#{line}"
|
|||
end
|
|||
stderr.each do |line|
|
|||
logger.debug "VNCProxy Error: #{line}"
|
|||
raise PortInUse if line["socket.error: [Errno 98] Address already in use"]
|
|||
end
|
|||
end
|
|||
end
|
|||
end
|