mirror of
https://github.com/vagrant-libvirt/vagrant-libvirt.git
synced 2025-02-25 18:55:27 -06:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user