Flag when source device for public network does not exist (#1499)

Detect when the device provided for connecting the VM to a public
network via the host does not exist and attempt to provide a useful
error message to give end users a hint of how to correct.

Fixes: #1477
This commit is contained in:
Darragh Bailey
2022-06-03 14:54:37 +01:00
committed by GitHub
parent c7bcb50b2b
commit 70866ecbaa
2 changed files with 75 additions and 1 deletions

View File

@@ -195,6 +195,9 @@ module VagrantPlugins
# serial consoles # serial consoles
attr_accessor :serials attr_accessor :serials
# internal helper attributes
attr_accessor :host_device_exclude_prefixes
def initialize def initialize
@uri = UNSET_VALUE @uri = UNSET_VALUE
@driver = UNSET_VALUE @driver = UNSET_VALUE
@@ -342,6 +345,9 @@ module VagrantPlugins
@qemu_use_agent = UNSET_VALUE @qemu_use_agent = UNSET_VALUE
@serials = UNSET_VALUE @serials = UNSET_VALUE
# internal options to help override behaviour
@host_device_exclude_prefixes = UNSET_VALUE
end end
def boot(device) def boot(device)
@@ -972,6 +978,8 @@ module VagrantPlugins
@qemu_use_agent = false if @qemu_use_agent == UNSET_VALUE @qemu_use_agent = false if @qemu_use_agent == UNSET_VALUE
@serials = [{:type => 'pty', :source => nil}] if @serials == UNSET_VALUE @serials = [{:type => 'pty', :source => nil}] if @serials == UNSET_VALUE
@host_device_exclude_prefixes = ['docker', 'macvtap', 'virbr', 'vnet'] if @host_device_exclude_prefixes == UNSET_VALUE
end end
def validate(machine) def validate(machine)
@@ -1029,7 +1037,9 @@ module VagrantPlugins
errors << "#{e}" errors << "#{e}"
end end
machine.config.vm.networks.each do |_type, opts| machine.config.vm.networks.each_with_index do |network, index|
type, opts = network
if opts[:mac] if opts[:mac]
if opts[:mac] =~ /\A([0-9a-fA-F]{12})\z/ if opts[:mac] =~ /\A([0-9a-fA-F]{12})\z/
opts[:mac] = opts[:mac].scan(/../).join(':') opts[:mac] = opts[:mac].scan(/../).join(':')
@@ -1038,6 +1048,13 @@ module VagrantPlugins
errors << "Configured NIC MAC '#{opts[:mac]}' is not in 'xx:xx:xx:xx:xx:xx' or 'xxxxxxxxxxxx' format" errors << "Configured NIC MAC '#{opts[:mac]}' is not in 'xx:xx:xx:xx:xx:xx' or 'xxxxxxxxxxxx' format"
end end
end end
# only interested in public networks where portgroup is nil, as then source will be a host device
if type == :public_network && opts[:portgroup] == nil
if !host_devices.include?(opts[:dev])
errors << "network configuration #{index} for machine #{machine.name} is a public_network referencing host device '#{opts[:dev]}' which does not exist, consider adding ':dev => ....' referencing one of #{host_devices.join(", ")}"
end
end
end end
if !machine.provider_config.volume_cache.nil? and machine.provider_config.volume_cache != UNSET_VALUE if !machine.provider_config.volume_cache.nil? and machine.provider_config.volume_cache != UNSET_VALUE
@@ -1170,6 +1187,16 @@ module VagrantPlugins
@proxy_command = nil @proxy_command = nil
end end
end end
def host_devices
@host_devices ||= begin
require 'socket'
Socket.getifaddrs.map { |iface| iface.name }.uniq.select do |dev|
dev != "lo" && !@host_device_exclude_prefixes.any? { |exclude| dev.start_with?(exclude) }
end
end
end
end end
end end
end end

View File

@@ -630,6 +630,53 @@ describe VagrantPlugins::ProviderLibvirt::Config do
end end
end end
context 'with public_network defined' do
let(:host_devices) { [
instance_double(Socket::Ifaddr),
instance_double(Socket::Ifaddr),
] }
before do
machine.config.vm.network :public_network, dev: 'eth0', ip: "192.168.2.157"
expect(Socket).to receive(:getifaddrs).and_return(host_devices)
expect(host_devices[0]).to receive(:name).and_return('eth0')
expect(host_devices[1]).to receive(:name).and_return('virbr0')
end
it 'should validate use of existing device' do
assert_valid
end
context 'when default device not on host' do
before do
machine.config.vm.network :public_network, dev: 'eno1', ip: "192.168.2.157"
end
it 'should be invalid' do
assert_invalid
end
end
context 'when using excluded host device' do
before do
machine.config.vm.network :public_network, dev: 'virbr0', ip: "192.168.2.157"
end
it 'should be invalid' do
assert_invalid
end
context 'when user overrides to allow device' do
before do
subject.host_device_exclude_prefixes = []
end
it 'should validate' do
assert_valid
end
end
end
end
context 'with nvram defined' do context 'with nvram defined' do
before do before do
subject.nvram = '/path/to/some/nvram' subject.nvram = '/path/to/some/nvram'