From e2b18fc65db2e2871afd72ea86ac5f173463e7da Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Tue, 4 Oct 2016 17:25:00 -0700 Subject: [PATCH 1/2] guests/linux: Update network interface sorting implementation Always pull ordered ethernet devices to the head of the list. Ensure aliases are not included. --- plugins/guests/linux/cap/network_interfaces.rb | 18 +++++++----------- .../linux/cap/network_interfaces_test.rb | 12 ++++++++++++ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/plugins/guests/linux/cap/network_interfaces.rb b/plugins/guests/linux/cap/network_interfaces.rb index 6d3ce657c..c66de24c4 100644 --- a/plugins/guests/linux/cap/network_interfaces.rb +++ b/plugins/guests/linux/cap/network_interfaces.rb @@ -20,16 +20,10 @@ module VagrantPlugins s << data if type == :stdout end ifaces = s.split("\n") - eth_prefix = nil @@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| - if eth_prefix.nil? - eth_prefix = POSSIBLE_ETHERNET_PREFIXES.detect do |prefix| - iface.start_with?(prefix) - end - end iface.scan(/(.+?)(\d+)/).flatten.map do |iface_part| if iface_part.to_i.to_s == iface_part iface_part.to_i @@ -40,12 +34,14 @@ module VagrantPlugins end.sort.map(&:join) @@logger.debug("Sorted list: #{ifaces.inspect}") # Extract ethernet devices and place at start of list - if eth_prefix - eth_start = ifaces.index{|iface| iface.start_with?(eth_prefix) } - eth_end = ifaces.rindex{|iface| iface.start_with?(eth_prefix) } - ifaces.unshift(*ifaces.slice!(eth_start, eth_end - 1)) - @@logger.debug("Ethernet preferred sorted list: #{ifaces.inspect}") + resorted_ifaces = [] + resorted_ifaces += ifaces.find_all do |iface| + POSSIBLE_ETHERNET_PREFIXES.any?{|prefix| iface.start_with?(prefix)} && + !iface.include?(':') end + resorted_ifaces += ifaces - resorted_ifaces + ifaces = resorted_ifaces + @@logger.debug("Ethernet preferred sorted list: #{ifaces.inspect}") ifaces 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 index 810606f2a..5c6a36546 100644 --- a/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb +++ b/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb @@ -56,5 +56,17 @@ describe "VagrantPlugins::GuestLinux::Cap::NetworkInterfaces" do result = cap.network_interfaces(machine) expect(result).to eq(["enp0s3", "enp0s5", "enp0s8", "bridge0", "docker0"]) end + + it "sorts ethernet devices discovered with predictable network interfaces naming first in list with less" do + expect(comm).to receive(:sudo).and_yield(:stdout, "enp0s3\nenp0s8\ndocker0") + result = cap.network_interfaces(machine) + expect(result).to eq(["enp0s3", "enp0s8", "docker0"]) + end + + it "does not include ethernet devices aliases within prefix device listing" do + expect(comm).to receive(:sudo).and_yield(:stdout, "eth1\neth2\ndocker0\nbridge0\neth0\neth0:0") + result = cap.network_interfaces(machine) + expect(result).to eq(["eth0", "eth1", "eth2", "bridge0", "docker0", "eth0:0"]) + end end end From a8970281ced199a43ca9b0a4d5b0b97aff02a2e2 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Mon, 10 Oct 2016 10:22:07 -0700 Subject: [PATCH 2/2] guests/linux: Properly sort interface name types Add failing networking interface list sorting test with example provided by #7883. Update sorting logic to properly handle different types and differing array lengths. Fixes #7883 --- .../guests/linux/cap/network_interfaces.rb | 20 ++++++++++++++++++- .../linux/cap/network_interfaces_test.rb | 10 ++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/plugins/guests/linux/cap/network_interfaces.rb b/plugins/guests/linux/cap/network_interfaces.rb index c66de24c4..9a7db83d1 100644 --- a/plugins/guests/linux/cap/network_interfaces.rb +++ b/plugins/guests/linux/cap/network_interfaces.rb @@ -23,6 +23,9 @@ module VagrantPlugins @@logger.debug("Unsorted list: #{ifaces.inspect}") # Break out integers from strings and sort the arrays to provide # a natural sort for the interface names + # NOTE: Devices named with a hex value suffix will _not_ be sorted + # as expected. This is generally seen with veth* devices, and proper ordering + # is currently not required ifaces = ifaces.map do |iface| iface.scan(/(.+?)(\d+)/).flatten.map do |iface_part| if iface_part.to_i.to_s == iface_part @@ -31,7 +34,22 @@ module VagrantPlugins iface_part end end - end.sort.map(&:join) + end + ifaces = ifaces.sort do |lhs, rhs| + result = 0 + slice_length = [rhs.size, lhs.size].min + slice_length.times do |idx| + if(lhs[idx].is_a?(rhs[idx].class)) + result = lhs[idx] <=> rhs[idx] + elsif(lhs[idx].is_a?(String)) + result = 1 + else + result = -1 + end + break if result != 0 + end + result + end.map(&:join) @@logger.debug("Sorted list: #{ifaces.inspect}") # Extract ethernet devices and place at start of list resorted_ifaces = [] diff --git a/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb b/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb index 5c6a36546..5142beaa2 100644 --- a/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb +++ b/test/unit/plugins/guests/linux/cap/network_interfaces_test.rb @@ -64,9 +64,15 @@ describe "VagrantPlugins::GuestLinux::Cap::NetworkInterfaces" do end it "does not include ethernet devices aliases within prefix device listing" do - expect(comm).to receive(:sudo).and_yield(:stdout, "eth1\neth2\ndocker0\nbridge0\neth0\neth0:0") + expect(comm).to receive(:sudo).and_yield(:stdout, "eth1\neth2\ndocker0\nbridge0\neth0\ndocker1\neth0:0") result = cap.network_interfaces(machine) - expect(result).to eq(["eth0", "eth1", "eth2", "bridge0", "docker0", "eth0:0"]) + expect(result).to eq(["eth0", "eth1", "eth2", "bridge0", "docker0", "docker1", "eth0:0"]) + end + + it "properly sorts non-consistent device name formats" do + expect(comm).to receive(:sudo).and_yield(:stdout, "eth0\neth1\ndocker0\nveth437f7f9\nveth06b3e44\nveth8bb7081") + result = cap.network_interfaces(machine) + expect(result).to eq(["eth0", "eth1", "docker0", "veth8bb7081", "veth437f7f9", "veth06b3e44"]) end end end