module Facter::Util::IP

A base module for collecting IP-related information from all kinds of platforms.

Constants

REGEX_MAP

A map of all the different regexes that work for a given platform or set of platforms.

Public Class Methods

aix_entstat_interface(interface) click to toggle source
# File lib/facter/util/ip.rb, line 197
def self.aix_entstat_interface(interface)
  if interface[0..1] != "lo"
    Facter::Core::Execution.exec("/usr/bin/entstat #{interface}")
  else
    return ""
  end
end
aix_get_macadress(interface) click to toggle source
# File lib/facter/util/ip.rb, line 213
def self.aix_get_macadress(interface)
  aix_entstat_interface(interface).each_line do |s|
    if s =~ /^Hardware\sAddress:\s(\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/
      return s
    end
  end
end
aix_get_mtu(interface) click to toggle source
# File lib/facter/util/ip.rb, line 205
def self.aix_get_mtu(interface)
  aix_lsattr_interface(interface).each_line do |s|
    if s =~ /mtu\s+(\d+)/
      return s
    end
  end
end
aix_lsattr_interface(interface) click to toggle source
# File lib/facter/util/ip.rb, line 193
def self.aix_lsattr_interface(interface)
  Facter::Core::Execution.exec("/usr/sbin/lsattr -El #{interface}")
end
alphafy(interface) click to toggle source

Convert an interface name into purely alphanumeric characters.

# File lib/facter/util/ip.rb, line 45
def self.alphafy(interface)
  interface.gsub(/[^a-z0-9_]/i, '_')
end
convert_from_hex?(kernel) click to toggle source
# File lib/facter/util/ip.rb, line 49
def self.convert_from_hex?(kernel)
  kernels_to_convert = [:sunos, :openbsd, :netbsd, :freebsd, :darwin, :"hp-ux", :"gnu/kfreebsd", :dragonfly, :aix]
  kernels_to_convert.include?(kernel)
end
exec_ifconfig(additional_arguments=[]) click to toggle source

::exec_ifconfig uses the ifconfig command

@return [String] the output of `ifconfig #{arguments} 2>/dev/null` or nil

# File lib/facter/util/ip.rb, line 105
def self.exec_ifconfig(additional_arguments=[])
  Facter::Core::Execution.exec("#{self.get_ifconfig} #{additional_arguments.join(' ')}")
end
exec_netstat(additional_arguments=[]) click to toggle source

::exec_netstat uses the netstat command

@return [String] the output of `netstat #{arguments} 2>/dev/null` or nil

# File lib/facter/util/ip.rb, line 121
def self.exec_netstat(additional_arguments=[])
  Facter::Core::Execution.exec("#{self.get_netstat} #{additional_arguments.join(' ')}")
end
get_all_interface_output() click to toggle source
# File lib/facter/util/ip.rb, line 81
def self.get_all_interface_output
  case Facter.value(:kernel)
  when 'Linux', 'OpenBSD', 'NetBSD', 'FreeBSD', 'Darwin', 'GNU/kFreeBSD', 'DragonFly', 'AIX'
    output = Facter::Util::IP.exec_ifconfig(["-a","2>/dev/null"])
  when 'SunOS'
    output = Facter::Util::IP.exec_ifconfig(["-a"])
  when 'HP-UX'
    # (#17487)[https://projects.puppetlabs.com/issues/17487]
    # Handle NIC bonding where asterisks and virtual NICs are printed.
    if output = hpux_netstat_in
      output.gsub!(/\*/, "")                  # delete asterisks.
      output.gsub!(/^[^\n]*none[^\n]*\n/, "") # delete lines with 'none' instead of IPs.
      output.sub!(/^[^\n]*\n/, "")            # delete the header line.
      output
    end
  end
  output
end
get_bonding_master(interface) click to toggle source
# File lib/facter/util/ip.rb, line 229
def self.get_bonding_master(interface)
  if Facter.value(:kernel) != 'Linux'
    return nil
  end
  # We need ip instead of ifconfig because it will show us
  # the bonding master device.
  if not FileTest.executable?("/sbin/ip")
    return nil
  end
  # A bonding interface can never be an alias interface. Alias
  # interfaces do have a colon in their name and the ip link show
  # command throws an error message when we pass it an alias
  # interface.
  if interface =~ /:/
    return nil
  end
  regex = /SLAVE[,>].* (bond[0-9]+)/
    ethbond = regex.match(%x{/sbin/ip link show '#{interface}'})
  if ethbond
    device = ethbond[1]
  else
    device = nil
  end
  device
end
get_ifconfig() click to toggle source

::get_ifconfig looks up the ifconfig binary

@return [String] path to the ifconfig binary

# File lib/facter/util/ip.rb, line 112
def self.get_ifconfig
  common_paths=["/bin/ifconfig","/sbin/ifconfig","/usr/sbin/ifconfig"]
  common_paths.select{|path| File.executable?(path)}.first
end
get_infiniband_macaddress(interface) click to toggle source
# File lib/facter/util/ip.rb, line 140
def self.get_infiniband_macaddress(interface)
  if File.exists?("/sys/class/net/#{interface}/address") then
    ib_mac_address = %x`cat /sys/class/net/#{interface}/address`.chomp
  elsif File.exists?("/sbin/ip") then
    ip_output = %x{/sbin/ip link show '#{interface}'}
    ib_mac_address = ip_output.scan(%r{infiniband\s+((\w{1,2}:){5,}\w{1,2})})
  else
    ib_mac_address = "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF"
    Facter.debug("ip.rb: nothing under /sys/class/net/#{interface}/address and /sbin/ip not available")
  end
  ib_mac_address
end
get_interface_value(interface, label) click to toggle source

::get_interface_value obtains the value of a specific attribute of a specific interface.

@param interface [String] the interface identifier, e.g. “eth0” or “bond0”

@param label [String] the attribute of the interface to obtain a value for, e.g. “netmask” or “ipaddress”

@api private

@return [String] representing the requested value. An empty array is returned if the kernel is not supported by the REGEX_MAP constant.

# File lib/facter/util/ip.rb, line 268
def self.get_interface_value(interface, label)
  if Facter.value(:kernel) == 'windows'
    require 'facter/util/ip/windows'
    return Facter::Util::IP::Windows.value_for_interface_and_label(interface, label)
  end

  tmp1 = []

  kernel = Facter.value(:kernel).downcase.to_sym

  # If it's not directly in the map or aliased in the map, then we don't know how to deal with it.
  unless map = REGEX_MAP[kernel] || REGEX_MAP.values.find { |tmp| tmp[:aliases] and tmp[:aliases].include?(kernel) }
    return []
  end

  # Pull the correct regex out of the map.
  regex = map[label.to_sym]

  # Linux changes the MAC address reported via ifconfig when an ethernet interface
  # becomes a slave of a bonding device to the master MAC address.
  # We have to dig a bit to get the original/real MAC address of the interface.
  bonddev = get_bonding_master(interface)
  if label == 'macaddress' and bonddev
    bondinfo = read_proc_net_bonding("/proc/net/bonding/#{bonddev}")
    re = /^Slave Interface: #{interface}\b.*?\bPermanent HW addr: (([0-9A-F]{2}:?)*)$/im
    if match = re.match(bondinfo)
      value = match[1].upcase
    end
  else
    output_int = get_output_for_interface_and_label(interface, label)

    output_int.each_line do |s|
      if s =~ regex
        value = $1
          if label == 'netmask' && convert_from_hex?(kernel)
            value = value.scan(/../).collect do |byte| byte.to_i(16) end.join('.')
          end
        tmp1.push(value)
      end
    end

    if tmp1
      value = tmp1.shift
    end
  end
end
get_interfaces() click to toggle source
# File lib/facter/util/ip.rb, line 66
def self.get_interfaces
  if Facter.value(:kernel) == 'windows'
    require 'facter/util/ip/windows'
    return Facter::Util::IP::Windows.interfaces
  end

  return [] unless output = Facter::Util::IP.get_all_interface_output()

  # Our regex appears to be stupid, in that it leaves colons sitting
  # at the end of interfaces.  So, we have to trim those trailing
  # characters.  I tried making the regex better but supporting all
  # platforms with a single regex is probably a bit too much.
  output.scan(/^\S+/).collect { |i| i.sub(/:$/, '') }.uniq
end
get_netstat() click to toggle source

::get_netstat looks up the netstat binary

@return [String] path to the netstat binary

# File lib/facter/util/ip.rb, line 128
def self.get_netstat
  common_paths=["/bin/netstat","/sbin/netstat","/usr/sbin/netstat","/usr/bin/netstat"]
  common_paths.select{|path| File.executable?(path)}.first
end
get_network_value(interface) click to toggle source
# File lib/facter/util/ip.rb, line 328
def self.get_network_value(interface)
  require 'ipaddr'

  ipaddress = get_interface_value(interface, "ipaddress")
  netmask = get_interface_value(interface, "netmask")

  if ipaddress && netmask
    ip = IPAddr.new(ipaddress, Socket::AF_INET)
    subnet = IPAddr.new(netmask, Socket::AF_INET)
    network = ip.mask(subnet.to_s).to_s
  end
end
get_output_for_interface_and_label(interface, label) click to toggle source
# File lib/facter/util/ip.rb, line 221
def self.get_output_for_interface_and_label(interface, label)
  return get_single_interface_output(interface) unless Facter.value(:kernel) == 'windows'

  require 'facter/util/ip/windows'
  output = Facter::Util::IP::Windows.value_for_interface_and_label(interface, label)
  output ? output : ""
end
get_single_interface_output(interface) click to toggle source
# File lib/facter/util/ip.rb, line 157
def self.get_single_interface_output(interface)
  output = ""
  case Facter.value(:kernel)
  when 'OpenBSD', 'NetBSD', 'FreeBSD', 'Darwin', 'GNU/kFreeBSD', 'DragonFly'
    output = Facter::Util::IP.ifconfig_interface(interface)
  when 'Linux'
    ifconfig_output = Facter::Util::IP.ifconfig_interface(interface)
    if interface =~ /^ib/ then
      real_mac_address = get_infiniband_macaddress(interface)
      output = ifconfig_output.sub(%r{(?:ether|HWaddr)\s+((\w{1,2}:){5,}\w{1,2})}, "HWaddr #{real_mac_address}")
    else
      output = ifconfig_output
    end
  when 'SunOS'
    output = Facter::Util::IP.exec_ifconfig([interface])
  when 'HP-UX'
     mac = ""
     ifc = hpux_ifconfig_interface(interface)
     hpux_lanscan.scan(/(\dx\S+).*UP\s+(\w+\d+)/).each {|i| mac = i[0] if i.include?(interface) }
     mac = mac.sub(/0x(\S+)/,'\1').scan(/../).join(":")
     output = ifc + "\n" + mac
  when 'AIX'
      output = Facter::Util::IP.ifconfig_interface(interface) + "\n" + aix_get_mtu(interface) + "\n" + aix_get_macadress(interface)
      output
  end
  output
end
hpux_ifconfig_interface(interface) click to toggle source
# File lib/facter/util/ip.rb, line 185
def self.hpux_ifconfig_interface(interface)
  Facter::Util::IP.exec_ifconfig([interface])
end
hpux_lanscan() click to toggle source
# File lib/facter/util/ip.rb, line 189
def self.hpux_lanscan
  Facter::Core::Execution.exec("/usr/sbin/lanscan")
end
hpux_netstat_in() click to toggle source

::hpux_netstat_in is a delegate method that allows us to stub netstat -in without stubbing exec.

# File lib/facter/util/ip.rb, line 136
def self.hpux_netstat_in
  Facter::Core::Execution.exec("/bin/netstat -in")
end
ifconfig_interface(interface) click to toggle source
# File lib/facter/util/ip.rb, line 153
def self.ifconfig_interface(interface)
  output = Facter::Util::IP.exec_ifconfig(["'#{interface}'","2>/dev/null"])
end
supported_platforms() click to toggle source
# File lib/facter/util/ip.rb, line 54
def self.supported_platforms
  REGEX_MAP.inject([]) do |result, tmp|
    key, map = tmp
    if map[:aliases]
      result += map[:aliases]
    else
      result << key
    end
    result
  end
end

Private Class Methods

read_proc_net_bonding(path) click to toggle source

::read_proc_net_bonding is a seam method for mocking purposes.

@param path [String] representing the path to read, e.g. “/proc/net/bonding/bond0”

@api private

@return [String] modeling the raw file read

# File lib/facter/util/ip.rb, line 323
def self.read_proc_net_bonding(path)
  File.read(path) if File.exists?(path)
end