diff --git a/plugins/guests/gentoo/cap/configure_networks.rb b/plugins/guests/gentoo/cap/configure_networks.rb index 38b18501f..f7464432c 100644 --- a/plugins/guests/gentoo/cap/configure_networks.rb +++ b/plugins/guests/gentoo/cap/configure_networks.rb @@ -1,4 +1,5 @@ require "tempfile" +require "ipaddr" require_relative "../../../../lib/vagrant/util/template_renderer" @@ -14,35 +15,70 @@ module VagrantPlugins commands = [] interfaces = machine.guest.capability(:network_interfaces, "/bin/ip") - # Remove any previous network additions to the configuration file. - commands << "sed -i'' -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/conf.d/net" + networks.map! { |n| n[:device] = interfaces[n[:interface]]; n } - networks.each_with_index do |network, i| - network[:device] = interfaces[network[:interface]] + if comm.test('[[ `systemctl` =~ -\.mount ]]') + # Configure networking for Systemd - entry = TemplateRenderer.render("guests/gentoo/network_#{network[:type]}", - options: network, - ) + # convert netmasks to CIDR by converting to a binary string and counting the '1's + networks.map! { |n| n[:netmask] = IPAddr.new(n[:netmask]).to_i.to_s(2).count("1"); n } - remote_path = "/tmp/vagrant-network-#{network[:device]}-#{Time.now.to_i}-#{i}" + # glob networks by device, so that we can write one file per device + # (result is hash[devicename] = [net, net, net...]) + networks = networks.map { |n| [n[:device], n] }.reduce({}) { |h, (k, v)| (h[k] ||= []) << v; h } - Tempfile.open("vagrant-gentoo-configure-networks") do |f| - f.binmode - f.write(entry) - f.fsync - f.close - comm.upload(f.path, remote_path) + # Write one .network file out for each device + networks.each_pair do |device_name, device_networks| + entry = TemplateRenderer.render('guests/gentoo/network_systemd', networks: device_networks) + + filename = "50_vagrant_#{device_name}.network" + tmpfile = "/tmp/#{filename}" + destfile = "/etc/systemd/network/#{filename}" + + Tempfile.open('vagrant-gentoo-configure-networks') do |f| + f.binmode + f.write(entry) + f.fsync + f.close + comm.upload(f.path, tmpfile) + end + + commands << "mv #{tmpfile} #{destfile} && chmod 644 #{destfile}" end - commands << <<-EOH.gsub(/^ {14}/, '') - ln -sf /etc/init.d/net.lo /etc/init.d/net.#{network[:device]} - /etc/init.d/net.#{network[:device]} stop || true + # tell systemd to reload the networking config + commands << 'systemctl daemon-reload && systemctl restart systemd-networkd.service' + else + # Configure networking for OpenRC - cat '#{remote_path}' >> /etc/conf.d/net - rm -f '#{remote_path}' + # Remove any previous network additions to the configuration file. + commands << "sed -i'' -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/conf.d/net" - /etc/init.d/net.#{network[:device]} start - EOH + networks.each_with_index do |network, i| + entry = TemplateRenderer.render("guests/gentoo/network_#{network[:type]}", + options: network, + ) + + remote_path = "/tmp/vagrant-network-#{network[:device]}-#{Time.now.to_i}-#{i}" + + Tempfile.open("vagrant-gentoo-configure-networks") do |f| + f.binmode + f.write(entry) + f.fsync + f.close + comm.upload(f.path, remote_path) + end + + commands << <<-EOH.gsub(/^ {14}/, '') + ln -sf /etc/init.d/net.lo /etc/init.d/net.#{network[:device]} + /etc/init.d/net.#{network[:device]} stop || true + + cat '#{remote_path}' >> /etc/conf.d/net + rm -f '#{remote_path}' + + /etc/init.d/net.#{network[:device]} start + EOH + end end comm.sudo(commands.join("\n")) diff --git a/templates/guests/gentoo/network_systemd.erb b/templates/guests/gentoo/network_systemd.erb new file mode 100644 index 000000000..ddd6a79e6 --- /dev/null +++ b/templates/guests/gentoo/network_systemd.erb @@ -0,0 +1,16 @@ +[Match] +Name=<%= networks[0][:device] %> + +[Network] +<%- gateway = nil %> +<%- networks.each do |net| %> +<%- if net[:type] == 'dhcp' %> +DHCP=yes +<%- elsif net[:ip] %> +Address=<%= net[:ip] %>/<%= net[:netmask] %> +<%- end %> +<%- gateway ||= net[:gateway] %> +<%- end %> +<%- if gateway %> +Gateway=<%= gateway %> +<%- end %> diff --git a/test/unit/templates/guests/gentoo/systemd_network_test.rb b/test/unit/templates/guests/gentoo/systemd_network_test.rb new file mode 100644 index 000000000..a95c5e6ae --- /dev/null +++ b/test/unit/templates/guests/gentoo/systemd_network_test.rb @@ -0,0 +1,73 @@ +require_relative "../../../base" + +require "vagrant/util/template_renderer" + +describe "templates/guests/gentoo/network_systemd" do + let(:template) { "guests/gentoo/network_systemd" } + + it "renders the template with a static ip" do + result = Vagrant::Util::TemplateRenderer.render(template, networks: [{ + device: "eth0", + type: "dhcp", + }]) + expect(result).to eq <<-EOH.gsub(/^ {6}/, "") + [Match] + Name=eth0 + + [Network] + DHCP=yes + EOH + end + + it "renders the template with multiple ips" do + result = Vagrant::Util::TemplateRenderer.render(template, networks: [{ + device: "eth0", + ip: "1.1.1.1", + netmask: "16", + },{ + device: "eth0", + ip: "1.1.2.2", + netmask: "16", + }]) + expect(result).to eq <<-EOH.gsub(/^ {6}/, "") + [Match] + Name=eth0 + + [Network] + Address=1.1.1.1/16 + Address=1.1.2.2/16 + EOH + end + + it "renders the template with a static ip" do + result = Vagrant::Util::TemplateRenderer.render(template, networks: [{ + device: "eth0", + ip: "1.1.1.1", + netmask: "16", + }]) + expect(result).to eq <<-EOH.gsub(/^ {6}/, "") + [Match] + Name=eth0 + + [Network] + Address=1.1.1.1/16 + EOH + end + + it "includes the gateway" do + result = Vagrant::Util::TemplateRenderer.render(template, networks: [{ + device: "eth0", + ip: "1.1.1.1", + netmask: "16", + gateway: "1.2.3.4", + }]) + expect(result).to eq <<-EOH.gsub(/^ {6}/, "") + [Match] + Name=eth0 + + [Network] + Address=1.1.1.1/16 + Gateway=1.2.3.4 + EOH + end +end