diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index 38cce7967..4271967ef 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -468,6 +468,10 @@ module Vagrant error_key(:multi_vm_target_required) end + class NetplanNoAvailableRenderers < VagrantError + error_key(:netplan_no_available_renderers) + end + class NetSSHException < VagrantError error_key(:net_ssh_exception) end diff --git a/lib/vagrant/util/guest_inspection.rb b/lib/vagrant/util/guest_inspection.rb index f6e1b1e7d..46037f9d4 100644 --- a/lib/vagrant/util/guest_inspection.rb +++ b/lib/vagrant/util/guest_inspection.rb @@ -73,6 +73,14 @@ module Vagrant comm.test("command -v netplan") end + # is networkd isntalled + # + # @param [Vagrant::Plugin::V2::Communicator] comm Guest communicator + # @return [Boolean] + def networkd?(comm) + comm.test("command -v networkd") + 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 23b7bbcdf..eda4c4b3c 100644 --- a/plugins/guests/debian/cap/configure_networks.rb +++ b/plugins/guests/debian/cap/configure_networks.rb @@ -10,7 +10,6 @@ module VagrantPlugins extend Vagrant::Util::GuestInspection::Linux NETPLAN_DEFAULT_VERSION = 2 - NETPLAN_DEFAULT_RENDERER = "networkd".freeze NETPLAN_DIRECTORY = "/etc/netplan".freeze NETWORKD_DIRECTORY = "/etc/systemd/network".freeze @@ -61,12 +60,21 @@ module VagrantPlugins # By default, netplan expects the renderer to be systemd-networkd, # but if any device is managed by NetworkManager, then we use that renderer # ref: https://netplan.io/reference - renderer = NETPLAN_DEFAULT_RENDERER - ethernets.keys.each do |k| - if nm_controlled?(comm, k) - renderer = "NetworkManager" - break + if networkd?(comm) + renderer = "networkd" + ethernets.keys.each do |k| + if nm_controlled?(comm, k) + render = "NetworkManager" + if !nmcli?(comm) + raise Vagrant::Errors::NetworkManagerNotInstalled, device: k + end + break + end end + elsif nmcli?(comm) + renderer = "NetworkManager" + else + raise Vagrant::Errors::NetplanNoAvailableRenderers end np_config = {"network" => {"version" => NETPLAN_DEFAULT_VERSION, diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 4557a54e2..b4e9ad546 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1000,6 +1000,9 @@ en: the proper location. multi_vm_target_required: |- This command requires a specific VM name to target in a multi-VM environment. + netplan_no_available_renderers: |- + No renderers compatible with netplan are available on guest. Please install + a compatible renderer. net_ssh_exception: |- An error occurred in the underlying SSH library that Vagrant uses. The error message is shown below. In many cases, errors from this 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 bff0d153f..337f7a08c 100644 --- a/test/unit/plugins/guests/debian/cap/configure_networks_test.rb +++ b/test/unit/plugins/guests/debian/cap/configure_networks_test.rb @@ -140,6 +140,8 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do let(:networkd_yml) { "---\nnetwork:\n version: 2\n renderer: networkd\n ethernets:\n eth1:\n dhcp4: true\n eth2:\n addresses:\n - 33.33.33.10/16\n gateway4: 33.33.0.1\n" } it "uses NetworkManager if detected on device" do + allow(cap).to receive(:networkd?).and_return(false) + allow(cap).to receive(:nmcli?).and_return(true) allow(cap).to receive(:nm_controlled?).and_return(true) allow(comm).to receive(:test).with("nmcli -t d show eth1").and_return(true) allow(comm).to receive(:test).with("nmcli -t d show eth2").and_return(true) @@ -156,7 +158,18 @@ describe "VagrantPlugins::GuestDebian::Cap::ConfigureNetworks" do expect(comm.received_commands[0]).to match("netplan apply") end + it "raises and error if NetworkManager is detected on device but nmcli is not installed" do + allow(cap).to receive(:networkd?).and_return(true) + allow(cap).to receive(:nmcli?).and_return(false) + allow(cap).to receive(:nm_controlled?).and_return(true) + allow(comm).to receive(:test).with("nmcli -t d show eth1").and_return(true) + allow(comm).to receive(:test).with("nmcli -t d show eth2").and_return(true) + + expect { cap.configure_networks(machine, [network_0, network_1]) }.to raise_error(Vagrant::Errors::NetworkManagerNotInstalled) + end + it "creates and starts the networks for systemd with netplan" do + allow(cap).to receive(:networkd?).and_return(true) expect(cap).to receive(:upload_tmp_file).with(comm, networkd_yml) .and_return("/tmp/vagrant-network-entry.1234")