132 lines
4.6 KiB
Ruby
132 lines
4.6 KiB
Ruby
require "ipaddr"
|
|
|
|
require_relative "../../../../lib/vagrant/util/template_renderer"
|
|
require_relative "../../../../lib/vagrant/util/tempfile"
|
|
|
|
module VagrantPlugins
|
|
module GuestNixos
|
|
module Cap
|
|
class ConfigureNetworks
|
|
include Vagrant::Util
|
|
|
|
def self.configure_networks(machine, networks)
|
|
# set the prefix length.
|
|
networks.each do |network|
|
|
network[:prefix_length] = (network[:netmask] && netmask_to_cidr(network[:netmask]))
|
|
end
|
|
|
|
# set the device names.
|
|
assign_device_names(machine, networks)
|
|
|
|
# upload the config file
|
|
network_module = TemplateRenderer.render("guests/nixos/network", networks: networks)
|
|
upload(machine, network_module, "/etc/nixos/vagrant-network.nix")
|
|
end
|
|
|
|
# Set :device on each network.
|
|
# Attempts to use biosdevname when available to detect interface names,
|
|
# and falls back to ifconfig otherwise.
|
|
def self.assign_device_names(machine, networks)
|
|
if machine.communicate.test("command -v biosdevname")
|
|
# use biosdevname to get info about the interfaces
|
|
interfaces = get_interfaces(machine)
|
|
if machine.provider.capability?(:nic_mac_addresses)
|
|
# find device name by MAC lookup.
|
|
mac_addresses = machine.provider.capability(:nic_mac_addresses)
|
|
networks.each do |network|
|
|
mac_address = mac_addresses[network[:interface]+1]
|
|
interface = interfaces.detect {|nic| nic[:mac_address].gsub(":","") == mac_address} if mac_address
|
|
network[:device] = interface[:kernel] if interface
|
|
end
|
|
else
|
|
# assume interface numbers correspond to (ethN+1).
|
|
networks.each do |network|
|
|
interface = interfaces.detect {|nic| nic[:ethn] == network[:interface]}
|
|
network[:device] = interface[:kernel] if interface
|
|
end
|
|
end
|
|
else
|
|
# assume interface numbers correspond to the order of interfaces.
|
|
interfaces = get_interface_names(machine)
|
|
networks.each do |network|
|
|
network[:device] = interfaces[network[:interface]]
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.get_interface_names(machine)
|
|
output = nil
|
|
machine.communicate.execute("ifconfig -a") do |type, result|
|
|
output = result.chomp if type == :stdout
|
|
end
|
|
names = output.scan(/^[^:\s]+/).reject {|name| name =~ /^lo/ }
|
|
names
|
|
end
|
|
|
|
# Upload a file.
|
|
def self.upload(machine, content, remote_path)
|
|
remote_temp = mktemp(machine)
|
|
|
|
Tempfile.create("nixos-configure-networks") do |f|
|
|
f.write(content)
|
|
f.fsync
|
|
f.close
|
|
machine.communicate.upload(f.path, "#{remote_temp}")
|
|
end
|
|
|
|
machine.communicate.sudo("mv #{remote_temp} #{remote_path}")
|
|
end
|
|
|
|
# Create a temp file.
|
|
def self.mktemp(machine)
|
|
path = nil
|
|
|
|
machine.communicate.execute("mktemp --suffix -vagrant-upload") do |type, result|
|
|
path = result.chomp if type == :stdout
|
|
end
|
|
path
|
|
end
|
|
|
|
# using biosdevname, get all interfaces as a list of hashes, where:
|
|
# :kernel - the kernel's name for the device,
|
|
# :ethn - the calculated ethN-style name converted to integer.
|
|
# :mac_address - the permanent mac address. ethN-style name converted to integer.
|
|
def self.get_interfaces(machine)
|
|
interfaces = []
|
|
|
|
# get all adapters, as named by the kernel
|
|
output = nil
|
|
machine.communicate.sudo("biosdevname -d") do |type, result|
|
|
output = result if type == :stdout
|
|
end
|
|
kernel_if_names = output.scan(/Kernel name: ([^\n]+)/).flatten
|
|
mac_addresses = output.scan(/Permanent MAC: ([^\n]+)/).flatten
|
|
|
|
# get ethN-style names
|
|
ethns = []
|
|
kernel_if_names.each do |name|
|
|
machine.communicate.sudo("biosdevname --policy=all_ethN -i #{name}") do |type, result|
|
|
ethns << result.gsub(/[^\d]/,'').to_i if type == :stdout
|
|
end
|
|
end
|
|
|
|
# populate the interface list
|
|
kernel_if_names.each_index do |i|
|
|
interfaces << {
|
|
kernel: kernel_if_names[i],
|
|
ethn: ethns[i],
|
|
mac_address: mac_addresses[i]
|
|
}
|
|
end
|
|
|
|
interfaces
|
|
end
|
|
|
|
def self.netmask_to_cidr(mask)
|
|
IPAddr.new(mask).to_i.to_s(2).count("1")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|