mirror of
https://github.com/vagrant-libvirt/vagrant-libvirt.git
synced 2025-02-25 18:55:27 -06:00
Support setting iface name for target dev on private networks (#1692)
Allow for iface_name to be set on public_network configurations to control the name of the interface created by libvirt. This overrides the default that would be created automatically, but cannot use a reserved name as it will be ignored. Closes: #799
This commit is contained in:
@@ -494,9 +494,11 @@ starts with `libvirt__` string. Here is a list of those options:
|
||||
for for more information. *Note: takes either 'yes' or 'no' for value*
|
||||
* `:libvirt__ipv6_address` - Define ipv6 address, require also prefix.
|
||||
* `:libvirt__ipv6_prefix` - Define ipv6 prefix. generate string `<ip family="ipv6" address="address" prefix="prefix" >`
|
||||
* `:libvirt__iface_name` - Define a name for the private network interface.
|
||||
With this feature one can [simulate physical link
|
||||
failures](https://github.com/vagrant-libvirt/vagrant-libvirt/pull/498)
|
||||
* `:libvirt__iface_name` - Define a name for the corresponding network interface
|
||||
created on the host. With this feature one can [simulate physical link
|
||||
failures](https://github.com/vagrant-libvirt/vagrant-libvirt/pull/498). Note
|
||||
that you cannot use names reserved for libvirt's usage based on [documentation](
|
||||
https://libvirt.org/formatdomain.html#overriding-the-target-element).
|
||||
* `:mac` - MAC address for the interface. *Note: specify this in lowercase
|
||||
since Vagrant network scripts assume it will be!*
|
||||
* `:libvirt__mtu` - MTU size for the Libvirt network, if not defined, the
|
||||
@@ -542,6 +544,11 @@ virtual network.
|
||||
* `:trust_guest_rx_filters` - Support trustGuestRxFilters attribute. Details
|
||||
are listed [here](http://www.libvirt.org/formatdomain.html#elementsNICSDirect).
|
||||
Default is 'false'.
|
||||
* `:libvirt__iface_name` - Define a name for the corresponding network interface
|
||||
that is created on the host connected to the bridge dev. This can be used to
|
||||
help attach VLAN tags to specific VMs by adjusting the pattern to match. Note
|
||||
that you cannot use names reserved for libvirt's usage based on [documentation](
|
||||
https://libvirt.org/formatdomain.html#overriding-the-target-element).
|
||||
|
||||
Additionally for public networks, to facilitate validating if the device provided
|
||||
can be used, vagrant-libvirt will check both the host interfaces visible to libvirt
|
||||
|
||||
@@ -4,6 +4,9 @@ require 'log4r'
|
||||
require 'vagrant/util/network_ip'
|
||||
require 'vagrant/util/scoped_hash_override'
|
||||
|
||||
require 'vagrant-libvirt/util/erb_template'
|
||||
require 'vagrant-libvirt/util/network_util'
|
||||
|
||||
module VagrantPlugins
|
||||
module ProviderLibvirt
|
||||
module Action
|
||||
@@ -96,6 +99,7 @@ module VagrantPlugins
|
||||
@driver_iommu = iface_configuration.fetch(:driver_iommu, false )
|
||||
@driver_name = iface_configuration.fetch(:driver_name, false)
|
||||
@driver_queues = iface_configuration.fetch(:driver_queues, false)
|
||||
@device_name = iface_configuration.fetch(:iface_name, nil)
|
||||
@portgroup = iface_configuration.fetch(:portgroup, nil)
|
||||
@network_name = iface_configuration.fetch(:network_name, @network_name)
|
||||
template_name = 'public_interface'
|
||||
@@ -169,7 +173,7 @@ module VagrantPlugins
|
||||
@logger.debug {
|
||||
"Attaching Network Device with XML:\n#{xml}"
|
||||
}
|
||||
domain.attach_device(xml)
|
||||
env[:machine].provider.driver.attach_device(xml)
|
||||
rescue => e
|
||||
raise Errors::AttachDeviceError,
|
||||
error_message: e.message
|
||||
|
||||
@@ -1412,6 +1412,13 @@ module VagrantPlugins
|
||||
errors << "network configuration #{index} for machine #{machine.name} is a public_network referencing host device '#{hostdev}' which does not exist, consider adding ':dev => ....' referencing one of #{devices.join(", ")}"
|
||||
end
|
||||
end
|
||||
|
||||
unless network[:iface_name].nil?
|
||||
restricted_devnames = ['vnet', 'vif', 'macvtap', 'macvlan']
|
||||
if restricted_devnames.any? { |restricted| network[:iface_name].start_with?(restricted) }
|
||||
errors << "network configuration for machine #{machine.name} with setting :libvirt__iface_name => '#{network[:iface_name]}' starts with a restricted prefix according to libvirt docs https://libvirt.org/formatdomain.html#overriding-the-target-element, please use a device name that does not start with one of #{restricted_devnames.join(", ")}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
errors
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
<interface type='<%= @type %>'<% if @trust_guest_rx_filters %> trustGuestRxFilters='yes'<% end %>>
|
||||
<alias name='ua-net-<%= @iface_number %>'/>
|
||||
<% if @mac %>
|
||||
<%- if @mac %>
|
||||
<mac address='<%= @mac %>'/>
|
||||
<% end %>
|
||||
<%if @type == 'direct'%>
|
||||
<%- end %>
|
||||
<%- if @type == 'direct'%>
|
||||
<source dev='<%= @device %>' mode='<%= @mode %>'/>
|
||||
<% elsif !@portgroup.nil? %>
|
||||
<%- elsif !@portgroup.nil? %>
|
||||
<source network='<%=@network_name%>' portgroup='<%=@portgroup%>'/>
|
||||
<% else %>
|
||||
<%- else %>
|
||||
<source bridge='<%=@device%>'/>
|
||||
<% end %>
|
||||
<%- end %>
|
||||
<%- unless @device_name.nil? %>
|
||||
<target dev='<%= @device_name %>'/>
|
||||
<%- end %>
|
||||
<model type='<%=@model_type%>'/>
|
||||
<% if @driver_name and @driver_queues %>
|
||||
<%- if @driver_name and @driver_queues %>
|
||||
<driver <% if @driver_iommu %> iommu="on" <% end %> name='<%=@driver_name%>' queues='<%=@driver_queues%>'/>
|
||||
<% elsif @driver_queues %>
|
||||
<%- elsif @driver_queues %>
|
||||
<driver <% if @driver_iommu %> iommu="on" <% end %> queues='<%=@driver_queues%>'/>
|
||||
<% elsif @driver_name %>
|
||||
<%- elsif @driver_name %>
|
||||
<driver <% if @driver_iommu %> iommu="on" <% end %> name='<%=@driver_name%>'/>
|
||||
<% elsif @driver_iommu %>
|
||||
<%- elsif @driver_iommu %>
|
||||
<driver iommu='on' />
|
||||
<% end %>
|
||||
|
||||
<% if @ovs %>
|
||||
<%- end %>
|
||||
<%- if @ovs %>
|
||||
<virtualport type='openvswitch'>
|
||||
<% if @ovs_interfaceid %>
|
||||
<%- if @ovs_interfaceid %>
|
||||
<parameters interfaceid='<%=@ovs_interfaceid%>'/>
|
||||
<% end %>
|
||||
<%- end %>
|
||||
</virtualport>
|
||||
<% end %>
|
||||
<% if @pci_bus and @pci_slot %>
|
||||
<%- end %>
|
||||
<%- if @pci_bus and @pci_slot %>
|
||||
<address type='pci' bus='<%=@pci_bus%>' slot='<%=@pci_slot%>' />
|
||||
<% end %>
|
||||
<%- end %>
|
||||
</interface>
|
||||
|
||||
305
spec/unit/action/create_network_interfaces.rb
Normal file
305
spec/unit/action/create_network_interfaces.rb
Normal file
@@ -0,0 +1,305 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../spec_helper'
|
||||
|
||||
require 'vagrant-libvirt/errors'
|
||||
require 'vagrant-libvirt/action/create_network_interfaces'
|
||||
require 'vagrant-libvirt/util/unindent'
|
||||
|
||||
describe VagrantPlugins::ProviderLibvirt::Action::CreateNetworkInterfaces do
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
include_context 'unit'
|
||||
include_context 'libvirt'
|
||||
|
||||
let(:networks) { [
|
||||
instance_double(::Libvirt::Network),
|
||||
instance_double(::Libvirt::Network),
|
||||
] }
|
||||
let(:default_network_xml) {
|
||||
<<-EOF
|
||||
<network>
|
||||
<name>default</name>
|
||||
<uuid>e5f871eb-2899-48b2-83df-78aa43efa360</uuid>
|
||||
<forward mode='nat'>
|
||||
<nat>
|
||||
<port start='1024' end='65535'/>
|
||||
</nat>
|
||||
</forward>
|
||||
<bridge name='virbr0' stp='on' delay='0'/>
|
||||
<mac address='52:54:00:71:ce:a6'/>
|
||||
<ip address='192.168.122.1' netmask='255.255.255.0'>
|
||||
<dhcp>
|
||||
<range start='192.168.122.2' end='192.168.122.254'/>
|
||||
</dhcp>
|
||||
</ip>
|
||||
</network>
|
||||
EOF
|
||||
}
|
||||
let(:management_network_xml) {
|
||||
<<-EOF
|
||||
<network ipv6='yes'>
|
||||
<name>vagrant-libvirt</name>
|
||||
<uuid>46360938-0607-4168-a182-1352fac4a4f9</uuid>
|
||||
<forward mode='nat'/>
|
||||
<bridge name='virbr1' stp='on' delay='0'/>
|
||||
<mac address='52:54:00:c2:d5:a5'/>
|
||||
<ip address='192.168.121.1' netmask='255.255.255.0'>
|
||||
<dhcp>
|
||||
<range start='192.168.121.1' end='192.168.121.254'/>
|
||||
</dhcp>
|
||||
</ip>
|
||||
</network>
|
||||
EOF
|
||||
}
|
||||
let(:default_management_nic_xml) {
|
||||
<<-EOF.unindent
|
||||
<interface type="network">
|
||||
<alias name="ua-net-0"></alias>
|
||||
<source network="vagrant-libvirt"></source>
|
||||
<target dev="vnet0"></target>
|
||||
<model type="virtio"></model>
|
||||
<driver iommu="off"></driver>
|
||||
</interface>
|
||||
EOF
|
||||
}
|
||||
|
||||
before do
|
||||
allow(app).to receive(:call)
|
||||
allow(libvirt_client).to receive(:lookup_domain_by_uuid).and_return(libvirt_domain)
|
||||
|
||||
allow(driver).to receive(:list_all_networks).and_return(networks)
|
||||
|
||||
allow(networks[0]).to receive(:xml_desc).and_return(default_network_xml)
|
||||
allow(networks[0]).to receive(:name).and_return('default')
|
||||
allow(networks[0]).to receive(:bridge_name).and_return('virbr0')
|
||||
allow(networks[0]).to receive(:active?).and_return(true)
|
||||
allow(networks[0]).to receive(:autostart?).and_return(true)
|
||||
allow(networks[1]).to receive(:xml_desc).and_return(management_network_xml)
|
||||
allow(networks[1]).to receive(:name).and_return('vagrant-libvirt')
|
||||
allow(networks[1]).to receive(:bridge_name).and_return('virbr1')
|
||||
allow(networks[1]).to receive(:active?).and_return(true)
|
||||
allow(networks[1]).to receive(:autostart?).and_return(false)
|
||||
|
||||
allow(logger).to receive(:info)
|
||||
allow(logger).to receive(:debug)
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
it 'should inject the management network definition' do
|
||||
expect(driver).to receive(:attach_device).with(default_management_nic_xml)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
|
||||
context 'private network' do
|
||||
let(:vagrantfile) do
|
||||
<<-EOF
|
||||
Vagrant.configure('2') do |config|
|
||||
config.vm.box = "vagrant-libvirt/test"
|
||||
config.vm.define :test
|
||||
config.vm.provider :libvirt do |libvirt|
|
||||
#{vagrantfile_providerconfig}
|
||||
end
|
||||
|
||||
config.vm.network :private_network, :ip => "10.20.30.40"
|
||||
end
|
||||
EOF
|
||||
end
|
||||
let(:private_network) { instance_double(::Libvirt::Network) }
|
||||
let(:private_network_xml) {
|
||||
<<-EOF
|
||||
<network ipv6='yes'>
|
||||
<name>test1</name>
|
||||
<uuid>46360938-0607-4168-a182-1352fac4a4f9</uuid>
|
||||
<forward mode='nat'/>
|
||||
<bridge name='virbr2' stp='on' delay='0'/>
|
||||
<mac address='52:54:00:c2:d5:a5'/>
|
||||
<ip address='10.20.30.1' netmask='255.255.255.0'>
|
||||
<dhcp>
|
||||
<range start='10.20.30.1' end='10.20.30.254'/>
|
||||
</dhcp>
|
||||
</ip>
|
||||
</network>
|
||||
EOF
|
||||
}
|
||||
let(:private_nic_xml) {
|
||||
<<-EOF.unindent
|
||||
<interface type="network">
|
||||
<alias name="ua-net-1"></alias>
|
||||
<source network="test1"></source>
|
||||
<target dev="vnet1"></target>
|
||||
<model type="virtio"></model>
|
||||
<driver iommu="off"></driver>
|
||||
</interface>
|
||||
EOF
|
||||
}
|
||||
|
||||
before do
|
||||
allow(private_network).to receive(:xml_desc).and_return(private_network_xml)
|
||||
allow(private_network).to receive(:name).and_return('test1')
|
||||
allow(private_network).to receive(:bridge_name).and_return('virbr2')
|
||||
allow(private_network).to receive(:active?).and_return(true)
|
||||
allow(private_network).to receive(:autostart?).and_return(false)
|
||||
end
|
||||
|
||||
it 'should attach for two networks' do
|
||||
expect(driver).to receive(:list_all_networks).and_return(networks + [private_network])
|
||||
expect(driver).to receive(:attach_device).with(default_management_nic_xml)
|
||||
expect(driver).to receive(:attach_device).with(private_nic_xml)
|
||||
expect(guest).to receive(:capability).with(:configure_networks, any_args)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
|
||||
context 'when iface name is set' do
|
||||
let(:private_nic_xml) {
|
||||
<<-EOF.unindent
|
||||
<interface type="network">
|
||||
<alias name="ua-net-1"></alias>
|
||||
<source network="test1"></source>
|
||||
<target dev="myvnet0"></target>
|
||||
<model type="virtio"></model>
|
||||
<driver iommu="off"></driver>
|
||||
</interface>
|
||||
EOF
|
||||
}
|
||||
|
||||
before do
|
||||
machine.config.vm.networks[0][1][:libvirt__iface_name] = "myvnet0"
|
||||
end
|
||||
|
||||
it 'should set target appropriately' do
|
||||
expect(driver).to receive(:list_all_networks).and_return(networks + [private_network])
|
||||
expect(driver).to receive(:attach_device).with(default_management_nic_xml)
|
||||
expect(driver).to receive(:attach_device).with(private_nic_xml)
|
||||
expect(guest).to receive(:capability).with(:configure_networks, any_args)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it 'should skip configuring networks in guest without box' do
|
||||
machine.config.vm.box = nil
|
||||
|
||||
expect(driver).to receive(:list_all_networks).and_return(networks + [private_network])
|
||||
expect(driver).to receive(:attach_device).with(default_management_nic_xml)
|
||||
expect(driver).to receive(:attach_device).with(private_nic_xml)
|
||||
expect(guest).to_not receive(:capability).with(:configure_networks, any_args)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'public network' do
|
||||
let(:vagrantfile) do
|
||||
<<-EOF
|
||||
Vagrant.configure('2') do |config|
|
||||
config.vm.box = "vagrant-libvirt/test"
|
||||
config.vm.define :test
|
||||
config.vm.provider :libvirt do |libvirt|
|
||||
#{vagrantfile_providerconfig}
|
||||
end
|
||||
|
||||
config.vm.network :public_network, :dev => "virbr1", :mode => "bridge", :type => "bridge"
|
||||
end
|
||||
EOF
|
||||
end
|
||||
let(:public_network) { instance_double(::Libvirt::Network) }
|
||||
let(:public_network_xml) {
|
||||
<<-EOF
|
||||
<network ipv6='yes'>
|
||||
<name>test1</name>
|
||||
<uuid>46360938-0607-4168-a182-1352fac4a4f9</uuid>
|
||||
<forward mode='nat'/>
|
||||
<bridge name='virbr2' stp='on' delay='0'/>
|
||||
<mac address='52:54:00:c2:d5:a5'/>
|
||||
<ip address='10.20.30.1' netmask='255.255.255.0'>
|
||||
<dhcp>
|
||||
<range start='10.20.30.1' end='10.20.30.254'/>
|
||||
</dhcp>
|
||||
</ip>
|
||||
</network>
|
||||
EOF
|
||||
}
|
||||
let(:public_nic_xml) {
|
||||
<<-EOF.unindent
|
||||
<interface type='bridge'>
|
||||
<alias name='ua-net-1'/>
|
||||
<source bridge='virbr1'/>
|
||||
<model type='virtio'/>
|
||||
</interface>
|
||||
EOF
|
||||
}
|
||||
let(:domain_xml) {
|
||||
# don't need full domain here, just enough for the network element to work
|
||||
<<-EOF.unindent
|
||||
<domain type='qemu'>
|
||||
<devices>
|
||||
<interface type='network'>
|
||||
<alias name='ua-net-0'/>
|
||||
<mac address='52:54:00:7d:14:0e'/>
|
||||
<source network='vagrant-libvirt'/>
|
||||
<model type='virtio'/>
|
||||
<driver iommu='off'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
|
||||
</interface>
|
||||
<interface type='network'>
|
||||
<alias name='ua-net-1'/>
|
||||
<mac address='52:54:00:7d:14:0f'/>
|
||||
<source bridge='virbr1'/>
|
||||
<model type='virtio'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
|
||||
</interface>
|
||||
</devices>
|
||||
</domain>
|
||||
EOF
|
||||
}
|
||||
|
||||
before do
|
||||
allow(public_network).to receive(:xml_desc).and_return(public_network_xml)
|
||||
allow(public_network).to receive(:name).and_return('test1')
|
||||
allow(public_network).to receive(:bridge_name).and_return('virbr2')
|
||||
allow(public_network).to receive(:active?).and_return(true)
|
||||
allow(public_network).to receive(:autostart?).and_return(false)
|
||||
|
||||
allow(libvirt_domain).to receive(:xml_desc).and_return(domain_xml)
|
||||
end
|
||||
|
||||
it 'should attach for two networks' do
|
||||
expect(driver).to receive(:list_all_networks).and_return(networks + [public_network])
|
||||
expect(driver).to receive(:attach_device).with(default_management_nic_xml)
|
||||
expect(driver).to receive(:attach_device).with(public_nic_xml)
|
||||
expect(guest).to receive(:capability).with(:configure_networks, any_args)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
|
||||
context 'when iface name is set' do
|
||||
let(:public_nic_xml) {
|
||||
<<-EOF.unindent
|
||||
<interface type='bridge'>
|
||||
<alias name='ua-net-1'/>
|
||||
<source bridge='virbr1'/>
|
||||
<target dev='myvnet0'/>
|
||||
<model type='virtio'/>
|
||||
</interface>
|
||||
EOF
|
||||
}
|
||||
|
||||
before do
|
||||
machine.config.vm.networks[0][1][:libvirt__iface_name] = "myvnet0"
|
||||
end
|
||||
|
||||
it 'should set target appropriately' do
|
||||
expect(driver).to receive(:list_all_networks).and_return(networks + [public_network])
|
||||
expect(driver).to receive(:attach_device).with(default_management_nic_xml)
|
||||
expect(driver).to receive(:attach_device).with(public_nic_xml)
|
||||
expect(guest).to receive(:capability).with(:configure_networks, any_args)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -801,8 +801,9 @@ describe VagrantPlugins::ProviderLibvirt::Config do
|
||||
'virbr0',
|
||||
] }
|
||||
let(:driver) { instance_double(::VagrantPlugins::ProviderLibvirt::Driver) }
|
||||
let(:device_name) { 'eth0' }
|
||||
before do
|
||||
machine.config.vm.network :public_network, dev: 'eth0', ip: "192.168.2.157"
|
||||
machine.config.vm.network :public_network, dev: device_name, ip: "192.168.2.157"
|
||||
allow(machine.provider).to receive(:driver).and_return(driver)
|
||||
expect(driver).to receive(:host_devices).and_return(host_devices).at_least(:once).times
|
||||
end
|
||||
@@ -812,9 +813,7 @@ describe VagrantPlugins::ProviderLibvirt::Config do
|
||||
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
|
||||
let(:device_name) { 'eno1' }
|
||||
|
||||
it 'should be invalid' do
|
||||
assert_invalid
|
||||
@@ -822,9 +821,7 @@ describe VagrantPlugins::ProviderLibvirt::Config do
|
||||
end
|
||||
|
||||
context 'when using excluded host device' do
|
||||
before do
|
||||
machine.config.vm.network :public_network, dev: 'virbr0', ip: "192.168.2.157"
|
||||
end
|
||||
let(:device_name) { 'virbr0' }
|
||||
|
||||
it 'should be invalid' do
|
||||
assert_invalid
|
||||
@@ -840,6 +837,27 @@ describe VagrantPlugins::ProviderLibvirt::Config do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when setting iface_name' do
|
||||
let(:iface_name) { 'myvnet1' }
|
||||
|
||||
before do
|
||||
machine.config.vm.network :public_network, libvirt__iface_name: iface_name, ip: "192.168.2.157"
|
||||
end
|
||||
|
||||
it 'should valididate' do
|
||||
assert_valid
|
||||
end
|
||||
|
||||
context 'when set to reserved value' do
|
||||
let(:iface_name) { 'vnet1' }
|
||||
|
||||
it 'should be invalid' do
|
||||
errors = assert_invalid
|
||||
expect(errors).to include(match(/network configuration for machine test with setting :libvirt__iface_name => '#{iface_name}' starts/))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with nvram defined' do
|
||||
|
||||
Reference in New Issue
Block a user