Provides support for defining the NIC type used for any guest adapter which does not define an adapter type. This is defaulted to "virtio".
280 lines
9.2 KiB
Ruby
280 lines
9.2 KiB
Ruby
require_relative "../base"
|
|
|
|
require "vagrant/util/platform"
|
|
|
|
describe VagrantPlugins::ProviderVirtualBox::Action::Network do
|
|
include_context "unit"
|
|
include_context "virtualbox"
|
|
|
|
let(:iso_env) do
|
|
# We have to create a Vagrantfile so there is a root path
|
|
env = isolated_environment
|
|
env.vagrantfile("")
|
|
env.create_vagrant_env
|
|
end
|
|
|
|
let(:machine) do
|
|
iso_env.machine(iso_env.machine_names[0], :virtualbox).tap do |m|
|
|
allow(m.provider).to receive(:driver).and_return(driver)
|
|
end
|
|
end
|
|
|
|
let(:env) {{ machine: machine, ui: machine.ui }}
|
|
let(:app) { lambda { |*args| }}
|
|
let(:driver) { double("driver") }
|
|
|
|
let(:nics) { {} }
|
|
|
|
subject { described_class.new(app, env) }
|
|
|
|
before do
|
|
allow(driver).to receive(:enable_adapters)
|
|
allow(driver).to receive(:read_network_interfaces) { nics }
|
|
end
|
|
|
|
it "calls the next action in the chain" do
|
|
called = false
|
|
app = lambda { |*args| called = true }
|
|
|
|
action = described_class.new(app, env)
|
|
action.call(env)
|
|
|
|
expect(called).to eq(true)
|
|
end
|
|
|
|
it "creates a host-only interface with an IPv6 address <prefix>:1" do
|
|
guest = double("guest")
|
|
machine.config.vm.network 'private_network', { type: :static, ip: 'dead:beef::100' }
|
|
#allow(driver).to receive(:read_bridged_interfaces) { [] }
|
|
allow(driver).to receive(:read_host_only_interfaces) { [] }
|
|
#allow(driver).to receive(:read_dhcp_servers) { [] }
|
|
allow(machine).to receive(:guest) { guest }
|
|
allow(driver).to receive(:create_host_only_network) {{ name: 'vboxnet0' }}
|
|
allow(guest).to receive(:capability)
|
|
interface_ip = 'dead:beef::1'
|
|
|
|
subject.call(env)
|
|
|
|
expect(driver).to have_received(:create_host_only_network).with({
|
|
adapter_ip: interface_ip,
|
|
netmask: 64,
|
|
})
|
|
|
|
expect(guest).to have_received(:capability).with(:configure_networks, [{
|
|
type: :static6,
|
|
adapter_ip: 'dead:beef::1',
|
|
ip: 'dead:beef::100',
|
|
netmask: 64,
|
|
auto_config: true,
|
|
interface: nil
|
|
}])
|
|
end
|
|
|
|
it "raises the appropriate error when provided with an invalid IP address" do
|
|
guest = double("guest")
|
|
machine.config.vm.network 'private_network', { ip: '192.168.33.06' }
|
|
|
|
expect{ subject.call(env) }.to raise_error(Vagrant::Errors::NetworkAddressInvalid)
|
|
end
|
|
|
|
it "raises no invalid network error when provided with a valid IP address" do
|
|
guest = double("guest")
|
|
machine.config.vm.network 'private_network', { ip: '192.168.33.6' }
|
|
|
|
expect{ subject.call(env) }.not_to raise_error(Vagrant::Errors::NetworkAddressInvalid)
|
|
end
|
|
|
|
describe "setting nic type" do
|
|
before do
|
|
guest = double("guest")
|
|
allow(driver).to receive(:read_bridged_interfaces) { [] }
|
|
allow(driver).to receive(:read_host_only_interfaces) { [] }
|
|
allow(driver).to receive(:create_host_only_network) { {} }
|
|
allow(driver).to receive(:read_dhcp_servers) { [] }
|
|
allow(driver).to receive(:create_dhcp_server)
|
|
allow(machine).to receive(:guest) { guest }
|
|
allow(guest).to receive(:capability)
|
|
end
|
|
|
|
it "sets default nic type when unset" do
|
|
machine.config.vm.network 'private_network', { type: 'dhcp' }
|
|
subject.call(env)
|
|
_, net_config = machine.config.vm.networks.detect { |type, _| type == :private_network }
|
|
expect(net_config[:virtualbox__nic_type]).to eq("virtio")
|
|
end
|
|
|
|
it "does not set nic type when already set" do
|
|
machine.config.vm.network 'private_network', { type: 'dhcp', nic_type: "custom" }
|
|
subject.call(env)
|
|
_, net_config = machine.config.vm.networks.detect { |type, _| type == :private_network }
|
|
expect(net_config[:nic_type]).to eq("custom")
|
|
expect(net_config[:virtualbox__nic_type]).to be_nil
|
|
end
|
|
|
|
it "does not set nic type when namespaced option is set" do
|
|
machine.config.vm.network 'private_network', { type: 'dhcp', virtualbox__nic_type: "custom" }
|
|
subject.call(env)
|
|
_, net_config = machine.config.vm.networks.detect { |type, _| type == :private_network }
|
|
expect(net_config[:nic_type]).to be_nil
|
|
expect(net_config[:virtualbox__nic_type]).to eq("custom")
|
|
end
|
|
end
|
|
|
|
context "with a dhcp private network" do
|
|
let(:bridgedifs) { [] }
|
|
let(:hostonlyifs) { [] }
|
|
let(:dhcpservers) { [] }
|
|
let(:guest) { double("guest") }
|
|
let(:network_args) {{ type: :dhcp }}
|
|
|
|
before do
|
|
machine.config.vm.network 'private_network', network_args
|
|
allow(driver).to receive(:read_bridged_interfaces) { bridgedifs }
|
|
allow(driver).to receive(:read_host_only_interfaces) { hostonlyifs }
|
|
allow(driver).to receive(:read_dhcp_servers) { dhcpservers }
|
|
allow(machine).to receive(:guest) { guest }
|
|
end
|
|
|
|
it "creates a host only interface and a dhcp server using default ips, then tells the guest to configure the network after boot" do
|
|
allow(driver).to receive(:create_host_only_network) {{ name: 'vboxnet0' }}
|
|
allow(driver).to receive(:create_dhcp_server)
|
|
allow(guest).to receive(:capability)
|
|
|
|
subject.call(env)
|
|
|
|
expect(driver).to have_received(:create_host_only_network).with({
|
|
adapter_ip: '172.28.128.1',
|
|
netmask: '255.255.255.0',
|
|
})
|
|
|
|
expect(driver).to have_received(:create_dhcp_server).with('vboxnet0', {
|
|
adapter_ip: "172.28.128.1",
|
|
auto_config: true,
|
|
ip: "172.28.128.1",
|
|
mac: nil,
|
|
name: nil,
|
|
netmask: "255.255.255.0",
|
|
nic_type: "virtio",
|
|
type: :dhcp,
|
|
dhcp_ip: "172.28.128.2",
|
|
dhcp_lower: "172.28.128.3",
|
|
dhcp_upper: "172.28.128.254",
|
|
adapter: 2
|
|
})
|
|
|
|
expect(guest).to have_received(:capability).with(:configure_networks, [{
|
|
type: :dhcp,
|
|
adapter_ip: "172.28.128.1",
|
|
ip: "172.28.128.1",
|
|
netmask: "255.255.255.0",
|
|
auto_config: true,
|
|
interface: nil
|
|
}])
|
|
end
|
|
|
|
context "when the default vbox dhcpserver is present from a fresh vbox install (see issue #3803)" do
|
|
let(:dhcpservers) {[
|
|
{
|
|
network_name: 'HostInterfaceNetworking-vboxnet0',
|
|
network: 'vboxnet0',
|
|
ip: '192.168.56.100',
|
|
netmask: '255.255.255.0',
|
|
lower: '192.168.56.101',
|
|
upper: '192.168.56.254'
|
|
}
|
|
]}
|
|
|
|
it "removes the invalid dhcpserver so it won't collide with any host only interface" do
|
|
allow(driver).to receive(:remove_dhcp_server)
|
|
allow(driver).to receive(:create_host_only_network) {{ name: 'vboxnet0' }}
|
|
allow(driver).to receive(:create_dhcp_server)
|
|
allow(guest).to receive(:capability)
|
|
|
|
subject.call(env)
|
|
|
|
expect(driver).to have_received(:remove_dhcp_server).with('HostInterfaceNetworking-vboxnet0')
|
|
end
|
|
|
|
context "but the user has intentionally configured their network just that way" do
|
|
let (:network_args) {{
|
|
type: :dhcp,
|
|
adapter_ip: '192.168.56.1',
|
|
dhcp_ip: '192.168.56.100',
|
|
dhcp_lower: '192.168.56.101',
|
|
dhcp_upper: '192.168.56.254'
|
|
}}
|
|
|
|
it "does not attempt to remove the dhcpserver" do
|
|
allow(driver).to receive(:remove_dhcp_server)
|
|
allow(driver).to receive(:create_host_only_network) {{ name: 'vboxnet0' }}
|
|
allow(driver).to receive(:create_dhcp_server)
|
|
allow(guest).to receive(:capability)
|
|
|
|
subject.call(env)
|
|
|
|
expect(driver).not_to have_received(:remove_dhcp_server).with('HostInterfaceNetworking-vboxnet0')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with invalid settings' do
|
|
[
|
|
{ ip: 'foo'},
|
|
{ ip: '1.2.3'},
|
|
{ ip: 'dead::beef::'},
|
|
{ ip: '172.28.128.3', netmask: 64},
|
|
{ ip: '172.28.128.3', netmask: 'ffff:ffff::'},
|
|
{ ip: 'dead:beef::', netmask: 'foo:bar::'},
|
|
{ ip: 'dead:beef::', netmask: '255.255.255.0'}
|
|
].each do |args|
|
|
it 'raises an exception' do
|
|
machine.config.vm.network 'private_network', **args
|
|
expect { subject.call(env) }.
|
|
to raise_error(Vagrant::Errors::NetworkAddressInvalid)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#hostonly_find_matching_network" do
|
|
let(:ip){ "192.168.55.2" }
|
|
let(:config){ {ip: ip, netmask: "255.255.255.0"} }
|
|
let(:interfaces){ [] }
|
|
|
|
before do
|
|
allow(driver).to receive(:read_host_only_interfaces).and_return(interfaces)
|
|
subject.instance_variable_set(:@env, env)
|
|
end
|
|
|
|
context "with no defined host interfaces" do
|
|
it "should return nil" do
|
|
expect(subject.hostonly_find_matching_network(config)).to be_nil
|
|
end
|
|
end
|
|
|
|
context "with matching host interface" do
|
|
let(:interfaces){ [{ip: "192.168.55.1", netmask: "255.255.255.0", name: "vnet"}] }
|
|
|
|
it "should return matching interface" do
|
|
expect(subject.hostonly_find_matching_network(config)).to eq(interfaces.first)
|
|
end
|
|
|
|
context "with matching name" do
|
|
let(:config){ {ip: ip, netmask: "255.255.255.0", name: "vnet"} }
|
|
|
|
it "should return matching interface" do
|
|
expect(subject.hostonly_find_matching_network(config)).to eq(interfaces.first)
|
|
end
|
|
end
|
|
|
|
context "with non-matching name" do
|
|
let(:config){ {ip: ip, netmask: "255.255.255.0", name: "unknown"} }
|
|
|
|
it "should return nil" do
|
|
expect(subject.hostonly_find_matching_network(config)).to be_nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|