From ce3329e1847e9696cbb4c8a49c08661ec9376c31 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Thu, 11 Aug 2016 17:01:36 -0700 Subject: [PATCH] guests/linux: Always order discovered network interfaces --- .../guests/linux/cap/network_interfaces.rb | 18 ++++++- .../linux/cap/network_interfaces_test.rb | 48 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test/unit/plugins/guests/linux/cap/network_interfaces_test.rb diff --git a/plugins/guests/linux/cap/network_interfaces.rb b/plugins/guests/linux/cap/network_interfaces.rb index 3360fde78..8a4c64dd3 100644 --- a/plugins/guests/linux/cap/network_interfaces.rb +++ b/plugins/guests/linux/cap/network_interfaces.rb @@ -2,6 +2,8 @@ module VagrantPlugins module GuestLinux module Cap class NetworkInterfaces + @@logger = Log4r::Logger.new("vagrant::guest::linux::network_interfaces") + # Get network interfaces as a list. The result will be something like: # # eth0\nenp0s8\nenp0s9 @@ -12,7 +14,21 @@ module VagrantPlugins machine.communicate.sudo("#{path} -o -0 addr | grep -v LOOPBACK | awk '{print $2}' | sed 's/://'") do |type, data| s << data if type == :stdout end - s.split("\n") + ifaces = s.split("\n") + @@logger.debug("Unsorted list: #{ifaces.inspect}") + # Break out integers from strings and sort the arrays to provide + # a natural sort for the interface names + ifaces = ifaces.map do |iface| + iface.scan(/(.+?)(\d+)/).flatten.map do |iface_part| + if iface_part.to_i.to_s == iface_part + iface_part.to_i + else + iface_part + end + end + end.sort.map(&:join) + @@logger.debug("Sorted list: #{ifaces.inspect}") + ifaces end end end diff --git a/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb b/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb new file mode 100644 index 000000000..8dd4498a7 --- /dev/null +++ b/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb @@ -0,0 +1,48 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestLinux::Cap::NetworkInterfaces" do + let(:caps) do + VagrantPlugins::GuestLinux::Plugin + .components + .guest_capabilities[:linux] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + after do + comm.verify_expectations! + end + + describe ".network_interfaces" do + let(:cap){ caps.get(:network_interfaces) } + + it "sorts discovered classic interfaces" do + expect(comm).to receive(:sudo).and_yield(:stdout, "eth1\neth2\neth0") + result = cap.network_interfaces(machine) + expect(result).to eq(["eth0", "eth1", "eth2"]) + end + + it "sorts discovered predictable network interfaces" do + expect(comm).to receive(:sudo).and_yield(:stdout, "enp0s8\nenp0s3\nenp0s5") + result = cap.network_interfaces(machine) + expect(result).to eq(["enp0s3", "enp0s5", "enp0s8"]) + end + + it "sorts discovered classic interfaces naturally" do + expect(comm).to receive(:sudo).and_yield(:stdout, "eth1\neth2\neth12\neth0\neth10") + result = cap.network_interfaces(machine) + expect(result).to eq(["eth0", "eth1", "eth2", "eth10", "eth12"]) + end + + it "sorts discovered predictable network interfaces naturally" do + expect(comm).to receive(:sudo).and_yield(:stdout, "enp0s8\nenp0s3\nenp0s5\nenp0s10\nenp1s3") + result = cap.network_interfaces(machine) + expect(result).to eq(["enp0s3", "enp0s5", "enp0s8", "enp0s10", "enp1s3"]) + end + end +end