Blob Blame History Raw
From 0364a677080c45e14ba2f503d96c34ff33ae0f39 Mon Sep 17 00:00:00 2001
From: Gilles Dubreuil <gilles@redhat.com>
Date: Mon, 16 Nov 2015 16:55:28 +1100
Subject: [PATCH] Adds IPv6 support for interface_for_ip function

Proper interface matching when an IPv6 address is provided.

If Facter version used is < 3 then it adds the netmask6 facts as custom facts.

Fix bugs https://bugzilla.redhat.com/show_bug.cgi?id=1280523

Change-Id: Ide26ca1740dc12ea5f47a28f4cecacd6ef0b18f9
---
 tripleo/lib/facter/netmask_ipv6.rb                 | 47 ++++++++++++++++++++++
 .../puppet/parser/functions/interface_for_ip.rb    | 32 +++++++++------
 2 files changed, 66 insertions(+), 13 deletions(-)
 create mode 100644 tripleo/lib/facter/netmask_ipv6.rb

diff --git a/tripleo/lib/facter/netmask_ipv6.rb b/tripleo/lib/facter/netmask_ipv6.rb
new file mode 100644
index 0000000..5261485
--- /dev/null
+++ b/tripleo/lib/facter/netmask_ipv6.rb
@@ -0,0 +1,47 @@
+require 'ipaddr'
+
+def netmask6(value)
+  if value
+    ip = IPAddr.new('::0').mask(value)
+    ip.inspect.split('/')[1].gsub('>', '')
+  end
+end
+
+if Facter.value('facterversion')[0].to_i < 3
+  Facter::Util::IP.get_interfaces.each do |interface|
+    Facter.add('netmask6_' + Facter::Util::IP.alphafy(interface)) do
+      setcode do
+        tmp = []
+        regex = %r{inet6\s+.*\s+(?:prefixlen)\s+(\d+)}x
+        output_int = Facter::Util::IP.get_output_for_interface_and_label(interface, 'netmask6')
+
+        output_int.each_line do |line|
+          prefixlen = nil
+          matches = line.match(regex)
+          prefixlen = matches[1] if matches
+
+          if prefixlen
+            value = netmask6(prefixlen)
+            tmp.push(value)
+          end
+        end
+
+        tmp.shift if tmp
+      end
+    end
+  end
+
+  Facter.add('netmask6') do
+    setcode do
+      prefixlen = nil
+      regex = %r{#{Facter.value(:ipaddress6)}.*?(?:prefixlen)\s*(\d+)}x
+
+      String(Facter::Util::IP.exec_ifconfig(['2>/dev/null'])).split(/\n/).collect do |line|
+        matches = line.match(regex)
+        prefixlen = matches[1] if matches
+      end
+
+      netmask6(prefixlen) if prefixlen
+    end
+  end
+end
diff --git a/tripleo/lib/puppet/parser/functions/interface_for_ip.rb b/tripleo/lib/puppet/parser/functions/interface_for_ip.rb
index 1c67120..fd68be0 100644
--- a/tripleo/lib/puppet/parser/functions/interface_for_ip.rb
+++ b/tripleo/lib/puppet/parser/functions/interface_for_ip.rb
@@ -8,25 +8,31 @@ module Puppet::Parser::Functions
   newfunction(:interface_for_ip, :type => :rvalue, :doc => "Find the bind IP address for the provided subnet.") do |arg|
     if arg[0].class == String
       begin
-        ip_to_find = arg[0]
+        ip1 = IPAddr.new(arg[0])
         Dir.foreach('/sys/class/net/') do |interface|
-          next if interface == '.' or interface == '..'
+          next if interface == '.' || interface == '..'
           iface_no_dash = interface.gsub('-', '_')
-          interface_ip = lookupvar("ipaddress_#{iface_no_dash}")
-          netmask = lookupvar("netmask_#{iface_no_dash}")
-          if not interface_ip.nil? then
-            ip1=IPAddr.new(interface_ip)
-            ip2=IPAddr.new(ip_to_find)
-            if ip1.mask(netmask) == ip2.mask(netmask) then
-              return interface
-            end
+
+          if ip1.ipv4?
+            ipaddress_name = "ipaddress_#{iface_no_dash}"
+            netmask_name   = "netmask_#{iface_no_dash}"
+          else
+            ipaddress_name = "ipaddress6_#{iface_no_dash}"
+            netmask_name   = "netmask6_#{iface_no_dash}"
+          end
+
+          interface_ip = lookupvar(ipaddress_name)
+          netmask = lookupvar(netmask_name)
+          unless interface_ip.nil? then
+            ip2 = IPAddr.new(interface_ip)
+            return interface if ip1.mask(netmask) == ip2.mask(netmask)
           end
         end
-      rescue JSON::ParserError
-        raise Puppet::ParseError, "Syntax error: #{arg[0]} is invalid"
+      rescue IPAddr::InvalidAddressError => e
+        raise Puppet::ParseError, "#{e}: #{arg[0]}"
       end
     else
-      raise Puppet::ParseError, "Syntax error: #{arg[0]} is not a String"
+      raise Puppet::ParseError, "Syntax error: #{arg[0]} must be a String"
     end
     return ''
   end