Bug #4498

ipaddress* facts do not include secondary IPs

Added by martin krafft almost 3 years ago. Updated 11 months ago.

Status:DuplicateStart date:08/08/2010
Priority:NormalDue date:
Assignee:-% Done:

0%

Category:library
Target version:-
Keywords: Affected Facter version:
Branch:

Description

I can add as many IP addresses to an interface (at least on Linux), using iproute2. However, since facter uses the horrific ifconfig command to scan for and obtain interface information, it does not see those additional interfaces (ifconfig needed the interface alias hack).

I am going to start working on a patch to swap ifconfig for iproute2 on Linux.


Related issues

Related to Facter - Bug #5816: ipaddress fact uses the IP of the alphabetically earliest... Duplicate 01/09/2011
Duplicates Facter - Bug #1346: Using 'ip addr' over ifconfig Code Insufficient 06/03/2008
Duplicates Facter - Bug #1574: ipaddress fact does not show all IP addresses when using ... Duplicate 09/12/2008

History

#1 Updated by Paul Nasrat almost 3 years ago

If you are doing this please post to list for design discussion as early as possible.

Note my preferred method to move to would be probably to read procfs/sysfs to enumerate the devices and support iproute2 and falling back to ifconfig.

I also want to completely rework how they are represented so we can provide richer objects to puppet for 2.0.

#2 Updated by Paul Nasrat almost 3 years ago

  • Target version set to 1.6.0

#3 Updated by Paul Nasrat almost 3 years ago

  • Status changed from Unreviewed to Duplicate
  • Target version changed from 1.6.0 to 14

Duplicate of bug 1346

#4 Updated by martin krafft almost 3 years ago

  • Assignee deleted (martin krafft)

Here is my patch as a basis:

