From f046482cfb4fc9ed10ae900660360f2030181ff3 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 13 Dec 2017 16:44:13 -0800 Subject: [PATCH 1/6] [WIP] systemd networkd for debian guests --- lib/vagrant/util/guest_inspection.rb | 16 ++ .../guests/debian/cap/configure_networks.rb | 141 ++++++++++++++++-- .../guests/debian/networkd/network_dhcp.erb | 4 + .../guests/debian/networkd/network_static.erb | 8 + .../debian/networkd/network_static6.erb | 8 + .../debian/cap/configure_networks_test.rb | 44 +++++- 6 files changed, 206 insertions(+), 15 deletions(-) create mode 100644 templates/guests/debian/networkd/network_dhcp.erb create mode 100644 templates/guests/debian/networkd/network_static.erb create mode 100644 templates/guests/debian/networkd/network_static6.erb diff --git a/lib/vagrant/util/guest_inspection.rb b/lib/vagrant/util/guest_inspection.rb index 033bb3e97..04350ee96 100644 --- a/lib/vagrant/util/guest_inspection.rb +++ b/lib/vagrant/util/guest_inspection.rb @@ -15,6 +15,13 @@ module Vagrant comm.test("systemctl | grep '^-\.mount'") end + # systemd-networkd.service is in use + # + # @return [Boolean] + def systemd_networkd?(comm) + comm.test("sudo systemctl status systemd-networkd.service") + end + # systemd hostname set is via hostnamectl # # @return [Boolean] @@ -22,6 +29,15 @@ module Vagrant comm.test("hostnamectl") end + ## netplan helpers + + # netplan is installed + # + # @return [Boolean] + def netplan?(comm) + comm.test("netplan -h") + end + ## nmcli helpers # nmcli is installed diff --git a/plugins/guests/debian/cap/configure_networks.rb b/plugins/guests/debian/cap/configure_networks.rb index 99d6681de..47a108782 100644 --- a/plugins/guests/debian/cap/configure_networks.rb +++ b/plugins/guests/debian/cap/configure_networks.rb @@ -7,14 +7,111 @@ module VagrantPlugins module Cap class ConfigureNetworks include Vagrant::Util + extend Vagrant::Util::GuestInspection::Linux - def self.configure_networks(machine, networks) - comm = machine.communicate + def self.generate_netplan_cfg(options) + cfg = {"network" => {"version" => 2, + "renderer" => "networkd", + "ethernets" => {}}} - commands = [] - entries = [] - interfaces = machine.guest.capability(:network_interfaces) + options.each do |option| + cfg["network"]["ethernets"].merge!(option) + end + return cfg + end + def self.build_interface_entries(interface) + entry = {interface[:device] => {"dhcp4" => true}} + if interface[:ip] + # is this always the right prefix length to pick?? + entry[interface[:device]].merge!({"addresses" => ["#{interface[:ip]}/24"]}) + entry[interface[:device]]["dhcp4"] = false + end + + if interface[:gateway] + entry[interface[:device]].merge!({"gateway4" => interface[:gateway]}) + end + return entry + end + + def self.determine_systemd_networkd(comm) + return systemd?(comm) && systemd_networkd?(comm) + end + + def self.upload_tmp_file(comm, content, remote_path) + Tempfile.open("vagrant-debian-configure-networks") do |f| + f.binmode + f.write(content) + f.fsync + f.close + comm.upload(f.path, remote_path) + end + end + + def self.configure_netplan_networks(machine, interfaces, comm, networks) + commands = [] + entries = [] + + root_device = interfaces.first + networks.each do |network| + network[:device] = interfaces[network[:interface]] + + options = network.merge(:root_device => root_device) + entry = build_interface_entries(options) + entries << entry + end + + remote_path = "/tmp/vagrant-network-entry" + + netplan_cfg = generate_netplan_cfg(entries) + content = netplan_cfg.to_yaml + upload_tmp_file(comm, content, remote_path) + + commands << <<-EOH.gsub(/^ {12}/, "") + mv '#{remote_path}' /etc/netplan/99-vagrant.yaml + sudo netplan apply + EOH + + return commands + end + + def self.configure_networkd_networks(machine, interfaces, comm, networks) + commands = [] + entries = [] + + root_device = interfaces.first + networks.each.with_index do |network,i| + network[:device] = interfaces[network[:interface]] + # generic systemd-networkd config file + # update for debian + entry = TemplateRenderer.render("guests/debian/networkd/network_#{network[:type]}", + options: network, + ) + + remote_path = "/tmp/vagrant-network-#{network[:device]}-#{Time.now.to_i}-#{i}" + upload_tmp_file(comm, entry, remote_path) + + commands << <<-EOH.gsub(/^ {14}/, '').rstrip + # Configure #{network[:device]} + mv '#{remote_path}' '/etc/systemd/network/#{network[:device]}.network' && + sudo chown root:root '/etc/systemd/network/#{network[:device]}.network' && + sudo chmod 644 '/etc/systemd/network/#{network[:device]}.network' && + ip link set '#{network[:device]}' down && + sudo rm /etc/resolv.conf && + sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf && + sudo systemctl enable systemd-resolved.service && + sudo systemctl start systemd-resolved.service && + sudo systemctl enable systemd-networkd.service + sudo systemctl start systemd-networkd.service + EOH + end + + return commands + end + + def self.configure_other_networks(machine, interfaces, comm, networks) + commands = [] + entries = [] root_device = interfaces.first networks.each do |network| network[:device] = interfaces[network[:interface]] @@ -25,13 +122,9 @@ module VagrantPlugins entries << entry end - Tempfile.open("vagrant-debian-configure-networks") do |f| - f.binmode - f.write(entries.join("\n")) - f.fsync - f.close - comm.upload(f.path, "/tmp/vagrant-network-entry") - end + remote_path = "/tmp/vagrant-network-entry" + content = entries.join("\n") + upload_tmp_file(comm, content, remote_path) networks.each do |network| # Ubuntu 16.04+ returns an error when downing an interface that @@ -46,13 +139,11 @@ module VagrantPlugins # Remove any previous network modifications from the interfaces file sed -e '/^#VAGRANT-BEGIN/,$ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces.pre sed -ne '/^#VAGRANT-END/,$ p' /etc/network/interfaces | tac | sed -e '/^#VAGRANT-END/,$ d' | tac > /tmp/vagrant-network-interfaces.post - cat \\ /tmp/vagrant-network-interfaces.pre \\ /tmp/vagrant-network-entry \\ /tmp/vagrant-network-interfaces.post \\ > /etc/network/interfaces - rm -f /tmp/vagrant-network-interfaces.pre rm -f /tmp/vagrant-network-entry rm -f /tmp/vagrant-network-interfaces.post @@ -63,6 +154,28 @@ module VagrantPlugins commands << "/sbin/ifup '#{network[:device]}'" end + return commands + end + + def self.configure_networks(machine, networks) + comm = machine.communicate + + commands = [] + interfaces = machine.guest.capability(:network_interfaces) + + systemd_controlled = determine_systemd_networkd(comm) + netplan_cli = netplan?(comm) + + if systemd_controlled + if netplan_cli + commands = configure_netplan_networks(machine, interfaces, comm, networks) + else + commands = configure_networkd_networks(machine, interfaces, comm, networks) + end + else + commands = configure_other_networks(machine, interfaces, comm, networks) + end + # Run all the commands in one session to prevent partial configuration # due to a severed network. comm.sudo(commands.join("\n")) diff --git a/templates/guests/debian/networkd/network_dhcp.erb b/templates/guests/debian/networkd/network_dhcp.erb new file mode 100644 index 000000000..377784574 --- /dev/null +++ b/templates/guests/debian/networkd/network_dhcp.erb @@ -0,0 +1,4 @@ +Description='A basic dhcp ethernet connection' +Interface=<%= options[:device] %> +Connection=ethernet +IP=dhcp diff --git a/templates/guests/debian/networkd/network_static.erb b/templates/guests/debian/networkd/network_static.erb new file mode 100644 index 000000000..52b2f2d77 --- /dev/null +++ b/templates/guests/debian/networkd/network_static.erb @@ -0,0 +1,8 @@ +Connection=ethernet +Description='A basic static ethernet connection' +Interface=<%= options[:device] %> +IP=static +Address=('<%= options[:ip]%>/<%= options[:netmask] %>') +<% if options[:gateway] -%> +Gateway='<%= options[:gateway] %>' +<% end -%> diff --git a/templates/guests/debian/networkd/network_static6.erb b/templates/guests/debian/networkd/network_static6.erb new file mode 100644 index 000000000..e64ffd5ca --- /dev/null +++ b/templates/guests/debian/networkd/network_static6.erb @@ -0,0 +1,8 @@ +Connection=ethernet +Description='A basic IPv6 ethernet connection' +Interface=<%= options[:device] %> +IP6=static +Address6=('<%= options[:ip]%>/<%= options[:netmask] %>') +<% if options[:gateway] -%> +Gateway6='<%= options[:gateway] %>' +<% end -%> diff --git a/test/unit/plugins/guests/debian/cap/configure_networks_test.rb b/test/unit/plugins/guests/debian/cap/configure_networks_test.rb index 13a742cae..f0d8ab9e3 100644 --- a/test/unit/plugins/guests/debian/cap/configure_networks_test.rb +++ b/test/unit/plugins/guests/debian/cap/configure_networks_test.rb @@ -11,6 +11,7 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do let(:machine) { double("machine", guest: guest) } let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + before do allow(machine).to receive(:communicate).and_return(comm) end @@ -19,6 +20,32 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do comm.verify_expectations! end + describe "#generate_netplan_cfg" do + end + + describe "#build_interface_entries" do + let(:network_0) do + { + interface: 0, + type: "dhcp", + } + end + + let(:network_1) do + { + interface: 1, + type: "static", + ip: "33.33.33.10", + netmask: "255.255.0.0", + gateway: "33.33.0.1", + } + end + + it "builds an interface entry" do + end + + end + describe ".configure_networks" do let(:cap) { caps.get(:configure_networks) } @@ -44,7 +71,11 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do } end - it "creates and starts the networks" do + it "creates and starts the networks for non systemd" do + allow(comm).to receive(:test).with("systemctl | grep '^-.mount'").and_return(false) + allow(comm).to receive(:test).with("systemctl status systemd-networkd.service").and_return(false) + allow(comm).to receive(:test).with("netplan -h").and_return(false) + cap.configure_networks(machine, [network_0, network_1]) expect(comm.received_commands[0]).to match("/sbin/ifdown 'eth1' || true") @@ -54,5 +85,16 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do expect(comm.received_commands[0]).to match("/sbin/ifup 'eth1'") expect(comm.received_commands[0]).to match("/sbin/ifup 'eth2'") end + + it "creates and starts the networks for systemd with netplan" do + allow(comm).to receive(:test).with("systemctl | grep '^-.mount'").and_return(true) + allow(comm).to receive(:test).with("sudo systemctl status systemd-networkd.service").and_return(true) + allow(comm).to receive(:test).with("netplan -h").and_return(true) + + cap.configure_networks(machine, [network_0, network_1]) + + expect(comm.received_commands[0]).to match("mv '/tmp/vagrant-network-entry' /etc/netplan/99-vagrant.yaml") + expect(comm.received_commands[0]).to match("sudo netplan apply") + end end end From 75a03ff9e9cc4dd4504327616666ffc92eda94a1 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Wed, 3 Jan 2018 07:17:41 -0800 Subject: [PATCH 2/6] Update available debian networking options --- .../guests/debian/cap/configure_networks.rb | 200 ++++++++---------- .../guests/debian/networkd/network_dhcp.erb | 4 - .../guests/debian/networkd/network_static.erb | 8 - .../debian/networkd/network_static6.erb | 8 - 4 files changed, 88 insertions(+), 132 deletions(-) delete mode 100644 templates/guests/debian/networkd/network_dhcp.erb delete mode 100644 templates/guests/debian/networkd/network_static.erb delete mode 100644 templates/guests/debian/networkd/network_static6.erb diff --git a/plugins/guests/debian/cap/configure_networks.rb b/plugins/guests/debian/cap/configure_networks.rb index 47a108782..c2a554c3d 100644 --- a/plugins/guests/debian/cap/configure_networks.rb +++ b/plugins/guests/debian/cap/configure_networks.rb @@ -9,107 +9,89 @@ module VagrantPlugins include Vagrant::Util extend Vagrant::Util::GuestInspection::Linux - def self.generate_netplan_cfg(options) - cfg = {"network" => {"version" => 2, - "renderer" => "networkd", - "ethernets" => {}}} + NETPLAN_DEFAULT_VERSION = 2 + NETPLAN_DEFAULT_RENDERER = "networkd".freeze + NETPLAN_DIRECTORY = "/etc/netplan".freeze + NETWORKD_DIRECTORY = "/etc/systemd/network".freeze - options.each do |option| - cfg["network"]["ethernets"].merge!(option) - end - return cfg - end - def self.build_interface_entries(interface) - entry = {interface[:device] => {"dhcp4" => true}} - if interface[:ip] - # is this always the right prefix length to pick?? - entry[interface[:device]].merge!({"addresses" => ["#{interface[:ip]}/24"]}) - entry[interface[:device]]["dhcp4"] = false - end + def self.configure_networks(machine, networks) + comm = machine.communicate + interfaces = machine.guest.capability(:network_interfaces) - if interface[:gateway] - entry[interface[:device]].merge!({"gateway4" => interface[:gateway]}) - end - return entry - end - - def self.determine_systemd_networkd(comm) - return systemd?(comm) && systemd_networkd?(comm) - end - - def self.upload_tmp_file(comm, content, remote_path) - Tempfile.open("vagrant-debian-configure-networks") do |f| - f.binmode - f.write(content) - f.fsync - f.close - comm.upload(f.path, remote_path) + if netplan?(comm) + configure_netplan(machine, interfaces, comm, networks) + elsif systemd?(comm) + if systemd_networkd?(comm) + configure_networkd(machine, interfaces, comm, networks) + else + configure_systemd(machine, interfaces, comm, networks) + end + else + configure_nettools(machine, interfaces, comm, networks) end end - def self.configure_netplan_networks(machine, interfaces, comm, networks) - commands = [] - entries = [] + # Configure networking using netplan + def self.configure_netplan(machine, interfaces, comm, networks) + ethernets = {}.tap do |e_nets| + networks.each do |network| + e_config = {}.tap do |entry| + if network[:ip] + mask = IPAddr.new(network.fetch(:netmask, "255.255.255.0")).to_i.to_s(2).count("1") + entry["addresses"] = ["#{network[:ip]}/#{mask}"] + else + entry["dhcp4"] = true + end + if network[:gateway] + entry["gateway4"] = network[:gateway] + end + end + e_nets[interfaces[network[:interface]]] = e_config + end + end + np_config = {"network" => {"version" => NETPLAN_DEFAULT_VERSION, + "renderer" => NETPLAN_DEFAULT_RENDERER, "ethernets" => ethernets}} + + remote_path = upload_tmp_file(comm, np_config.to_yaml) + dest_path = "#{NETPLAN_DIRECTORY}/99-vagrant.yaml" + comm.sudo(["mv -f '#{remote_path}' '#{dest_path}'", + "chown root:root '#{dest_path}'", + "chmod 0644 '#{dest_path}'", + "netplan apply"].join("\n")) + end + + # Configure guest networking using networkd + def self.configure_networkd(machine, interfaces, comm, networks) + net_conf = [] root_device = interfaces.first networks.each do |network| - network[:device] = interfaces[network[:interface]] - - options = network.merge(:root_device => root_device) - entry = build_interface_entries(options) - entries << entry + dev_name = interfaces[network[:interface]] + net_conf << "[Match]" + net_conf << "Name=#{dev_name}" + net_conf << "[Network]" + if network[:ip] + mask = IPAddr.new(network.fetch(:netmask, "255.255.255.0")).to_i.to_s(2).count("1") + net_conf << "DHCP=no" + net_conf << "Address=#{network[:ip]}/#{mask}" + net_conf << "Gateway=#{network[:gateway]}" if network[:gateway] + else + net_conf << "DHCP=yes" + end end - remote_path = "/tmp/vagrant-network-entry" - - netplan_cfg = generate_netplan_cfg(entries) - content = netplan_cfg.to_yaml - upload_tmp_file(comm, content, remote_path) - - commands << <<-EOH.gsub(/^ {12}/, "") - mv '#{remote_path}' /etc/netplan/99-vagrant.yaml - sudo netplan apply - EOH - - return commands + remote_path = upload_tmp_file(comm, net_conf.join("\n")) + dest_path = "#{NETWORKD_DIRECTORY}/99-vagrant.network" + comm.sudo(["mkdir -p #{NETWORKD_DIRECTORY}", + "mv -f '#{remote_path}' '#{dest_path}'", + "chown root:root '#{dest_path}'", + "chmod 0644 '#{dest_path}'", + "systemctl restart systemd-networkd.service"].join("\n")) end - def self.configure_networkd_networks(machine, interfaces, comm, networks) - commands = [] - entries = [] - - root_device = interfaces.first - networks.each.with_index do |network,i| - network[:device] = interfaces[network[:interface]] - # generic systemd-networkd config file - # update for debian - entry = TemplateRenderer.render("guests/debian/networkd/network_#{network[:type]}", - options: network, - ) - - remote_path = "/tmp/vagrant-network-#{network[:device]}-#{Time.now.to_i}-#{i}" - upload_tmp_file(comm, entry, remote_path) - - commands << <<-EOH.gsub(/^ {14}/, '').rstrip - # Configure #{network[:device]} - mv '#{remote_path}' '/etc/systemd/network/#{network[:device]}.network' && - sudo chown root:root '/etc/systemd/network/#{network[:device]}.network' && - sudo chmod 644 '/etc/systemd/network/#{network[:device]}.network' && - ip link set '#{network[:device]}' down && - sudo rm /etc/resolv.conf && - sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf && - sudo systemctl enable systemd-resolved.service && - sudo systemctl start systemd-resolved.service && - sudo systemctl enable systemd-networkd.service - sudo systemctl start systemd-networkd.service - EOH - end - - return commands - end - - def self.configure_other_networks(machine, interfaces, comm, networks) + # Configure guest networking using net-tools + def self.configure_nettools(machine, interfaces, comm, networks) commands = [] entries = [] root_device = interfaces.first @@ -122,8 +104,8 @@ module VagrantPlugins entries << entry end - remote_path = "/tmp/vagrant-network-entry" content = entries.join("\n") + remote_path = "/tmp/vagrant-network-entry" upload_tmp_file(comm, content, remote_path) networks.each do |network| @@ -153,32 +135,26 @@ module VagrantPlugins networks.each do |network| commands << "/sbin/ifup '#{network[:device]}'" end - - return commands + comm.sudo(commands.join("\n")) end - def self.configure_networks(machine, networks) - comm = machine.communicate - - commands = [] - interfaces = machine.guest.capability(:network_interfaces) - - systemd_controlled = determine_systemd_networkd(comm) - netplan_cli = netplan?(comm) - - if systemd_controlled - if netplan_cli - commands = configure_netplan_networks(machine, interfaces, comm, networks) - else - commands = configure_networkd_networks(machine, interfaces, comm, networks) - end - else - commands = configure_other_networks(machine, interfaces, comm, networks) + # Simple helper to upload content to guest temporary file + # + # @param [Vagrant::Plugin::Communicator] comm + # @param [String] content + # @return [String] remote path + def self.upload_tmp_file(comm, content, remote_path=nil) + if remote_path.nil? + remote_path = "/tmp/vagrant-network-entry-#{Time.now.to_i}" end - - # Run all the commands in one session to prevent partial configuration - # due to a severed network. - comm.sudo(commands.join("\n")) + Tempfile.open("vagrant-debian-configure-networks") do |f| + f.binmode + f.write(content) + f.fsync + f.close + comm.upload(f.path, remote_path) + end + remote_path end end end diff --git a/templates/guests/debian/networkd/network_dhcp.erb b/templates/guests/debian/networkd/network_dhcp.erb deleted file mode 100644 index 377784574..000000000 --- a/templates/guests/debian/networkd/network_dhcp.erb +++ /dev/null @@ -1,4 +0,0 @@ -Description='A basic dhcp ethernet connection' -Interface=<%= options[:device] %> -Connection=ethernet -IP=dhcp diff --git a/templates/guests/debian/networkd/network_static.erb b/templates/guests/debian/networkd/network_static.erb deleted file mode 100644 index 52b2f2d77..000000000 --- a/templates/guests/debian/networkd/network_static.erb +++ /dev/null @@ -1,8 +0,0 @@ -Connection=ethernet -Description='A basic static ethernet connection' -Interface=<%= options[:device] %> -IP=static -Address=('<%= options[:ip]%>/<%= options[:netmask] %>') -<% if options[:gateway] -%> -Gateway='<%= options[:gateway] %>' -<% end -%> diff --git a/templates/guests/debian/networkd/network_static6.erb b/templates/guests/debian/networkd/network_static6.erb deleted file mode 100644 index e64ffd5ca..000000000 --- a/templates/guests/debian/networkd/network_static6.erb +++ /dev/null @@ -1,8 +0,0 @@ -Connection=ethernet -Description='A basic IPv6 ethernet connection' -Interface=<%= options[:device] %> -IP6=static -Address6=('<%= options[:ip]%>/<%= options[:netmask] %>') -<% if options[:gateway] -%> -Gateway6='<%= options[:gateway] %>' -<% end -%> From a36a84c85a602e63ee79a7e3d13af130e5201439 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Wed, 3 Jan 2018 16:31:49 -0800 Subject: [PATCH 3/6] Only apply netplan configuration if systemd is in use --- plugins/guests/debian/cap/configure_networks.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/guests/debian/cap/configure_networks.rb b/plugins/guests/debian/cap/configure_networks.rb index c2a554c3d..34906e8d7 100644 --- a/plugins/guests/debian/cap/configure_networks.rb +++ b/plugins/guests/debian/cap/configure_networks.rb @@ -19,13 +19,13 @@ module VagrantPlugins comm = machine.communicate interfaces = machine.guest.capability(:network_interfaces) - if netplan?(comm) - configure_netplan(machine, interfaces, comm, networks) - elsif systemd?(comm) - if systemd_networkd?(comm) + if systemd?(comm) + if netplan?(comm) + configure_netplan(machine, interfaces, comm, networks) + elsif systemd_networkd?(comm) configure_networkd(machine, interfaces, comm, networks) else - configure_systemd(machine, interfaces, comm, networks) + configure_nettools(machine, interfaces, comm, networks) end else configure_nettools(machine, interfaces, comm, networks) From 95967650345c76a31c9e865f1de28700c7f052d4 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Wed, 3 Jan 2018 16:32:21 -0800 Subject: [PATCH 4/6] Update debian network configuration tests --- .../debian/cap/configure_networks_test.rb | 57 ++++++++++++++++--- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/test/unit/plugins/guests/debian/cap/configure_networks_test.rb b/test/unit/plugins/guests/debian/cap/configure_networks_test.rb index f0d8ab9e3..121af75dc 100644 --- a/test/unit/plugins/guests/debian/cap/configure_networks_test.rb +++ b/test/unit/plugins/guests/debian/cap/configure_networks_test.rb @@ -71,11 +71,13 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do } end - it "creates and starts the networks for non systemd" do + before do allow(comm).to receive(:test).with("systemctl | grep '^-.mount'").and_return(false) - allow(comm).to receive(:test).with("systemctl status systemd-networkd.service").and_return(false) + allow(comm).to receive(:test).with("sudo systemctl status systemd-networkd.service").and_return(false) allow(comm).to receive(:test).with("netplan -h").and_return(false) + end + it "creates and starts the networks using net-tools" do cap.configure_networks(machine, [network_0, network_1]) expect(comm.received_commands[0]).to match("/sbin/ifdown 'eth1' || true") @@ -86,15 +88,52 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do expect(comm.received_commands[0]).to match("/sbin/ifup 'eth2'") end - it "creates and starts the networks for systemd with netplan" do - allow(comm).to receive(:test).with("systemctl | grep '^-.mount'").and_return(true) - allow(comm).to receive(:test).with("sudo systemctl status systemd-networkd.service").and_return(true) - allow(comm).to receive(:test).with("netplan -h").and_return(true) + context "with systemd" do + before do + expect(comm).to receive(:test).with("systemctl | grep '^-.mount'").and_return(true) + allow(comm).to receive(:test).with("netplan -h").and_return(false) + end - cap.configure_networks(machine, [network_0, network_1]) + it "creates and starts the networks using net-tools" do + cap.configure_networks(machine, [network_0, network_1]) - expect(comm.received_commands[0]).to match("mv '/tmp/vagrant-network-entry' /etc/netplan/99-vagrant.yaml") - expect(comm.received_commands[0]).to match("sudo netplan apply") + expect(comm.received_commands[0]).to match("/sbin/ifdown 'eth1' || true") + expect(comm.received_commands[0]).to match("/sbin/ip addr flush dev 'eth1'") + expect(comm.received_commands[0]).to match("/sbin/ifdown 'eth2' || true") + expect(comm.received_commands[0]).to match("/sbin/ip addr flush dev 'eth2'") + expect(comm.received_commands[0]).to match("/sbin/ifup 'eth1'") + expect(comm.received_commands[0]).to match("/sbin/ifup 'eth2'") + end + + context "with systemd-networkd" do + before do + expect(comm).to receive(:test).with("sudo systemctl status systemd-networkd.service").and_return(true) + end + + it "creates and starts the networks using systemd-networkd" do + cap.configure_networks(machine, [network_0, network_1]) + + expect(comm.received_commands[0]).to match("mv -f '/tmp/vagrant-network-entry.*' '/etc/systemd/network/.*network'") + expect(comm.received_commands[0]).to match("chown") + expect(comm.received_commands[0]).to match("chmod") + expect(comm.received_commands[0]).to match("systemctl restart") + end + end + + context "with netplan" do + before do + expect(comm).to receive(:test).with("netplan -h").and_return(true) + end + + it "creates and starts the networks for systemd with netplan" do + cap.configure_networks(machine, [network_0, network_1]) + + expect(comm.received_commands[0]).to match("mv -f '/tmp/vagrant-network-entry.*' '/etc/netplan/.*.yaml'") + expect(comm.received_commands[0]).to match("chown") + expect(comm.received_commands[0]).to match("chmod") + expect(comm.received_commands[0]).to match("netplan apply") + end + end end end end From 913b5639e5aba0331621457b7cf44e7a934b5b62 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Wed, 3 Jan 2018 17:26:08 -0800 Subject: [PATCH 5/6] Do better handling given netmasks --- .../guests/debian/cap/configure_networks.rb | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/plugins/guests/debian/cap/configure_networks.rb b/plugins/guests/debian/cap/configure_networks.rb index 34906e8d7..f48bd4601 100644 --- a/plugins/guests/debian/cap/configure_networks.rb +++ b/plugins/guests/debian/cap/configure_networks.rb @@ -38,8 +38,15 @@ module VagrantPlugins networks.each do |network| e_config = {}.tap do |entry| if network[:ip] - mask = IPAddr.new(network.fetch(:netmask, "255.255.255.0")).to_i.to_s(2).count("1") - entry["addresses"] = ["#{network[:ip]}/#{mask}"] + mask = network[:netmask] + if mask && IPAddr.new(network[:ip]).ipv4? + begin + mask = IPAddr.new(mask).to_i.to_s(2).count("1") + rescue IPAddr::Error + # ignore and use given value + end + end + entry["addresses"] = [[network[:ip], mask].compact.join("/")] else entry["dhcp4"] = true end @@ -72,9 +79,17 @@ module VagrantPlugins net_conf << "Name=#{dev_name}" net_conf << "[Network]" if network[:ip] - mask = IPAddr.new(network.fetch(:netmask, "255.255.255.0")).to_i.to_s(2).count("1") + mask = network[:netmask] + if mask && IPAddr.new(network[:ip]).ipv4? + begin + mask = IPAddr.new(mask).to_i.to_s(2).count("1") + rescue IPAddr::Error + # ignore and use given value + end + end + address = [network[:ip], mask].compact.join("/") net_conf << "DHCP=no" - net_conf << "Address=#{network[:ip]}/#{mask}" + net_conf << "Address=#{address}" net_conf << "Gateway=#{network[:gateway]}" if network[:gateway] else net_conf << "DHCP=yes" From 5191ec1281f95abd77314ddf0d1d8b0a93bc4f33 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Thu, 4 Jan 2018 15:06:19 -0800 Subject: [PATCH 6/6] Remove old test stubs --- .../plugins/guests/debian/cap/configure_networks_test.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/unit/plugins/guests/debian/cap/configure_networks_test.rb b/test/unit/plugins/guests/debian/cap/configure_networks_test.rb index 121af75dc..84030d96c 100644 --- a/test/unit/plugins/guests/debian/cap/configure_networks_test.rb +++ b/test/unit/plugins/guests/debian/cap/configure_networks_test.rb @@ -20,9 +20,6 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do comm.verify_expectations! end - describe "#generate_netplan_cfg" do - end - describe "#build_interface_entries" do let(:network_0) do { @@ -40,10 +37,6 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do gateway: "33.33.0.1", } end - - it "builds an interface entry" do - end - end describe ".configure_networks" do