First pass at a forwarded port collision middleware
This commit is contained in:
parent
7c5d118e0d
commit
e97c330281
|
@ -0,0 +1,93 @@
|
||||||
|
require "set"
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
|
||||||
|
require "vagrant/util/is_port_open"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
module Action
|
||||||
|
module Builtin
|
||||||
|
# This middleware class will detect and handle collisions with
|
||||||
|
# forwarded ports, whether that means raising an error or repairing
|
||||||
|
# them automatically.
|
||||||
|
#
|
||||||
|
# Parameters it takes from the environment hash:
|
||||||
|
#
|
||||||
|
# * `:port_collision_repair` - If true, it will attempt to repair
|
||||||
|
# port collisions. If false, it will raise an exception when
|
||||||
|
# there is a collision.
|
||||||
|
#
|
||||||
|
class HandleForwardedPortCollisions
|
||||||
|
include Util::IsPortOpen
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::action::builtin::handle_port_collisions")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@logger.debug("Detecting any forwarded port collisions...")
|
||||||
|
|
||||||
|
# Determine the handler we'll use if we have any port collisions
|
||||||
|
repair = !!env[:port_collision_repair]
|
||||||
|
|
||||||
|
# Determine a list of usable ports for repair
|
||||||
|
usable_ports = Set.new(env[:machine].config.vm.usable_port_range)
|
||||||
|
|
||||||
|
# Pass one, remove all defined host ports from usable ports
|
||||||
|
with_forwarded_ports do |args|
|
||||||
|
usable_ports.delete(args[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Pass two, detect/handle any collisions
|
||||||
|
with_forwarded_ports do |args|
|
||||||
|
# Get the host port of this forwarded port
|
||||||
|
# TODO: handle overrides in the case that an existing VM is
|
||||||
|
# already running with auto-corrected ports.
|
||||||
|
guest_port = args[0]
|
||||||
|
host_port = args[1]
|
||||||
|
|
||||||
|
# If the port is open (listening for TCP connections)
|
||||||
|
if is_port_open?("127.0.0.1", host_port)
|
||||||
|
if !repair
|
||||||
|
raise Errors::ForwardPortCollision,
|
||||||
|
:guest_port => guest_port.to_s,
|
||||||
|
:host_port => host_port.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
@logger.info("Attempting to repair FP collision: #{host_port}")
|
||||||
|
|
||||||
|
# If we have no usable ports then we can't repair
|
||||||
|
if usable_ports.empty?
|
||||||
|
raise Errors::ForwardPortAutolistEmpty,
|
||||||
|
:vm_name => env[:machine].name,
|
||||||
|
:guest_port => guest_port.to_s,
|
||||||
|
:host_port => host_port.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
# Attempt to repair the forwarded port
|
||||||
|
repaired_port = usable_ports.to_a.sort[0]
|
||||||
|
usable_ports.delete(repaired_port)
|
||||||
|
|
||||||
|
# Modify the args in place
|
||||||
|
args[1] = repaired_port
|
||||||
|
|
||||||
|
@logger.info("Repaired FP collision: #{host_port} to #{repaired_port}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def with_forwarded_ports
|
||||||
|
env[:machine].config.vm.networks.each do |type, args|
|
||||||
|
# Ignore anything but forwarded ports
|
||||||
|
next if type != :forwarded_port
|
||||||
|
|
||||||
|
yield args
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue