diff --git a/plugins/guests/fedora/cap/configure_networks.rb b/plugins/guests/fedora/cap/configure_networks.rb index e4a7e1f19..9305b34b0 100644 --- a/plugins/guests/fedora/cap/configure_networks.rb +++ b/plugins/guests/fedora/cap/configure_networks.rb @@ -1,4 +1,3 @@ -require "set" require "tempfile" require_relative "../../../../lib/vagrant/util/retryable" @@ -12,122 +11,52 @@ module VagrantPlugins include Vagrant::Util def self.configure_networks(machine, networks) - network_scripts_dir = machine.guest.capability("network_scripts_dir") + comm = machine.communicate - virtual = false - interface_names = Array.new - interface_names_by_slot = Array.new - machine.communicate.sudo("/usr/sbin/biosdevname &>/dev/null; echo $?") do |_, result| - # The above command returns: - # - '4' if /usr/sbin/biosdevname detects it is running in a virtual machine - # - '127' if /usr/sbin/biosdevname doesn't exist - virtual = true if ['4', '127'].include? result.chomp + network_scripts_dir = machine.guest.capability(:network_scripts_dir) + + interfaces = [] + commands = [] + + comm.sudo("/sbin/ip -o -0 addr | grep -v LOOPBACK | awk '{print $2}' | sed 's/://'") do |_, stdout| + interfaces = stdout.split("\n") end - if virtual - machine.communicate.sudo("ls -v /sys/class/net | egrep -v lo\\|docker") do |_, result| - interface_names = result.split("\n") - end + networks.each.with_index do |network, i| + network[:device] = interfaces[network[:interface]] - interface_names_by_slot = networks.map do |network| - "#{interface_names[network[:interface]]}" - end - else - machine.communicate.sudo("/usr/sbin/biosdevname -d | grep Kernel | cut -f2 -d: | sed -e 's/ //;'") do |_, result| - interface_names = result.split("\n") - end - - interface_name_pairs = Array.new - interface_names.each do |interface_name| - machine.communicate.sudo("/usr/sbin/biosdevname --policy=all_ethN -i #{interface_name}") do |_, result| - interface_name_pairs.push([interface_name, result.gsub("\n", "")]) - end - end - - setting_interface_names = networks.map do |network| - "eth#{network[:interface]}" - end - - interface_names_by_slot = interface_names.dup - interface_name_pairs.each do |interface_name, previous_interface_name| - if setting_interface_names.index(previous_interface_name) == nil - interface_names_by_slot.delete(interface_name) - end - end - end - - # Read interface MAC addresses for later matching - mac_addresses = Array.new(interface_names.length) - interface_names.each_with_index do |ifname, index| - machine.communicate.sudo("cat /sys/class/net/#{ifname}/address") do |_, result| - mac_addresses[index] = result.strip - end - end - - # Accumulate the configurations to add to the interfaces file as well - # as what interfaces we're actually configuring since we use that later. - interfaces = Set.new - networks.each do |network| - interface = nil - if network[:mac_address] - found_idx = mac_addresses.find_index(network[:mac_address]) - # Ignore network if requested MAC address could not be found - next if found_idx.nil? - interface = interface_names[found_idx] - else - ifname_by_slot = interface_names_by_slot[network[:interface]-1] - # Don't overwrite if interface was already matched via MAC address - next if interfaces.include?(ifname_by_slot) - interface = ifname_by_slot - end - - interfaces.add(interface) - network[:device] = interface - - # Remove any previous vagrant configuration in this network - # interface's configuration files. - machine.communicate.sudo("touch #{network_scripts_dir}/ifcfg-#{interface}") - machine.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' #{network_scripts_dir}/ifcfg-#{interface} > /tmp/vagrant-ifcfg-#{interface}") - machine.communicate.sudo("cat /tmp/vagrant-ifcfg-#{interface} > #{network_scripts_dir}/ifcfg-#{interface}") - machine.communicate.sudo("rm -f /tmp/vagrant-ifcfg-#{interface}") - - # Render and upload the network entry file to a deterministic - # temporary location. + # Render a new configuration entry = TemplateRenderer.render("guests/fedora/network_#{network[:type]}", - options: network) + options: network, + ) + # Upload the new configuration + remote_path = "/tmp/vagrant-network-entry-#{network[:device]}-#{Time.now.to_i}-#{i}" Tempfile.open("vagrant-fedora-configure-networks") do |f| f.binmode f.write(entry) f.fsync f.close - machine.communicate.upload(f.path, "/tmp/vagrant-network-entry_#{interface}") + machine.communicate.upload(f.path, remote_path) end + + # Add the new interface and bring it back up + final_path = "#{network_scripts_dir}/ifcfg-#{network[:device]}" + commands << <<-EOH.gsub(/^ {14}/, '') + # Down the interface before munging the config file. This might + # fail if the interface is not actually set up yet so ignore + # errors. + /sbin/ifdown '#{network[:device]}' || true + + # Move new config into place + mv '#{remote_path}' '#{final_path}' + + # Bring the interface up + ARPCHECK=no /sbin/ifup '#{network[:device]}' + EOH end - # Bring down all the interfaces we're reconfiguring. By bringing down - # each specifically, we avoid reconfiguring p7p (the NAT interface) so - # SSH never dies. - interfaces.each do |interface| - retryable(on: Vagrant::Errors::VagrantError, tries: 3, sleep: 2) do - machine.communicate.sudo(<<-SCRIPT, error_check: true) -cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-#{interface} - -if command -v nmcli &>/dev/null; then - if command -v systemctl &>/dev/null && systemctl -q is-enabled NetworkManager &>/dev/null; then - nmcli c reload #{interface} - elif command -v service &>/dev/null && service NetworkManager status &>/dev/null; then - nmcli c reload #{interface} - fi -fi - -/sbin/ifdown #{interface} -/sbin/ifup #{interface} - -rm -f /tmp/vagrant-network-entry_#{interface} -SCRIPT - end - end + comm.sudo(commands.join("\n")) end end end diff --git a/templates/guests/freebsd/network_static6.erb b/templates/guests/freebsd/network_static6.erb new file mode 100644 index 000000000..094584da6 --- /dev/null +++ b/templates/guests/freebsd/network_static6.erb @@ -0,0 +1,6 @@ +#VAGRANT-BEGIN +ifconfig_<%= options[:device] %>_ipv6="inet6 <%= options[:ip] %> prefixlen <%= options[:netmask] %>" +<% if options[:gateway] %> +ipv6_default_router="<%= options[:gateway] %>" +<% end %> +#VAGRANT-END diff --git a/templates/guests/redhat/network_dhcp.erb b/templates/guests/redhat/network_dhcp.erb index 8bbaa62e4..b15250cc2 100644 --- a/templates/guests/redhat/network_dhcp.erb +++ b/templates/guests/redhat/network_dhcp.erb @@ -2,5 +2,5 @@ # The contents below are automatically generated by Vagrant. Do not modify. BOOTPROTO=dhcp ONBOOT=yes -DEVICE=eth<%= options[:interface] %> +DEVICE=<%= options[:device] %> #VAGRANT-END diff --git a/templates/guests/redhat/network_static.erb b/templates/guests/redhat/network_static.erb index 53ef59571..b144c6cf4 100644 --- a/templates/guests/redhat/network_static.erb +++ b/templates/guests/redhat/network_static.erb @@ -5,7 +5,7 @@ BOOTPROTO=none ONBOOT=yes IPADDR=<%= options[:ip] %> NETMASK=<%= options[:netmask] %> -DEVICE=eth<%= options[:interface] %> +DEVICE=<%= options[:device] %> <% if options[:gateway] %> GATEWAY=<%= options[:gateway] %> <% end %> diff --git a/templates/guests/redhat/network_static6.erb b/templates/guests/redhat/network_static6.erb new file mode 100644 index 000000000..288da4396 --- /dev/null +++ b/templates/guests/redhat/network_static6.erb @@ -0,0 +1,10 @@ +#VAGRANT-BEGIN +# The contents below are automatically generated by Vagrant. Do not modify. +auto <%= options[:device] %> +iface <%= options[:device] %> inet6 static + address <%= options[:ip] %> + netmask <%= options[:netmask] %> +<% if options[:gateway] %> + gateway <%= options[:gateway] %> +<% end %> +#VAGRANT-END