Merge pull request #6652 from mitchellh/pr-6596
Only consider the VM interfaces in the IPv6 fixup
This commit is contained in:
commit
3ac1bfc6d9
|
@ -3,6 +3,7 @@ require "socket"
|
|||
|
||||
require "log4r"
|
||||
|
||||
require "vagrant/util/presence"
|
||||
require "vagrant/util/scoped_hash_override"
|
||||
|
||||
module VagrantPlugins
|
||||
|
@ -12,6 +13,7 @@ module VagrantPlugins
|
|||
# a VM with an IPv6 host-only network will someties lose the
|
||||
# route to that machine.
|
||||
class NetworkFixIPv6
|
||||
include Vagrant::Util::Presence
|
||||
include Vagrant::Util::ScopedHashOverride
|
||||
|
||||
def initialize(app, env)
|
||||
|
@ -41,16 +43,15 @@ module VagrantPlugins
|
|||
# If we have no IPv6, forget it
|
||||
return if !has_v6
|
||||
|
||||
# We do, so fix them if we must
|
||||
env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
|
||||
# Ignore interfaces without an IPv6 address
|
||||
next if interface[:ipv6] == ""
|
||||
host_only_interfaces(env).each do |interface|
|
||||
next if !present?(interface[:ipv6])
|
||||
next if interface[:status] != "Up"
|
||||
|
||||
# Make the test IP. This is just the highest value IP
|
||||
ip = IPAddr.new(interface[:ipv6])
|
||||
ip |= IPAddr.new(":#{":FFFF" * (interface[:ipv6_prefix].to_i / 16)}")
|
||||
ip |= ("1" * (128 - interface[:ipv6_prefix].to_i)).to_i(2)
|
||||
|
||||
@logger.info("testing IPv6: #{ip}")
|
||||
|
||||
begin
|
||||
UDPSocket.new(Socket::AF_INET6).connect(ip.to_s, 80)
|
||||
rescue Errno::EHOSTUNREACH
|
||||
|
@ -59,6 +60,21 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# The list of interface names for host-only adapters.
|
||||
# @return [Array<String>]
|
||||
def host_only_interface_names(env)
|
||||
env[:machine].provider.driver.read_network_interfaces
|
||||
.map { |_, i| i[:hostonly] if i[:type] == :hostonly }.compact
|
||||
end
|
||||
|
||||
# The list of host_only_interfaces that are tied to a host-only adapter.
|
||||
# @return [Array]
|
||||
def host_only_interfaces(env)
|
||||
iface_names = self.host_only_interface_names(env)
|
||||
env[:machine].provider.driver.read_host_only_interfaces
|
||||
.select { |interface| iface_names.include?(interface[:name]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require_relative "../base"
|
||||
require 'socket'
|
||||
|
||||
describe VagrantPlugins::ProviderVirtualBox::Action::NetworkFixIPv6 do
|
||||
include_context "unit"
|
||||
|
@ -11,11 +12,14 @@ describe VagrantPlugins::ProviderVirtualBox::Action::NetworkFixIPv6 do
|
|||
end
|
||||
|
||||
let(:machine) do
|
||||
iso_env.machine(iso_env.machine_names[0], :dummy)
|
||||
iso_env.machine(iso_env.machine_names[0], :dummy).tap do |m|
|
||||
m.provider.stub(driver: driver)
|
||||
end
|
||||
end
|
||||
|
||||
let(:env) {{ machine: machine }}
|
||||
let(:app) { lambda { |*args| }}
|
||||
let(:driver) { double("driver") }
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
|
@ -30,4 +34,132 @@ describe VagrantPlugins::ProviderVirtualBox::Action::NetworkFixIPv6 do
|
|||
.and_return(private_network: { ip: "" })
|
||||
expect { subject.call(env) }.to_not raise_error
|
||||
end
|
||||
|
||||
context "with IPv6 interfaces" do
|
||||
let(:socket) { double("socket") }
|
||||
|
||||
before do
|
||||
# This address is only used to trigger the fixup code. It doesn't matter
|
||||
# what it is.
|
||||
allow(machine.config.vm).to receive(:networks)
|
||||
.and_return(private_network: { ip: 'fe:80::' })
|
||||
allow(UDPSocket).to receive(:new).with(Socket::AF_INET6)
|
||||
.and_return(socket)
|
||||
socket.stub(:connect)
|
||||
end
|
||||
|
||||
it "only checks the interfaces associated with the VM" do
|
||||
all_networks = [{name: "vboxnet0",
|
||||
ipv6: "dead:beef::",
|
||||
ipv6_prefix: 64,
|
||||
status: 'Up'
|
||||
},
|
||||
{name: "vboxnet1",
|
||||
ipv6: "badd:badd::",
|
||||
ipv6_prefix: 64,
|
||||
status: 'Up'
|
||||
}
|
||||
]
|
||||
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
|
||||
}
|
||||
allow(machine.provider.driver).to receive(:read_network_interfaces)
|
||||
.and_return(ifaces)
|
||||
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
|
||||
.and_return(all_networks)
|
||||
subject.call(env)
|
||||
expect(socket).to have_received(:connect)
|
||||
.with(all_networks[0][:ipv6] + (['ffff']*4).join(':'), 80)
|
||||
end
|
||||
|
||||
it "correctly uses the netmask to figure out the probe address" do
|
||||
all_networks = [{name: "vboxnet0",
|
||||
ipv6: "dead:beef::",
|
||||
ipv6_prefix: 113,
|
||||
status: 'Up'
|
||||
}
|
||||
]
|
||||
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
|
||||
}
|
||||
allow(machine.provider.driver).to receive(:read_network_interfaces)
|
||||
.and_return(ifaces)
|
||||
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
|
||||
.and_return(all_networks)
|
||||
subject.call(env)
|
||||
expect(socket).to have_received(:connect)
|
||||
.with(all_networks[0][:ipv6] + '7fff', 80)
|
||||
end
|
||||
|
||||
it "should ignore interfaces that are down" do
|
||||
all_networks = [{name: "vboxnet0",
|
||||
ipv6: "dead:beef::",
|
||||
ipv6_prefix: 64,
|
||||
status: 'Down'
|
||||
}
|
||||
]
|
||||
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
|
||||
}
|
||||
allow(machine.provider.driver).to receive(:read_network_interfaces)
|
||||
.and_return(ifaces)
|
||||
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
|
||||
.and_return(all_networks)
|
||||
subject.call(env)
|
||||
expect(socket).to_not have_received(:connect)
|
||||
end
|
||||
|
||||
it "should ignore interfaces without an IPv6 address" do
|
||||
all_networks = [{name: "vboxnet0",
|
||||
ipv6: "",
|
||||
ipv6_prefix: 0,
|
||||
status: 'Up'
|
||||
}
|
||||
]
|
||||
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
|
||||
}
|
||||
allow(machine.provider.driver).to receive(:read_network_interfaces)
|
||||
.and_return(ifaces)
|
||||
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
|
||||
.and_return(all_networks)
|
||||
subject.call(env)
|
||||
expect(socket).to_not have_received(:connect)
|
||||
end
|
||||
|
||||
it "should ignore nat interfaces" do
|
||||
all_networks = [{name: "vboxnet0",
|
||||
ipv6: "",
|
||||
ipv6_prefix: 0,
|
||||
status: 'Up'
|
||||
}
|
||||
]
|
||||
ifaces = { 1 => {type: :nat}
|
||||
}
|
||||
allow(machine.provider.driver).to receive(:read_network_interfaces)
|
||||
.and_return(ifaces)
|
||||
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
|
||||
.and_return(all_networks)
|
||||
subject.call(env)
|
||||
expect(socket).to_not have_received(:connect)
|
||||
end
|
||||
|
||||
it "should reconfigure an interface if unreachable" do
|
||||
all_networks = [{name: "vboxnet0",
|
||||
ipv6: "dead:beef::",
|
||||
ipv6_prefix: 64,
|
||||
status: 'Up'
|
||||
}
|
||||
]
|
||||
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
|
||||
}
|
||||
allow(machine.provider.driver).to receive(:read_network_interfaces)
|
||||
.and_return(ifaces)
|
||||
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
|
||||
.and_return(all_networks)
|
||||
allow(socket).to receive(:connect)
|
||||
.with(all_networks[0][:ipv6] + (['ffff']*4).join(':'), 80)
|
||||
.and_raise Errno::EHOSTUNREACH
|
||||
allow(machine.provider.driver).to receive(:reconfig_host_only)
|
||||
subject.call(env)
|
||||
expect(machine.provider.driver).to have_received(:reconfig_host_only)
|
||||
.with(all_networks[0])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue