Fix for #4608
Added support for Port forwarding in an IP aliased environment. The change makes the following forwarding rule(s) possible. Ex: eth0 is ip aliased to have a range of IP addresses 10.20.30.0/24. In the Vagrant file, we can now have an entry like the following and it will just work! Note the host port 8081 is the same for both .1 and .2. Vagrant.configure("2") do |config| config.vm.network "forwarded_port", guest: 80, host: 8080 config.vm.network "forwarded_port", guest: 81, host: 8081, host_ip: 10.20.30.1 config.vm.network "forwarded_port", guest: 82, host: 8081, host_ip: 10.20.30.2 end
This commit is contained in:
parent
b99ed21506
commit
af9d0df635
|
@ -62,7 +62,7 @@ module Vagrant
|
||||||
@logger.info("Detecting any forwarded port collisions...")
|
@logger.info("Detecting any forwarded port collisions...")
|
||||||
|
|
||||||
# Get the extra ports we consider in use
|
# Get the extra ports we consider in use
|
||||||
extra_in_use = env[:port_collision_extra_in_use] || []
|
extra_in_use = env[:port_collision_extra_in_use] || {}
|
||||||
|
|
||||||
# Get the remap
|
# Get the remap
|
||||||
remap = env[:port_collision_remap] || {}
|
remap = env[:port_collision_remap] || {}
|
||||||
|
@ -81,7 +81,7 @@ module Vagrant
|
||||||
|
|
||||||
# Determine a list of usable ports for repair
|
# Determine a list of usable ports for repair
|
||||||
usable_ports = Set.new(env[:machine].config.vm.usable_port_range)
|
usable_ports = Set.new(env[:machine].config.vm.usable_port_range)
|
||||||
usable_ports.subtract(extra_in_use)
|
usable_ports.subtract(extra_in_use.keys)
|
||||||
|
|
||||||
# Pass one, remove all defined host ports from usable ports
|
# Pass one, remove all defined host ports from usable ports
|
||||||
with_forwarded_ports(env) do |options|
|
with_forwarded_ports(env) do |options|
|
||||||
|
@ -92,6 +92,7 @@ module Vagrant
|
||||||
with_forwarded_ports(env) do |options|
|
with_forwarded_ports(env) do |options|
|
||||||
guest_port = options[:guest]
|
guest_port = options[:guest]
|
||||||
host_port = options[:host]
|
host_port = options[:host]
|
||||||
|
host_ip = options[:host_ip]
|
||||||
|
|
||||||
if options[:protocol] && options[:protocol] != "tcp"
|
if options[:protocol] && options[:protocol] != "tcp"
|
||||||
@logger.debug("Skipping #{host_port} because UDP protocol.")
|
@logger.debug("Skipping #{host_port} because UDP protocol.")
|
||||||
|
@ -105,9 +106,9 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
# If the port is open (listening for TCP connections)
|
# If the port is open (listening for TCP connections)
|
||||||
in_use = extra_in_use.include?(host_port) ||
|
in_use = is_forwarded_already(extra_in_use, host_port, host_ip) ||
|
||||||
port_checker[host_port] ||
|
port_checker[host_ip, host_port] ||
|
||||||
lease_check(host_port)
|
lease_check(host_ip, host_port)
|
||||||
if in_use
|
if in_use
|
||||||
if !repair || !options[:auto_correct]
|
if !repair || !options[:auto_correct]
|
||||||
raise Errors::ForwardPortCollision,
|
raise Errors::ForwardPortCollision,
|
||||||
|
@ -124,9 +125,9 @@ module Vagrant
|
||||||
usable_ports.delete(repaired_port)
|
usable_ports.delete(repaired_port)
|
||||||
|
|
||||||
# If the port is in use, then we can't use this either...
|
# If the port is in use, then we can't use this either...
|
||||||
in_use = extra_in_use.include?(repaired_port) ||
|
in_use = is_forwarded_already(extra_in_use, repaired_port, host_ip) ||
|
||||||
port_checker[repaired_port] ||
|
port_checker[host_ip, repaired_port] ||
|
||||||
lease_check(repaired_port)
|
lease_check(host_ip, repaired_port)
|
||||||
if in_use
|
if in_use
|
||||||
@logger.info("Repaired port also in use: #{repaired_port}. Trying another...")
|
@logger.info("Repaired port also in use: #{repaired_port}. Trying another...")
|
||||||
next
|
next
|
||||||
|
@ -158,13 +159,19 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def lease_check(port)
|
def lease_check(host_ip=nil, host_port)
|
||||||
# Check if this port is "leased". We use a leasing system of
|
# Check if this port is "leased". We use a leasing system of
|
||||||
# about 60 seconds to avoid any forwarded port collisions in
|
# about 60 seconds to avoid any forwarded port collisions in
|
||||||
# a highly parallelized environment.
|
# a highly parallelized environment.
|
||||||
leasedir = @machine.env.data_dir.join("fp-leases")
|
leasedir = @machine.env.data_dir.join("fp-leases")
|
||||||
leasedir.mkpath
|
leasedir.mkpath
|
||||||
|
|
||||||
|
if host_ip.nil?
|
||||||
|
lease_file_name = host_port.to_s
|
||||||
|
else
|
||||||
|
lease_file_name = "#{host_ip.gsub('.','_')}_#{host_port.to_s}"
|
||||||
|
end
|
||||||
|
|
||||||
invalid = false
|
invalid = false
|
||||||
oldest = Time.now.to_i - 60
|
oldest = Time.now.to_i - 60
|
||||||
leasedir.children.each do |child|
|
leasedir.children.each do |child|
|
||||||
|
@ -173,7 +180,7 @@ module Vagrant
|
||||||
child.delete
|
child.delete
|
||||||
end
|
end
|
||||||
|
|
||||||
if child.basename.to_s == port.to_s
|
if child.basename.to_s == lease_file_name
|
||||||
invalid = true
|
invalid = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -182,13 +189,13 @@ module Vagrant
|
||||||
return true if invalid
|
return true if invalid
|
||||||
|
|
||||||
# Otherwise, create the lease
|
# Otherwise, create the lease
|
||||||
leasedir.join(port.to_s).open("w+") do |f|
|
leasedir.join(lease_file_name).open("w+") do |f|
|
||||||
f.binmode
|
f.binmode
|
||||||
f.write(Time.now.to_i.to_s + "\n")
|
f.write(Time.now.to_i.to_s + "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add to the leased array so we unlease it right away
|
# Add to the leased array so we unlease it right away
|
||||||
@leased << port.to_s
|
@leased << lease_file_name
|
||||||
|
|
||||||
# Things look good to us!
|
# Things look good to us!
|
||||||
false
|
false
|
||||||
|
@ -203,8 +210,32 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def port_check(port)
|
# This functions checks to see if the current instance's hostport and
|
||||||
is_port_open?("127.0.0.1", port)
|
# hostip for forwarding is in use by the virtual machines created
|
||||||
|
# previously.
|
||||||
|
def is_forwarded_already(extra_in_use, hostport, hostip)
|
||||||
|
hostip = '*' if hostip.nil? || hostip.empty?
|
||||||
|
# ret. false if none of the VMs we spun up had this port forwarded.
|
||||||
|
return false if not extra_in_use.has_key?(hostport)
|
||||||
|
|
||||||
|
# ret. true if the user has requested to bind on all interfaces but
|
||||||
|
# we already have a rule in one the VMs we spun up.
|
||||||
|
if hostip == '*'
|
||||||
|
if extra_in_use.fetch(hostport).size != 0
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return extra_in_use.fetch(hostport).include?(hostip)
|
||||||
|
end
|
||||||
|
|
||||||
|
def port_check(host_ip, host_port)
|
||||||
|
# If the user hasn't specified a host_ip, his/her intention is taken to be
|
||||||
|
# to listen on all interfaces.
|
||||||
|
return is_port_open?("0.0.0.0", host_port) if host_ip.nil?
|
||||||
|
return is_port_open?(host_ip, host_port)
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_forwarded_ports(env)
|
def with_forwarded_ports(env)
|
||||||
|
|
|
@ -244,9 +244,11 @@ module VagrantPlugins
|
||||||
default_id = nil
|
default_id = nil
|
||||||
|
|
||||||
if type == :forwarded_port
|
if type == :forwarded_port
|
||||||
# For forwarded ports, set the default ID to the
|
# For forwarded ports, set the default ID to be the
|
||||||
# host port so that host ports overwrite each other.
|
# concat of host_ip, proto and host_port. This would ensure Vagrant
|
||||||
default_id = "#{options[:protocol]}#{options[:host]}"
|
# caters for port forwarding in an IP aliased environment where
|
||||||
|
# different host IP addresses are to be listened on the same port.
|
||||||
|
default_id = "#{options[:host_ip]}#{options[:protocol]}#{options[:host]}"
|
||||||
end
|
end
|
||||||
|
|
||||||
options[:id] = default_id || SecureRandom.uuid
|
options[:id] = default_id || SecureRandom.uuid
|
||||||
|
@ -676,7 +678,7 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
if options[:host]
|
if options[:host]
|
||||||
key = "#{options[:protocol]}#{options[:host]}"
|
key = "#{options[:host_ip]}#{options[:protocol]}#{options[:host]}"
|
||||||
if fp_used.include?(key)
|
if fp_used.include?(key)
|
||||||
errors << I18n.t("vagrant.config.vm.network_fp_host_not_unique",
|
errors << I18n.t("vagrant.config.vm.network_fp_host_not_unique",
|
||||||
host: options[:host].to_s,
|
host: options[:host].to_s,
|
||||||
|
|
|
@ -366,8 +366,10 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse out the forwarded port information
|
# Parse out the forwarded port information
|
||||||
if line =~ /^Forwarding.+?="(.+?),.+?,.*?,(.+?),.*?,(.+?)"$/
|
# Forwarding(1)="172.22.8.201tcp32977,tcp,172.22.8.201,32977,,3777"
|
||||||
result = [current_nic, $1.to_s, $2.to_i, $3.to_i]
|
# Forwarding(2)="tcp32978,tcp,,32978,,3777"
|
||||||
|
if line =~ /^Forwarding.+?="(.+?),.+?,(.*?),(.+?),.*?,(.+?)"$/
|
||||||
|
result = [current_nic, $1.to_s, $3.to_i, $4.to_i, $2]
|
||||||
@logger.debug(" - #{result.inspect}")
|
@logger.debug(" - #{result.inspect}")
|
||||||
results << result
|
results << result
|
||||||
end
|
end
|
||||||
|
@ -556,7 +558,7 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_used_ports
|
def read_used_ports
|
||||||
ports = []
|
used_ports = Hash.new{|hash, key| hash[key] = Set.new}
|
||||||
execute("list", "vms", retryable: true).split("\n").each do |line|
|
execute("list", "vms", retryable: true).split("\n").each do |line|
|
||||||
if line =~ /^".+?" \{(.+?)\}$/
|
if line =~ /^".+?" \{(.+?)\}$/
|
||||||
uuid = $1.to_s
|
uuid = $1.to_s
|
||||||
|
@ -564,13 +566,14 @@ module VagrantPlugins
|
||||||
# Ignore our own used ports
|
# Ignore our own used ports
|
||||||
next if uuid == @uuid
|
next if uuid == @uuid
|
||||||
|
|
||||||
read_forwarded_ports(uuid, true).each do |_, _, hostport, _|
|
read_forwarded_ports(uuid, true).each do |_, _, hostport, _, hostip|
|
||||||
ports << hostport
|
hostip = '*' if hostip.nil? || hostip.empty?
|
||||||
|
used_ports[hostport].add?(hostip)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ports
|
used_ports
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_vms
|
def read_vms
|
||||||
|
|
|
@ -15,6 +15,7 @@ module VagrantPlugins
|
||||||
if type == :forwarded_port
|
if type == :forwarded_port
|
||||||
guest_port = options[:guest]
|
guest_port = options[:guest]
|
||||||
host_port = options[:host]
|
host_port = options[:host]
|
||||||
|
host_ip = options[:host_ip]
|
||||||
protocol = options[:protocol] || "tcp"
|
protocol = options[:protocol] || "tcp"
|
||||||
options = scoped_hash_override(options, :virtualbox)
|
options = scoped_hash_override(options, :virtualbox)
|
||||||
id = options[:id]
|
id = options[:id]
|
||||||
|
@ -22,7 +23,8 @@ module VagrantPlugins
|
||||||
# If the forwarded port was marked as disabled, ignore.
|
# If the forwarded port was marked as disabled, ignore.
|
||||||
next if options[:disabled]
|
next if options[:disabled]
|
||||||
|
|
||||||
mappings[host_port.to_s + protocol.to_s] =
|
key = "#{host_ip}#{protocol}#{host_port}"
|
||||||
|
mappings[key] =
|
||||||
Model::ForwardedPort.new(id, host_port, guest_port, options)
|
Model::ForwardedPort.new(id, host_port, guest_port, options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue