[Pkg-puppet-devel] [facter] 32/61: (#16668) Use WMI to collect IPv6 address

Stig Sandbeck Mathisen ssm at debian.org
Mon Nov 4 15:01:55 UTC 2013


This is an automated email from the git hooks/post-receive script.

ssm pushed a commit to branch master
in repository facter.

commit 66d8c80575e167946e72f8b0004ce79e0d1baf6b
Author: Rob Reynolds <rob at puppetlabs.com>
Date:   Wed Jul 24 17:12:03 2013 -0700

    (#16668) Use WMI to collect IPv6 address
    
    Previously, we were using netsh.exe to collect the ipaddress6 fact, but it
    relied on en_US output that wasn't internationalizable.
    
    This commit uses WMI, like the ipaddress fact, and handles issues like
    multiple NICs, both IPv4 and IPv6 IP addresses on a single NIC,
    per-interface metrics, and the binding order of interfaces.
---
 lib/facter/ipaddress6.rb      |   15 ++++-
 lib/facter/util/ip/windows.rb |   18 +++++
 spec/unit/ipaddress6_spec.rb  |  145 ++++++++++++++++++++++++++++++++++++++---
 3 files changed, 167 insertions(+), 11 deletions(-)

diff --git a/lib/facter/ipaddress6.rb b/lib/facter/ipaddress6.rb
index 4e44d13..559088b 100644
--- a/lib/facter/ipaddress6.rb
+++ b/lib/facter/ipaddress6.rb
@@ -26,7 +26,7 @@ require 'facter/util/ip'
 def get_address_after_token(output, token, return_first=false)
   ip = nil
 
-  String(output).scan(/#{token} ((?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4})/).each do |match|
+  String(output).scan(/#{token}\s?((?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4})/).each do |match|
     match = match.first
     unless match =~ /fe80.*/ or match == "::1"
       ip = match
@@ -66,8 +66,17 @@ end
 Facter.add(:ipaddress6) do
   confine :kernel => :windows
   setcode do
-    output = Facter::Util::Resolution.exec("#{ENV['SYSTEMROOT']}/system32/netsh.exe interface ipv6 show address level=verbose")
+    require 'facter/util/ip/windows'
+    ipaddr = nil
 
-    get_address_after_token(output, 'Address', true)
+    adapters = Facter::Util::IP::Windows.get_preferred_network_adapters
+    adapters.find do |nic|
+      nic.IPAddress.any? do |addr|
+        ipaddr = addr if Facter::Util::IP::Windows.valid_ipv6_address?(addr)
+        ipaddr
+      end
+    end
+
+    ipaddr
   end
 end
diff --git a/lib/facter/util/ip/windows.rb b/lib/facter/util/ip/windows.rb
index 11ce6ec..3030d30 100644
--- a/lib/facter/util/ip/windows.rb
+++ b/lib/facter/util/ip/windows.rb
@@ -104,4 +104,22 @@ class Facter::Util::IP::Windows
 
     nil
   end
+
+  # Determines if the value passed in is a valid ipv6 address.
+  #
+  # @param ip_address [String]
+  #
+  # @return [String] or [NilClass]
+  #
+  # @api private
+  def self.valid_ipv6_address?(ip_address)
+    String(ip_address).scan(/(?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4}/).each do |match|
+      unless match =~ /fe80.*/ or match == "::1"
+        return match
+      end
+    end
+
+    nil
+  end
+
 end
diff --git a/spec/unit/ipaddress6_spec.rb b/spec/unit/ipaddress6_spec.rb
index 54e553d..e46ef86 100755
--- a/spec/unit/ipaddress6_spec.rb
+++ b/spec/unit/ipaddress6_spec.rb
@@ -12,7 +12,7 @@ def netsh_fixture(filename)
 end
 
 
-describe "IPv6 address fact" do
+describe "The IPv6 address fact" do
   include FacterSpec::ConfigHelper
 
   before do
@@ -55,14 +55,143 @@ describe "IPv6 address fact" do
     Facter.value(:ipaddress6).should == "2610:10:20:209:203:baff:fe27:a7c"
   end
 
-  it "should return ipaddress6 information for Windows" do
-    ENV.stubs(:[]).with('SYSTEMROOT').returns('d:/windows')
-    given_a_configuration_of(:is_windows => true)
+  context "on Windows" do
+    require 'facter/util/wmi'
+    require 'facter/util/registry'
+    require 'facter/util/ip/windows'
 
-    fixture = netsh_fixture('windows_netsh_addresses_with_multiple_interfaces')
-    Facter::Util::Resolution.stubs(:exec).with('d:/windows/system32/netsh.exe interface ipv6 show address level=verbose').
-      returns(fixture)
+    let(:settingId0) { '{4AE6B55C-6DD6-427D-A5BB-13535D4BE926}' }
+    let(:settingId1) { '{38762816-7957-42AC-8DAA-3B08D0C857C7}' }
+    let(:nic_bindings) { ["\\Device\\#{settingId0}", "\\Device\\#{settingId1}" ] }
 
-    Facter.value(:ipaddress6).should == "2001:0:4137:9e76:2087:77a:53ef:7527"
+    before :each do
+      Facter.fact(:kernel).stubs(:value).returns(:windows)
+      Facter::Util::Registry.stubs(:hklm_read).returns(nic_bindings)
+      given_a_configuration_of(:is_windows => true)
+    end
+
+    it "should do what when VPN is turned on?"
+
+    context "when you have no active network adapter" do
+      it "should return nil if there are no active (or any) network adapters" do
+        Facter::Util::WMI.expects(:execquery).with(Facter::Util::IP::Windows::WMI_IP_INFO_QUERY).returns([])
+
+        Facter.value(:ipaddress6).should == nil
+      end
+    end
+
+    context "when you have one network adapter" do
+      it "should return empty if ipv6 is not on" do
+        network1 = mock('network1', :IPAddress => ["12.123.12.12"])
+        Facter::Util::WMI.expects(:execquery).returns([network1])
+
+        Facter.value(:ipaddress6).should == nil
+      end
+
+      it "should return the ipv6 address properly" do
+        network1 = mock('network1', :IPAddress => ["12.123.12.12", "2011:0:4137:9e76:2087:77a:53ef:7527"])
+        Facter::Util::WMI.expects(:execquery).returns([network1])
+
+        Facter.value(:ipaddress6).should == "2011:0:4137:9e76:2087:77a:53ef:7527"
+      end
+
+      it "should return the first ipv6 address if there is more than one (multi-homing)" do
+        network1 = mock('network1', :IPAddress => ["12.123.12.12", "2013:0:4137:9e76:2087:77a:53ef:7527", "2011:0:4137:9e76:2087:77a:53ef:7527"])
+        Facter::Util::WMI.expects(:execquery).returns([network1])
+
+        Facter.value(:ipaddress6).should == "2013:0:4137:9e76:2087:77a:53ef:7527"
+      end
+
+      it "should return return nil if the ipv6 address is link local" do
+        network1 = mock('network1', :IPAddress => ["12.123.12.12", "fe80::2db2:5b42:4e30:b508"])
+        Facter::Util::WMI.expects(:execquery).returns([network1])
+
+        Facter.value(:ipaddress6).should == nil
+      end
+    end
+
+    context "when you have more than one network adapter" do
+      it "should return empty if ipv6 is not on" do
+        network1 = mock('network1')
+        network1.expects(:SettingID).returns(settingId0)
+        network1.expects(:IPConnectionMetric).returns(10)
+        network1.expects(:IPAddress).returns(["12.123.12.12"])
+        network2 = mock('network2')
+        network2.expects(:SettingID).returns(settingId1)
+        network2.expects(:IPConnectionMetric).returns(10)
+        network2.expects(:IPAddress).returns(["12.123.12.13"])
+        Facter::Util::WMI.expects(:execquery).returns([network1, network2])
+
+        Facter.value(:ipaddress6).should == nil
+      end
+
+      it "should return the ipv6 of the adapter with the lowest IP connection metric (best connection)" do
+        network1 = mock('network1')
+        network1.expects(:IPConnectionMetric).returns(10)
+        network2 = mock('network2')
+        network2.expects(:IPConnectionMetric).returns(5)
+        network2.expects(:IPAddress).returns(["12.123.12.13", "2013:0:4137:9e76:2087:77a:53ef:7527"])
+        Facter::Util::WMI.expects(:execquery).returns([network1, network2])
+
+        Facter.value(:ipaddress6).should == "2013:0:4137:9e76:2087:77a:53ef:7527"
+      end
+
+      it "should return the ipv6 of the adapter with the lowest IP connection metric (best connection) that has ipv6 enabled" do
+        network1 = mock('network1')
+        network1.expects(:IPConnectionMetric).returns(10)
+        network1.expects(:IPAddress).returns(["12.123.12.12", "2011:0:4137:9e76:2087:77a:53ef:7527"])
+        network2 = mock('network2')
+        network2.expects(:IPConnectionMetric).returns(5)
+        network2.expects(:IPAddress).returns(["12.123.12.13"])
+
+        Facter::Util::WMI.expects(:execquery).returns([network2, network1])
+
+        Facter.value(:ipaddress6).should == "2011:0:4137:9e76:2087:77a:53ef:7527"
+      end
+
+      context "when the IP connection metric is the same" do
+        it "should return the ipv6 of the adapter with the lowest binding order" do
+          network1 = mock('network1')
+          network1.expects(:SettingID).returns(settingId0)
+          network1.expects(:IPConnectionMetric).returns(5)
+          network1.expects(:IPAddress).returns(["12.123.12.12", "2011:0:4137:9e76:2087:77a:53ef:7527"])
+          network2 = mock('network2')
+          network2.expects(:SettingID).returns(settingId1)
+          network2.expects(:IPConnectionMetric).returns(5)
+          #network2.expects(:IPAddress).returns(["12.123.12.13", "2013:0:4137:9e76:2087:77a:53ef:7527"])
+          Facter::Util::WMI.expects(:execquery).returns([network1, network2])
+
+          Facter.value(:ipaddress6).should == "2011:0:4137:9e76:2087:77a:53ef:7527"
+        end
+
+        it "should return the ipv6 of the adapter with the lowest binding order even if the adapter is not first" do
+<<<<<<< HEAD
+          network1 = mock('network1')
+          network1.expects(:SettingID).returns(settingId1)
+          network1.expects(:IPConnectionMetric).returns(5)
+          network2 = mock('network2')
+          network2.expects(:SettingID).returns(settingId0)
+          network2.expects(:IPConnectionMetric).returns(5)
+          network2.expects(:IPAddress).returns(["12.123.12.13", "2013:0:4137:9e76:2087:77a:53ef:7527"])
+          Facter::Util::WMI.expects(:execquery).returns([network1, network2])
+
+          Facter.value(:ipaddress6).should == "2013:0:4137:9e76:2087:77a:53ef:7527"
+||||||| parent of 6541f09... maint: remove whitespace from netmask.rb, windows_network.rb, and ipaddress6_spec.rb
+          nics = given_two_valid_windows_nics_with_ipv4_and_ipv6
+          Facter::Util::Registry.stubs(:hklm_read).returns(["\\Device\\#{settingId1}", "\\Device\\#{settingId0}" ])
+
+          Facter::Util::WMI.expects(:execquery).returns(nics.values)
+
+          Facter.value(:ipaddress6).should == ipv6Address1
+=======
+          nics = given_two_valid_windows_nics_with_ipv4_and_ipv6
+          Facter::Util::Registry.stubs(:hklm_read).returns(["\\Device\\#{settingId1}", "\\Device\\#{settingId0}" ])
+          Facter::Util::WMI.expects(:execquery).returns(nics.values)
+
+          Facter.value(:ipaddress6).should == ipv6Address1
+>>>>>>> 6541f09... maint: remove whitespace from netmask.rb, windows_network.rb, and ipaddress6_spec.rb
+        end
+      end
+    end
   end
 end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-puppet/facter.git



More information about the Pkg-puppet-devel mailing list