2016-06-23 02:08:02 +00:00
|
|
|
module VagrantPlugins
|
|
|
|
module GuestLinux
|
|
|
|
module Cap
|
|
|
|
class NetworkInterfaces
|
2016-09-29 22:33:29 +00:00
|
|
|
# Valid ethernet device prefix values.
|
|
|
|
# eth - classic prefix
|
|
|
|
# en - predictable interface names prefix
|
2016-09-30 19:11:54 +00:00
|
|
|
POSSIBLE_ETHERNET_PREFIXES = ["eth".freeze, "en".freeze].freeze
|
2016-09-29 22:33:29 +00:00
|
|
|
|
2016-08-12 00:01:36 +00:00
|
|
|
@@logger = Log4r::Logger.new("vagrant::guest::linux::network_interfaces")
|
|
|
|
|
2016-06-23 02:08:02 +00:00
|
|
|
# Get network interfaces as a list. The result will be something like:
|
|
|
|
#
|
|
|
|
# eth0\nenp0s8\nenp0s9
|
|
|
|
#
|
|
|
|
# @return [Array<String>]
|
2016-06-26 15:41:16 +00:00
|
|
|
def self.network_interfaces(machine, path = "/sbin/ip")
|
2016-06-23 02:08:02 +00:00
|
|
|
s = ""
|
2016-06-26 15:41:16 +00:00
|
|
|
machine.communicate.sudo("#{path} -o -0 addr | grep -v LOOPBACK | awk '{print $2}' | sed 's/://'") do |type, data|
|
2016-06-23 02:08:02 +00:00
|
|
|
s << data if type == :stdout
|
|
|
|
end
|
2018-08-03 17:48:28 +00:00
|
|
|
|
2017-04-24 15:53:45 +00:00
|
|
|
# In some cases net devices may be added to the guest and will not
|
|
|
|
# properly show up when using `ip`. This pulls any device information
|
|
|
|
# that can be found in /proc and adds it to the list of interfaces
|
|
|
|
s << "\n"
|
|
|
|
machine.communicate.sudo("cat /proc/net/dev | grep -E '^[a-z0-9 ]+:' | awk '{print $1}' | sed 's/://'", error_check: false) do |type, data|
|
|
|
|
s << data if type == :stdout
|
|
|
|
end
|
2018-08-03 17:48:28 +00:00
|
|
|
|
|
|
|
# Collect all loopback interfaces
|
|
|
|
los = ""
|
|
|
|
machine.communicate.sudo("#{path} -o -0 addr | grep LOOPBACK | awk '{print $2}' | sed 's/://'") do |type, data|
|
|
|
|
los << data if type == :stdout
|
|
|
|
end
|
|
|
|
loifaces = los.split("\n")
|
|
|
|
@@logger.debug("loopback interfaces: #{loifaces.inspect}")
|
|
|
|
|
|
|
|
ifaces = s.split("\n").reject { |x| x.empty? or loifaces.include?(x) }
|
|
|
|
|
2016-08-12 00:01:36 +00:00
|
|
|
@@logger.debug("Unsorted list: #{ifaces.inspect}")
|
|
|
|
# Break out integers from strings and sort the arrays to provide
|
|
|
|
# a natural sort for the interface names
|
2016-10-10 17:22:07 +00:00
|
|
|
# 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
|
2016-08-12 00:01:36 +00:00
|
|
|
ifaces = ifaces.map do |iface|
|
2018-08-03 17:48:28 +00:00
|
|
|
iface.scan(/(.+?)(\d+)?/).flatten.map do |iface_part|
|
2016-08-12 00:01:36 +00:00
|
|
|
if iface_part.to_i.to_s == iface_part
|
|
|
|
iface_part.to_i
|
|
|
|
else
|
|
|
|
iface_part
|
|
|
|
end
|
|
|
|
end
|
2016-10-10 17:22:07 +00:00
|
|
|
end
|
2017-04-24 15:53:45 +00:00
|
|
|
ifaces = ifaces.uniq.sort do |lhs, rhs|
|
2016-10-10 17:22:07 +00:00
|
|
|
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)
|
2016-08-12 00:01:36 +00:00
|
|
|
@@logger.debug("Sorted list: #{ifaces.inspect}")
|
2016-09-29 22:33:29 +00:00
|
|
|
# Extract ethernet devices and place at start of list
|
2016-10-05 00:25:00 +00:00
|
|
|
resorted_ifaces = []
|
|
|
|
resorted_ifaces += ifaces.find_all do |iface|
|
|
|
|
POSSIBLE_ETHERNET_PREFIXES.any?{|prefix| iface.start_with?(prefix)} &&
|
2016-11-10 15:19:26 +00:00
|
|
|
iface.match(/^[a-zA-Z0-9]+$/)
|
2016-09-29 22:33:29 +00:00
|
|
|
end
|
2016-10-05 00:25:00 +00:00
|
|
|
resorted_ifaces += ifaces - resorted_ifaces
|
|
|
|
ifaces = resorted_ifaces
|
|
|
|
@@logger.debug("Ethernet preferred sorted list: #{ifaces.inspect}")
|
2016-08-12 00:01:36 +00:00
|
|
|
ifaces
|
2016-06-23 02:08:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|