index 5ad9658..7682a04 100644
--- a/files/util/ip.rb
+++ b/files/util/ip.rb
@@ -5,9 +5,9 @@ module Facter::Util::IP
     # a given platform or set of platforms.
     REGEX_MAP = {
         :linux => {
-            :ipaddress  => /inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/,
-            :macaddress => /(?:ether|HWaddr)\s+(\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/,
-            :netmask    => /Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
+            :ipaddress  => /\s+inet ((?:\d+\.){3}\d+)\/\d+(?: brd (?:\d+\.){3}\d+)? scope global/,
+            :macaddress => /\s+link\/\S+ ((?:[0-9a-f]{2}:){5}:[0-9a-f]{2}) brd (?:[0-9a-f]{2}:){5}:[0-9a-f]{2}/,
+            :netmask    => /\s+inet (?:(?:\d+\.){3}\d+)\/(\d+)(?: brd (?:\d+\.){3}\d+)? scope global/
         },
         :bsd   => {
             :aliases    => [:openbsd, :netbsd, :freebsd, :darwin],
@@ -32,6 +32,11 @@ module Facter::Util::IP
         kernels_to_convert.include?(kernel)
     end
 
+    def self.convert_from_prefixlen?(kernel)
+        kernels_to_convert = [:linux]
+        kernels_to_convert.include?(kernel)
+    end
+
     def self.supported_platforms
         REGEX_MAP.inject([]) do |result, tmp|
             key, map = tmp
@@ -56,7 +61,9 @@ module Facter::Util::IP
 
     def self.get_all_interface_output
         case Facter.value(:kernel)
-        when 'Linux', 'OpenBSD', 'NetBSD', 'FreeBSD', 'Darwin'
+        when 'Linux'
+            output = %x{/bin/ip addr list}.gsub(/^\d+:\s+/, '')
+        when 'OpenBSD', 'NetBSD', 'FreeBSD', 'Darwin'
             output = %x{/sbin/ifconfig -a}
         when 'SunOS'
             output = %x{/usr/sbin/ifconfig -a}
@@ -67,7 +74,9 @@ module Facter::Util::IP
     def self.get_single_interface_output(interface)
         output = ""
         case Facter.value(:kernel)
-        when 'Linux', 'OpenBSD', 'NetBSD', 'FreeBSD', 'Darwin'
+        when 'Linux'
+            output = %x{/bin/ip addr list dev #{interface}}.gsub(/^\d+:\s+/, '')
+        when 'OpenBSD', 'NetBSD', 'FreeBSD', 'Darwin'
             output = %x{/sbin/ifconfig #{interface}}
         when 'SunOS'
             output = %x{/usr/sbin/ifconfig #{interface}}
@@ -130,8 +139,17 @@ module Facter::Util::IP
                 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('.')
+                        if label == 'netmask'
+                            convert_from_hex = convert_from_hex?(kernel)
+                            if convert_from_prefixlen?(kernel)
+                                hostmaxlen = 32-value.to_i
+                                value = ((0xffffffff >> hostmaxlen) << hostmaxlen).to_s(16)
+                                convert_from_hex = true
+                            end
+
+                            if convert_from_hex
+                                value = value.scan(/../).collect do |byte| byte.to_i(16) end.join('.')
+                            end
                         end
                         tmp1.push(value)
                     end

And then the one that actually implements multiple returns with a compatibility interface:

diff --git a/files/interfaces.rb b/files/interfaces.rb
index 1239215..67e6ead 100644
--- a/files/interfaces.rb
+++ b/files/interfaces.rb
@@ -25,7 +25,7 @@ Facter::Util::IP.get_interfaces.each do |interface|
     %w{ipaddress macaddress netmask}.each do |label|
         Facter.add(label + "_" + Facter::Util::IP.alphafy(interface)) do
             setcode do
-                Facter::Util::IP.get_interface_value(interface, label)
+                Facter::Util::IP.get_interface_values(interface, label).join(',')
             end
         end
     end
diff --git a/files/network.rb b/files/network.rb
index df53ce4..02ee94c 100644
--- a/files/network.rb
+++ b/files/network.rb
@@ -3,7 +3,7 @@ require 'facter/util/ip'
 Facter::Util::IP.get_interfaces.each do |interface|
     Facter.add("network_" + Facter::Util::IP.alphafy(interface)) do
         setcode do
-            Facter::Util::IP.get_network_value(interface)
+            Facter::Util::IP.get_network_values(interface).join(',')
         end 
     end 
 end
diff --git a/files/util/ip.rb b/files/util/ip.rb
index 7682a04..7b29afb 100644
--- a/files/util/ip.rb
+++ b/files/util/ip.rb
@@ -111,7 +111,7 @@ module Facter::Util::IP
     end
 
 
-    def self.get_interface_value(interface, label)
+    def self.get_interface_values(interface, label)
         tmp1 = []
 
         kernel = Facter.value(:kernel).downcase.to_sym
@@ -157,21 +157,35 @@ module Facter::Util::IP
             end
 
             if tmp1
-                value = tmp1.shift
+                value = tmp1
             end
         end
     end
+    def self.get_interface_value(interface, label)
+        # compatibility interface
+        self.get_interface_values(interface, label).shift
+    end
   
-    def self.get_network_value(interface)
+    def self.get_network_values(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
+        ipaddresses = get_interface_values(interface, "ipaddress")
+        netmasks = get_interface_values(interface, "netmask")
+        ret = []
+        ipaddresses.zip(netmasks) { |pair|
+            if pair[0] && pair[1]
+                ip = IPAddr.new(pair[0], Socket::AF_INET)
+                subnet = IPAddr.new(pair[1], Socket::AF_INET)
+                network = ip.mask(subnet.to_s).to_s
+                ret.push(network)
+            end
+        }
+        if ret
+            value = ret
         end
     end
+    def self.get_network_value(interface)
+        # compatibility interface
+        self.get_network_values(interface).shift
+    end
 end

Of course, having ifconfig would be good for fallback.

One issue not addressed in the above are bonded interfaces. Those show up with the @ sign in the iface name. This actually causes problems with now, e.g.:

4: sixxs@NONE:  mtu 1480 qdisc noqueue state UNKNOWN 
    link/sit 0.0.0.0 peer 213.144.148.74
    inet6 2001:1620:f08::1/128 scope global 
       valid_lft forever preferred_lft forever

#5 Updated by martin krafft almost 3 years ago

  • Status changed from Duplicate to Re-opened

Please don’t delete, I’ll mark it a duplicate…

#6 Updated by martin krafft almost 3 years ago

  • Status changed from Re-opened to Code Insufficient

#7 Updated by James Turnbull almost 2 years ago

  • Category set to library

#8 Updated by Ken Barber over 1 year ago

  • Target version changed from 14 to 186

#9 Updated by Daniel Pittman over 1 year ago

  • Target version deleted (186)

#10 Updated by Andrew Parker 11 months ago

  • Status changed from Code Insufficient to Duplicate

This is being taken care of in #1346.

Also available in: Atom PDF