Handle nic model type updating during start (#1747)

Start domain added some support to update the nic model type if it
changed to avoid needing to completely destroy and recreate the domain.
Additionally support for setting the management network nic model type
was added, however the default value did not correctly reflect expected.

This updates `management_network_model_type` to default to
`nic_model_type`, which in turn defaults to `virtio`. This has now been
moved from the create network interfaces action into the config object
to allow chained resolving. This should ensure that setting
`nic_model_type` will correctly cause all networks to use the model
unless explicitly specified to use a different model.

Additionally the start domain action for updating the interfaces has
been modified to loop over all interfaces and all configured adapters in
the order they should have been added. This allows for checking whether
the model type needs to be updated based on the
`management_network_model_type` config option for the first network,
assuming the management network has been attached, and otherwise to fall
back to the default from `nic_model_type` for all other interfaces.

Finally ensure the iommu attribute is removed from the nic driver if
the model type is switched to anything other virtio to avoid issues with
attempting to enable invalid settings.

Fixes: #1743
This commit is contained in:
Darragh Bailey
2023-06-20 15:46:05 +01:00
committed by GitHub
parent df1dd25e1e
commit 889b13d636
16 changed files with 549 additions and 110 deletions

View File

@@ -102,9 +102,7 @@ end
Note: for discard to work, you will likely also need to set `disk_bus = 'scsi'`
* `:detect_zeroes` - Controls whether to detect zero write requests. The value can be "off", "on" or "unmap".
* `address_type` - Address type of disk device to emulate. If unspecified, Libvirt uses a sensible default.
* `nic_model_type` - parameter specifies the model of the network adapter when
you create a domain value by default virtio KVM believe possible values, see
the [documentation for Libvirt](https://libvirt.org/formatdomain.html#setting-the-nic-model).
* `nic_model_type` - parameter specifies the model of the network adapter when you create a domain, default is 'virtio'. For possible values, see the [documentation for Libvirt](https://libvirt.org/formatdomain.html#setting-the-nic-model).
* `shares` - Proportional weighted share for the domain relative to others. For more details see [documentation](https://libvirt.org/formatdomain.html#cpu-tuning).
* `memory` - Amount of memory in MBytes. Defaults to 512 if not set.
* `cpus` - Number of virtual cpus. Defaults to 1 if not set.
@@ -498,12 +496,12 @@ starts with `libvirt__` string. Here is a list of those options:
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
* `:libvirt__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
created network will use the Libvirt default (1500). VMs still need to set the
MTU accordingly.
* `:model_type` - parameter specifies the model of the network adapter when you
* `:libvirt__model_type` - parameter specifies the model of the network adapter when you
create a domain value by default virtio KVM believe possible values, see the
documentation for Libvirt
* `:libvirt__driver_name` - Define which network driver to use. [More
@@ -513,8 +511,8 @@ starts with `libvirt__` string. Here is a list of those options:
info](http://www.linux-kvm.org/page/Multiqueue)
* `:autostart` - Automatic startup of network by the Libvirt daemon.
If not specified the default is 'false'.
* `:bus` - The bus of the PCI device. Both :bus and :slot have to be defined.
* `:slot` - The slot of the PCI device. Both :bus and :slot have to be defined.
* `:libvirt__bus` - The bus of the PCI device. Both :bus and :slot have to be defined.
* `:libvirt__slot` - The slot of the PCI device. Both :bus and :slot have to be defined.
* `:libvirt__always_destroy` - Allow domains that use but did not create a
network to destroy it when the domain is destroyed (default: `true`). Set to
`false` to only allow the domain that created the network to destroy it.
@@ -592,7 +590,7 @@ used by this network are configurable at the provider level.
* `management_network_keep` - Starting from version *0.7.0*, *always_destroy* is set to *true* by default for any network.
This option allows to change this behaviour for the management network.
* `management_network_iface_name` - Allow controlling of the network device name that appears on the host for the management network, same as `:libvirt__iface_name` for public and private network definitions. (unreleased).
* `management_network_model_type` - Model of the network adapter to use for the management interface. Default is 'virtio'.
* `management_network_model_type` - Model of the network adapter to use for the management interface. Default is `nic_model_type`, which in turn defaults to 'virtio'.
You may wonder how vagrant-libvirt knows the IP address a VM received. Libvirt
doesn't provide a standard way to find out the IP address of a running domain.

View File

@@ -1,8 +1,6 @@
# frozen_string_literal: true
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'
@@ -15,15 +13,12 @@ module VagrantPlugins
class CreateNetworkInterfaces
include VagrantPlugins::ProviderLibvirt::Util::ErbTemplate
include VagrantPlugins::ProviderLibvirt::Util::NetworkUtil
include Vagrant::Util::NetworkIP
include Vagrant::Util::ScopedHashOverride
def initialize(app, env)
@logger = Log4r::Logger.new('vagrant_libvirt::action::create_network_interfaces')
@management_network_name = env[:machine].provider_config.management_network_name
config = env[:machine].provider_config
@nic_model_type = config.nic_model_type || 'virtio'
@nic_adapter_count = config.nic_adapter_count
@nic_model_type = config.nic_model_type
@app = app
end
@@ -39,34 +34,7 @@ module VagrantPlugins
end
# Setup list of interfaces before creating them.
adapters = []
# Vagrant gives you adapter 0 by default
# Assign interfaces to slots.
configured_networks(env[:machine], @logger).each do |options|
# don't need to create interface for this type
next if options[:iface_type] == :forwarded_port
# TODO: fill first ifaces with adapter option specified.
if options[:adapter]
if adapters[options[:adapter]]
raise Errors::InterfaceSlotNotAvailable
end
free_slot = options[:adapter].to_i
@logger.debug "Using specified adapter slot #{free_slot}"
else
free_slot = find_empty(adapters)
@logger.debug "Adapter not specified so found slot #{free_slot}"
raise Errors::InterfaceSlotExhausted if free_slot.nil?
end
# We have slot for interface, fill it with interface configuration.
adapters[free_slot] = options
adapters[free_slot][:network_name] = interface_network(
env[:machine].provider.driver, adapters[free_slot]
)
end
adapters = network_interfaces(env[:machine], @logger)
# Create each interface as new domain device.
@macs_per_network = Hash.new(0)
@@ -286,41 +254,6 @@ module VagrantPlugins
Nokogiri::XML::Node::SaveOptions::FORMAT
)
end
def find_empty(array, start = 0, stop = @nic_adapter_count)
(start..stop).each do |i|
return i unless array[i]
end
nil
end
# Return network name according to interface options.
def interface_network(driver, options)
# no need to get interface network for tcp tunnel config
return 'tunnel_interface' if options.fetch(:tunnel_type, nil)
if options[:network_name]
@logger.debug 'Found network by name'
return options[:network_name]
end
# Get list of all (active and inactive) Libvirt networks.
available_networks = libvirt_networks(driver)
return 'public' if options[:iface_type] == :public_network
if options[:ip]
address = network_address(options[:ip], options[:netmask])
available_networks.each do |network|
if address == network[:network_address]
@logger.debug 'Found network by ip'
return network[:name]
end
end
end
raise Errors::NetworkNotAvailableError, network_name: options[:ip]
end
end
end
end

View File

@@ -6,6 +6,7 @@ require 'rexml/document'
require 'rexml/formatters/pretty'
require 'rexml/xpath'
require 'vagrant-libvirt/util/network_util'
require 'vagrant-libvirt/util/xml'
module VagrantPlugins
@@ -13,9 +14,11 @@ module VagrantPlugins
module Action
# Just start the domain.
class StartDomain
include VagrantPlugins::ProviderLibvirt::Util::NetworkUtil
def initialize(app, _env)
def initialize(app, env)
@logger = Log4r::Logger.new('vagrant_libvirt::action::start_domain')
config = env[:machine].provider_config
@app = app
end
@@ -68,14 +71,44 @@ module VagrantPlugins
end
# Interface type
unless config.nic_model_type.nil?
REXML::XPath.each(xml_descr, '/domain/devices/interface/model') do |iface_model|
if iface_model.attributes['type'] != config.nic_model_type
@logger.debug "network type updated from '#{iface_model.attributes['type']}' to '#{config.nic_model_type}'"
adapters = network_interfaces(env[:machine], @logger)
index = 0
REXML::XPath.each(xml_descr, '/domain/devices/interface') do |iface|
# initial config defaults
nic_model_type = index == 0 && config.mgmt_attach ? config.management_network_model_type : config.nic_model_type
driver_iommu = index == 0 && config.mgmt_attach ? config.management_network_driver_iommu : false
# resolve per adapter option
if index < adapters.length
nic_model_type = adapters[index].fetch(:model_type, nic_model_type)
driver_iommu = adapters[index].fetch(:driver_iommu, driver_iommu )
end
iface_model = iface.elements['model']
if iface_model.attributes['type'] != nic_model_type
@logger.debug "network type updated from '#{iface_model.attributes['type']}' to '#{nic_model_type}'"
descr_changed = true
iface_model.attributes['type'] = nic_model_type
end
iface_driver = iface.elements['driver'] || REXML::Element.new('driver', iface)
if nic_model_type == 'virtio'
iommu = driver_iommu ? 'on': 'off'
if !iface_driver.attributes['iommu'].nil? && !driver_iommu.nil? && iface_driver.attributes['iommu'] != iommu
descr_changed = true
iface_model.attributes['type'] = config.nic_model_type
iface_driver.attributes['iommu'] = iommu
end
else
if !iface_driver.nil?
descr_changed = true if iface_driver.attributes['iommu']
iface_driver.attributes.delete('iommu')
end
end
iface.delete_element(iface_driver) if iface_driver.attributes.empty?
index += 1
end
if adapters.length != index
env[:ui].warn("number of network adapters in current config (#{adapters.length}) is different to attached interfaces (#{index}), may have incorrectly updated")
end
# vCpu count

View File

@@ -962,21 +962,6 @@ module VagrantPlugins
@snapshot_pool_name = @storage_pool_name if @snapshot_pool_name == UNSET_VALUE
@storage_pool_path = nil if @storage_pool_path == UNSET_VALUE
@random_hostname = false if @random_hostname == UNSET_VALUE
@management_network_device = 'virbr0' if @management_network_device == UNSET_VALUE
@management_network_name = 'vagrant-libvirt' if @management_network_name == UNSET_VALUE
@management_network_address = '192.168.121.0/24' if @management_network_address == UNSET_VALUE
@management_network_mode = 'nat' if @management_network_mode == UNSET_VALUE
@management_network_mac = nil if @management_network_mac == UNSET_VALUE
@management_network_guest_ipv6 = 'yes' if @management_network_guest_ipv6 == UNSET_VALUE
@management_network_autostart = false if @management_network_autostart == UNSET_VALUE
@management_network_pci_bus = nil if @management_network_pci_bus == UNSET_VALUE
@management_network_pci_slot = nil if @management_network_pci_slot == UNSET_VALUE
@management_network_domain = nil if @management_network_domain == UNSET_VALUE
@management_network_mtu = nil if @management_network_mtu == UNSET_VALUE
@management_network_keep = false if @management_network_keep == UNSET_VALUE
@management_network_driver_iommu = false if @management_network_driver_iommu == UNSET_VALUE
@management_network_iface_name = nil if @management_network_iface_name == UNSET_VALUE
@management_network_model_type = 'virtio' if @management_network_model_type == UNSET_VALUE
# Domain specific settings.
@title = '' if @title == UNSET_VALUE
@@ -1035,7 +1020,7 @@ module VagrantPlugins
end
@disk_address_type = nil if @disk_address_type == UNSET_VALUE
@disk_driver_opts = {} if @disk_driver_opts == UNSET_VALUE
@nic_model_type = nil if @nic_model_type == UNSET_VALUE
@nic_model_type = 'virtio' if @nic_model_type == UNSET_VALUE
@nested = false if @nested == UNSET_VALUE
@volume_cache = nil if @volume_cache == UNSET_VALUE
@kernel = nil if @kernel == UNSET_VALUE
@@ -1150,6 +1135,23 @@ module VagrantPlugins
@serials = [{:type => 'pty', :source => nil}] if @serials == UNSET_VALUE
# management network options
@management_network_device = 'virbr0' if @management_network_device == UNSET_VALUE
@management_network_name = 'vagrant-libvirt' if @management_network_name == UNSET_VALUE
@management_network_address = '192.168.121.0/24' if @management_network_address == UNSET_VALUE
@management_network_mode = 'nat' if @management_network_mode == UNSET_VALUE
@management_network_mac = nil if @management_network_mac == UNSET_VALUE
@management_network_guest_ipv6 = 'yes' if @management_network_guest_ipv6 == UNSET_VALUE
@management_network_autostart = false if @management_network_autostart == UNSET_VALUE
@management_network_pci_bus = nil if @management_network_pci_bus == UNSET_VALUE
@management_network_pci_slot = nil if @management_network_pci_slot == UNSET_VALUE
@management_network_domain = nil if @management_network_domain == UNSET_VALUE
@management_network_mtu = nil if @management_network_mtu == UNSET_VALUE
@management_network_keep = false if @management_network_keep == UNSET_VALUE
@management_network_driver_iommu = false if @management_network_driver_iommu == UNSET_VALUE
@management_network_iface_name = nil if @management_network_iface_name == UNSET_VALUE
@management_network_model_type = @nic_model_type if @management_network_model_type == UNSET_VALUE
@host_device_exclude_prefixes = ['docker', 'macvtap', 'virbr', 'vnet'] if @host_device_exclude_prefixes == UNSET_VALUE
end

View File

@@ -3,6 +3,7 @@
require 'ipaddr'
require 'nokogiri'
require 'vagrant/util/network_ip'
require 'vagrant/util/scoped_hash_override'
class IPAddr
def get_mask
@@ -17,6 +18,39 @@ module VagrantPlugins
module Util
module NetworkUtil
include Vagrant::Util::NetworkIP
include Vagrant::Util::ScopedHashOverride
def network_interfaces(machine, logger)
# Setup list of interfaces before creating them.
adapters = []
# Vagrant gives you adapter 0 by default
# Assign interfaces to slots.
configured_networks(machine, logger).each do |options|
# don't need to create interface for this type
next if options[:iface_type] == :forwarded_port
# TODO: fill first ifaces with adapter option specified.
if options[:adapter]
if adapters[options[:adapter]]
raise Errors::InterfaceSlotNotAvailable
end
free_slot = options[:adapter].to_i
@logger.debug "Using specified adapter slot #{free_slot}"
else
free_slot = find_empty(adapters, 0, machine.provider_config.nic_adapter_count)
@logger.debug "Adapter not specified so found slot #{free_slot}"
raise Errors::InterfaceSlotExhausted if free_slot.nil?
end
# We have slot for interface, fill it with interface configuration.
adapters[free_slot] = options
adapters[free_slot][:network_name] = interface_network(machine.provider.driver, adapters[free_slot])
end
adapters
end
def configured_networks(machine, logger)
qemu_use_session = machine.provider_config.qemu_use_session
@@ -198,6 +232,41 @@ module VagrantPlugins
libvirt_networks
end
def find_empty(array, start, stop)
(start..stop).each do |i|
return i unless array[i]
end
nil
end
# Return network name according to interface options.
def interface_network(driver, options)
# no need to get interface network for tcp tunnel config
return 'tunnel_interface' if options.fetch(:tunnel_type, nil)
if options[:network_name]
@logger.debug 'Found network by name'
return options[:network_name]
end
# Get list of all (active and inactive) Libvirt networks.
available_networks = libvirt_networks(driver)
return 'public' if options[:iface_type] == :public_network
if options[:ip]
address = network_address(options[:ip], options[:netmask])
available_networks.each do |network|
if address == network[:network_address]
@logger.debug 'Found network by ip'
return network[:name]
end
end
end
raise Errors::NetworkNotAvailableError, network_name: options[:ip]
end
end
end
end

View File

@@ -162,6 +162,109 @@ describe VagrantPlugins::ProviderLibvirt::Action::StartDomain do
end
end
context 'interface' do
let(:test_file) { 'existing_with_iommu.xml' }
let(:updated_domain_xml) {
new_xml = domain_xml.dup
new_xml.sub!(
/<model type='virtio'\/>\s+<driver iommu='on'\/>/m,
<<-EOF
<model type='e1000'/>
EOF
)
new_xml
}
let(:vagrantfile_providerconfig) {
<<-EOF
libvirt.management_network_model_type = 'e1000'
EOF
}
it 'should remove iommu if not interface model not virtio' do
expect(ui).to_not receive(:warn)
expect(connection).to receive(:define_domain).and_return(libvirt_domain)
expect(libvirt_domain).to receive(:xml_desc).and_return(domain_xml, updated_domain_xml)
expect(libvirt_domain).to receive(:autostart=)
expect(domain).to receive(:start)
expect(subject.call(env)).to be_nil
end
context 'iommu mismatch' do
let(:updated_domain_xml) {
new_xml = domain_xml.dup
new_xml.sub!(/(<model type='virtio'\/>\s+)<driver iommu='on'\/>/m) { |_|
match = Regexp.last_match
"#{match[1]}<driver iommu='off'/>"
}
new_xml
}
let(:vagrantfile_providerconfig) {
<<-EOF
libvirt.management_network_driver_iommu = false
EOF
}
it 'should update iommu to off' do
expect(ui).to_not receive(:warn)
expect(connection).to receive(:define_domain).and_return(libvirt_domain)
expect(libvirt_domain).to receive(:xml_desc).and_return(domain_xml, updated_domain_xml)
expect(libvirt_domain).to receive(:autostart=)
expect(domain).to receive(:start)
expect(subject.call(env)).to be_nil
end
end
context 'with additional interface' do
let(:test_file) { 'existing_with_two_interfaces_iommu.xml' }
let(:adapters) {
[
{:iface_type => :private_network, :model_type => "e1000", :network_name => "vagrant-libvirt", :driver_iommu => false},
{:iface_type => :private_network, :model_type => "virtio", :network_name => "vagrant-libvirt-1", :driver_iommu => true},
]
}
before do
allow(subject).to receive(:network_interfaces).and_return(adapters)
end
it 'should only update the management interface' do
expect(updated_domain_xml).to match(/<source network='vagrant-libvirt'\/>\s+<model type='e1000'\/>/m)
expect(updated_domain_xml).to match(/<source network='private'\/>\s+<model type='virtio'\/>/m)
expect(ui).to_not receive(:warn)
expect(connection).to receive(:define_domain).and_return(libvirt_domain)
expect(libvirt_domain).to receive(:xml_desc).and_return(domain_xml, updated_domain_xml)
expect(libvirt_domain).to receive(:autostart=)
expect(domain).to receive(:start)
expect(subject.call(env)).to be_nil
end
context 'with more adapters configured than attached' do
let(:adapters) {
[
{:iface_type => :private_network, :model_type => "e1000", :network_name => "vagrant-libvirt", :driver_iommu => false},
{:iface_type => :private_network, :model_type => "virtio", :network_name => "vagrant-libvirt-1", :driver_iommu => true},
{:iface_type => :private_network, :model_type => "virtio", :network_name => "vagrant-libvirt-2", :driver_iommu => true},
]
}
it 'should update and trigger a warning about mismatched adapters' do
expect(ui).to receive(:warn).with(/number of network adapters in current config \(3\) is different to attached interfaces \(2\)/)
expect(connection).to receive(:define_domain).and_return(libvirt_domain)
expect(libvirt_domain).to receive(:xml_desc).and_return(domain_xml, updated_domain_xml)
expect(libvirt_domain).to receive(:autostart=)
expect(domain).to receive(:start)
expect(subject.call(env)).to be_nil
end
end
end
end
context 'cpu' do
let(:test_file) { 'existing.xml' }
let(:updated_domain_xml) {

View File

@@ -23,6 +23,12 @@
</clock>
<devices>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>

View File

@@ -23,6 +23,12 @@
<timer name='rtc'/>
</clock>
<devices>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>

View File

@@ -24,6 +24,12 @@
<timer name='tsc'/>
</clock>
<devices>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>

View File

@@ -21,6 +21,12 @@
</features>
<clock offset='utc'/>
<devices>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>

View File

@@ -21,6 +21,12 @@
</features>
<clock offset='utc'/>
<devices>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<address bus='0x00' domain='0x0000' function='0x0' slot='0x05' type='pci'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>

View File

@@ -21,6 +21,12 @@
</features>
<clock offset='utc'/>
<devices>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<address bus='0x00' domain='0x0000' function='0x0' slot='0x05' type='pci'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>

View File

@@ -22,6 +22,12 @@
</features>
<clock offset='utc'/>
<devices>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>

View File

@@ -0,0 +1,64 @@
<domain type='qemu'>
<name>vagrant-libvirt_default</name>
<uuid>881a931b-0110-4d10-81aa-47a1a19f5726</uuid>
<description>Source: /home/test/vagrant-libvirt/Vagrantfile</description>
<memory unit='KiB'>2097152</memory>
<currentMemory unit='KiB'>2097152</currentMemory>
<vcpu placement='static'>2</vcpu>
<os>
<type arch='x86_64' machine='pc-i440fx-6.0'>hvm</type>
<bootmenu enable='no'/>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<cpu mode='host-model' check='partial'/>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/vagrant-libvirt_default.img'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</disk>
<controller type='usb' index='0' model='piix3-uhci'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pci-root'/>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<driver iommu='on'/>
<address bus='0x00' domain='0x0000' function='0x0' slot='0x05' type='pci'/>
</interface>
<serial type='pty'>
<target type='isa-serial' port='0'>
<model name='isa-serial'/>
</target>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us' websocket='-1'>
<listen type='address' address='127.0.0.1'/>
</graphics>
<audio id='1' type='none'/>
<video>
<model type='cirrus' vram='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</memballoon>
</devices>
</domain>

View File

@@ -0,0 +1,71 @@
<domain type='qemu'>
<name>vagrant-libvirt_default</name>
<uuid>881a931b-0110-4d10-81aa-47a1a19f5726</uuid>
<description>Source: /home/test/vagrant-libvirt/Vagrantfile</description>
<memory unit='KiB'>2097152</memory>
<currentMemory unit='KiB'>2097152</currentMemory>
<vcpu placement='static'>2</vcpu>
<os>
<type arch='x86_64' machine='pc-i440fx-6.0'>hvm</type>
<bootmenu enable='no'/>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<cpu mode='host-model' check='partial'/>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/vagrant-libvirt_default.img'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</disk>
<controller type='usb' index='0' model='piix3-uhci'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pci-root'/>
<interface type='network'>
<alias name='ua-net-0'/>
<source network='vagrant-libvirt'/>
<model type='virtio'/>
<driver iommu='on'/>
<address bus='0x00' domain='0x0000' function='0x0' slot='0x05' type='pci'/>
</interface>
<interface type='network'>
<alias name='ua-net-1'/>
<source network='private'/>
<model type='virtio'/>
<driver iommu='on'/>
<address bus='0x00' domain='0x0000' function='0x0' slot='0x06' type='pci'/>
</interface>
<serial type='pty'>
<target type='isa-serial' port='0'>
<model name='isa-serial'/>
</target>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us' websocket='-1'>
<listen type='address' address='127.0.0.1'/>
</graphics>
<audio id='1' type='none'/>
<video>
<model type='cirrus' vram='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</memballoon>
</devices>
</domain>

View File

@@ -8,28 +8,29 @@ describe 'VagrantPlugins::ProviderLibvirt::Util::NetworkUtil' do
include_context 'libvirt'
subject do
Class.new {
Class.new do
include VagrantPlugins::ProviderLibvirt::Util::NetworkUtil
def initialize
@logger = Log4r::Logger.new('test-logger')
end
}.new
end.new
end
def create_libvirt_network(name, attrs={})
def create_libvirt_network(name, attrs = {})
default_attrs = {
:active? => true,
:autostart? => true,
active?: true,
autostart?: true
}
network_xml = File.read(File.join(File.dirname(__FILE__), File.basename(__FILE__, '.rb'), name + '.xml'))
network_xml = File.read(File.join(File.dirname(__FILE__), File.basename(__FILE__, '.rb'), "#{name}.xml"))
double = instance_double(::Libvirt::Network)
allow(double).to receive(:xml_desc).and_return(network_xml)
allow(double).to receive(:name).and_return(name)
xml = REXML::Document.new(network_xml)
bridge = REXML::XPath.first(xml, '/network/bridge')
default_attrs[:bridge_name] = !bridge.nil? ? bridge.attributes['name'] : Libvirt::Error.new("network #{name} does not have attribute bridge_name")
default_attrs[:bridge_name] =
!bridge.nil? ? bridge.attributes['name'] : Libvirt::Error.new("network #{name} does not have attribute bridge_name")
default_attrs.merge(attrs).each do |aname, avalue|
if avalue.is_a?(Exception)
@@ -50,10 +51,133 @@ describe 'VagrantPlugins::ProviderLibvirt::Util::NetworkUtil' do
expect(logger).to_not receive(:debug)
expect(driver).to receive(:list_all_networks).and_return([default_network, additional_network])
expect(subject.libvirt_networks(driver)).to match_array([
hash_including(:name => 'default'),
hash_including(:name => 'vagrant-libvirt'),
])
expect(subject.libvirt_networks(driver)).to match_array(
[
hash_including(name: 'default'),
hash_including(name: 'vagrant-libvirt')
]
)
end
end
describe '#network_interfaces' do
let(:configured_networks_all) do
[
{
iface_type: :private_network,
ip: '192.168.121.0',
netmask: '255.255.255.0',
network_name: 'vagrant-libvirt',
},
{
auto_correct: true,
iface_type: :forwarded_port,
},
{
iface_type: :private_network,
ip: '192.168.123.0',
netmask: '255.255.255.0',
network_name: 'vagrant-libvirt-1',
},
{
iface_type: :private_network,
ip: '192.168.124.0',
netmask: '255.255.255.0',
network_name: 'vagrant-libvirt-2',
},
]
end
let(:configured_networks) do
[
configured_networks_all[0]
]
end
before do
expect(subject).to receive(:configured_networks).with(machine, logger).and_return(configured_networks)
end
it 'should return a list of default adapters configured' do
expect(logger).to receive(:debug).with('Adapter not specified so found slot 0')
expect(logger).to receive(:debug).with('Found network by name')
expect(subject.network_interfaces(machine, logger)).to match_array([configured_networks[0]])
end
context 'with forwarded ports' do
let(:configured_networks) do
[
configured_networks_all[0],
configured_networks_all[1]
]
end
it 'should skip the forwarded port' do
expect(logger).to receive(:debug).with('Adapter not specified so found slot 0')
expect(logger).to receive(:debug).with('Found network by name')
expect(subject.network_interfaces(machine, logger)).to match_array([configured_networks[0]])
end
end
context 'with 2 additional private networks with adapter set' do
let(:configured_networks) do
[
configured_networks_all[0],
configured_networks_all[2].merge(:adapter => 2),
configured_networks_all[3],
]
end
it 'should return the first private network last' do
expect(logger).to receive(:debug).with('Adapter not specified so found slot 0')
expect(logger).to receive(:debug).with('Found network by name').exactly(3).times
expect(logger).to receive(:debug).with('Using specified adapter slot 2')
expect(logger).to receive(:debug).with('Adapter not specified so found slot 1')
expect(subject.network_interfaces(machine, logger)).to match_array(
[
configured_networks[0],
configured_networks[2],
configured_networks[1]
]
)
end
end
end
describe '#configured_networks' do
it 'should return a list of default adapters configured' do
expect(logger).to receive(:info).with('Using vagrant-libvirt at 192.168.121.0/24 as the management network nat is the mode')
expect(logger).to receive(:debug).with(/In config found network type forwarded_port options/)
expect(subject.configured_networks(machine, logger)).to match_array(
[
hash_including(
{
forward_mode: 'nat',
iface_type: :private_network,
ip: '192.168.121.0',
model_type: 'virtio',
netmask: '255.255.255.0',
network_name: 'vagrant-libvirt',
}
),
hash_including(
{
auto_correct: true,
forward_mode: 'nat',
guest: 22,
host: 2222,
host_ip: '127.0.0.1',
id: 'ssh',
iface_type: :forwarded_port,
netmask: '255.255.255.0',
protocol: 'tcp',
}
)
]
)
end
end
end