mirror of
https://github.com/vagrant-libvirt/vagrant-libvirt.git
synced 2025-02-25 18:55:27 -06:00
If the network does not have a bridge name, ignore it and move onto the next one. This allows for hostdev networks to exist without breaking. Includes some rudimentary testing to exercise the lookup code along with a small bit of refactoring based on the realisation that there is no need to lookup the network information twice as it is available if the list_all_networks API is used. Fixes: #599
207 lines
8.4 KiB
Ruby
207 lines
8.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'ipaddr'
|
|
require 'nokogiri'
|
|
require 'vagrant/util/network_ip'
|
|
|
|
class IPAddr
|
|
def get_mask
|
|
if @addr
|
|
_to_string(@mask_addr)
|
|
end
|
|
end
|
|
end
|
|
|
|
module VagrantPlugins
|
|
module ProviderLibvirt
|
|
module Util
|
|
module NetworkUtil
|
|
include Vagrant::Util::NetworkIP
|
|
|
|
def configured_networks(env, logger)
|
|
qemu_use_session = env[:machine].provider_config.qemu_use_session
|
|
qemu_use_agent = env[:machine].provider_config.qemu_use_agent
|
|
management_network_device = env[:machine].provider_config.management_network_device
|
|
management_network_name = env[:machine].provider_config.management_network_name
|
|
management_network_address = env[:machine].provider_config.management_network_address
|
|
management_network_mode = env[:machine].provider_config.management_network_mode
|
|
management_network_mac = env[:machine].provider_config.management_network_mac
|
|
management_network_guest_ipv6 = env[:machine].provider_config.management_network_guest_ipv6
|
|
management_network_autostart = env[:machine].provider_config.management_network_autostart
|
|
management_network_pci_bus = env[:machine].provider_config.management_network_pci_bus
|
|
management_network_pci_slot = env[:machine].provider_config.management_network_pci_slot
|
|
management_network_domain = env[:machine].provider_config.management_network_domain
|
|
management_network_mtu = env[:machine].provider_config.management_network_mtu
|
|
management_network_keep = env[:machine].provider_config.management_network_keep
|
|
logger.info "Using #{management_network_name} at #{management_network_address} as the management network #{management_network_mode} is the mode"
|
|
|
|
begin
|
|
management_network_ip = IPAddr.new(management_network_address)
|
|
rescue ArgumentError
|
|
raise Errors::ManagementNetworkError,
|
|
error_message: "#{management_network_address} is not a valid IP address"
|
|
end
|
|
|
|
# capture address into $1 and mask into $2
|
|
management_network_ip.inspect =~ /IPv4:(.*)\/(.*)>/
|
|
|
|
if Regexp.last_match(2) == '255.255.255.255'
|
|
raise Errors::ManagementNetworkError,
|
|
error_message: "#{management_network_address} does not include both an address and subnet mask"
|
|
end
|
|
|
|
if qemu_use_session
|
|
management_network_options = {
|
|
iface_type: :public_network,
|
|
dev: management_network_device,
|
|
mode: 'bridge',
|
|
type: 'bridge',
|
|
bus: management_network_pci_bus,
|
|
slot: management_network_pci_slot
|
|
}
|
|
else
|
|
management_network_options = {
|
|
iface_type: :private_network,
|
|
network_name: management_network_name,
|
|
ip: Regexp.last_match(1),
|
|
netmask: Regexp.last_match(2),
|
|
dhcp_enabled: true,
|
|
forward_mode: management_network_mode,
|
|
guest_ipv6: management_network_guest_ipv6,
|
|
autostart: management_network_autostart,
|
|
bus: management_network_pci_bus,
|
|
slot: management_network_pci_slot
|
|
}
|
|
end
|
|
|
|
|
|
|
|
unless management_network_mac.nil?
|
|
management_network_options[:mac] = management_network_mac
|
|
end
|
|
|
|
unless management_network_domain.nil?
|
|
management_network_options[:domain_name] = management_network_domain
|
|
end
|
|
|
|
unless management_network_mtu.nil?
|
|
management_network_options[:mtu] = management_network_mtu
|
|
end
|
|
|
|
unless management_network_pci_bus.nil? and management_network_pci_slot.nil?
|
|
management_network_options[:bus] = management_network_pci_bus
|
|
management_network_options[:slot] = management_network_pci_slot
|
|
end
|
|
|
|
if management_network_keep
|
|
management_network_options[:always_destroy] = false
|
|
end
|
|
|
|
# if there is a box and management network is disabled
|
|
# need qemu agent enabled and at least one network that can be accessed
|
|
if (
|
|
env[:machine].config.vm.box &&
|
|
!env[:machine].provider_config.mgmt_attach &&
|
|
!env[:machine].provider_config.qemu_use_agent &&
|
|
!env[:machine].config.vm.networks.any? { |type, _| ["private_network", "public_network"].include?(type.to_s) }
|
|
)
|
|
raise Errors::ManagementNetworkRequired
|
|
end
|
|
|
|
# add management network to list of networks to check
|
|
# unless mgmt_attach set to false
|
|
networks = if env[:machine].provider_config.mgmt_attach
|
|
[management_network_options]
|
|
else
|
|
[]
|
|
end
|
|
|
|
env[:machine].config.vm.networks.each do |type, original_options|
|
|
logger.debug "In config found network type #{type} options #{original_options}"
|
|
# Options can be specified in Vagrantfile in short format (:ip => ...),
|
|
# or provider format # (:libvirt__network_name => ...).
|
|
# https://github.com/mitchellh/vagrant/blob/main/lib/vagrant/util/scoped_hash_override.rb
|
|
options = scoped_hash_override(original_options, :libvirt)
|
|
# store type in options
|
|
# use default values if not already set
|
|
options = {
|
|
iface_type: type,
|
|
netmask: options[:network_address] ?
|
|
IPAddr.new(options[:network_address]).get_mask :
|
|
'255.255.255.0',
|
|
dhcp_enabled: true,
|
|
forward_mode: 'nat',
|
|
always_destroy: true
|
|
}.merge(options)
|
|
|
|
if options[:type].to_s == 'dhcp' && options[:ip].nil?
|
|
options[:network_name] = options[:network_name] ?
|
|
options[:network_name] :
|
|
'vagrant-private-dhcp'
|
|
end
|
|
|
|
# add to list of networks to check
|
|
networks.push(options)
|
|
end
|
|
|
|
networks
|
|
end
|
|
|
|
# Return a list of all (active and inactive) Libvirt networks as a list
|
|
# of hashes with their name, network address and status (active or not)
|
|
def libvirt_networks(libvirt_client)
|
|
libvirt_networks = []
|
|
|
|
# Iterate over all (active and inactive) networks.
|
|
libvirt_client.list_all_networks.each do |libvirt_network|
|
|
begin
|
|
bridge_name = libvirt_network.bridge_name
|
|
rescue Libvirt::Error
|
|
# there does not appear to be a mechanism to determine the type of network, only by
|
|
# querying the attribute and catching the error is it possible to ignore unsupported.
|
|
@logger.debug "Ignoring #{libvirt_network.name} as it does not support retrieval of bridge_name attribute"
|
|
next
|
|
end
|
|
|
|
# Parse ip address and netmask from the network xml description.
|
|
xml = Nokogiri::XML(libvirt_network.xml_desc)
|
|
ip = xml.xpath('/network/ip/@address').first
|
|
ip = ip.value if ip
|
|
netmask = xml.xpath('/network/ip/@netmask').first
|
|
netmask = netmask.value if netmask
|
|
|
|
dhcp_enabled = if xml.at_xpath('//network/ip/dhcp')
|
|
true
|
|
else
|
|
false
|
|
end
|
|
|
|
domain_name = xml.at_xpath('/network/domain/@name')
|
|
domain_name = domain_name.value if domain_name
|
|
|
|
# Calculate network address of network from ip address and
|
|
# netmask.
|
|
network_address = (network_address(ip, netmask) if ip && netmask)
|
|
|
|
libvirt_networks << {
|
|
name: libvirt_network.name,
|
|
ip_address: ip,
|
|
netmask: netmask,
|
|
network_address: network_address,
|
|
dhcp_enabled: dhcp_enabled,
|
|
bridge_name: bridge_name,
|
|
domain_name: domain_name,
|
|
created: true,
|
|
active: libvirt_network.active?,
|
|
autostart: libvirt_network.autostart?,
|
|
libvirt_network: libvirt_network
|
|
}
|
|
end
|
|
|
|
libvirt_networks
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|