diff options
-rw-r--r-- | lib/facter/ipmess.rb | 39 | ||||
-rw-r--r-- | lib/facter/util/ip.rb | 78 | ||||
-rw-r--r-- | spec/unit/data/6.0-STABLE_FreeBSD_ifconfig | 12 | ||||
-rw-r--r-- | spec/unit/ipmess.rb | 19 | ||||
-rw-r--r-- | spec/unit/util/ip.rb | 48 |
5 files changed, 133 insertions, 63 deletions
diff --git a/lib/facter/ipmess.rb b/lib/facter/ipmess.rb index c61b1ec..2887b64 100644 --- a/lib/facter/ipmess.rb +++ b/lib/facter/ipmess.rb @@ -7,39 +7,26 @@ require 'facter/util/ip' +# Note that most of this only works on a fixed list of platforms; notably, Darwin +# is missing. + Facter.add(:interfaces) do - confine :kernel => [ :sunos, :freebsd, :openbsd, :netbsd, :linux ] + confine :kernel => Facter::Util::IP.supported_platforms setcode do - Facter::IPAddress.get_interfaces.join(",") + Facter::Util::IP.get_interfaces.collect { |iface| Facter::Util::IP.alphafy(iface) }.join(",") end end -case Facter.value(:kernel) -when 'SunOS', 'Linux', 'OpenBSD', 'NetBSD', 'FreeBSD' - Facter::IPAddress.get_interfaces.each do |interface| - mi = interface.gsub(/[:.]/, '_') - - Facter.add("ipaddress_" + mi) do - confine :kernel => [ :sunos, :freebsd, :openbsd, :netbsd, :linux ] - setcode do - label = 'ipaddress' - Facter::IPAddress.get_interface_value(interface, label) - end - end - - Facter.add("macaddress_" + mi) do - confine :kernel => [ :sunos, :freebsd, :openbsd, :netbsd, :linux ] - setcode do - label = 'macaddress' - Facter::IPAddress.get_interface_value(interface, label) - end - end +Facter::Util::IP.get_interfaces.each do |interface| + mi = Facter::Util::IP.alphafy(interface) - Facter.add("netmask_" + mi) do - confine :kernel => [ :sunos, :freebsd, :openbsd, :netbsd, :linux ] + # Make a fact for each detail of each interface. Yay. + # There's no point in confining these facts, since we wouldn't be able to create + # them if we weren't running on a supported platform. + %w{ipaddress macaddress netmask}.each do |label| + Facter.add(label + "_" + mi) do setcode do - label = 'netmask' - Facter::IPAddress.get_interface_value(interface, label) + Facter::Util::IP.get_interface_value(interface, label) end end end diff --git a/lib/facter/util/ip.rb b/lib/facter/util/ip.rb index 3dbfcda..598b084 100644 --- a/lib/facter/util/ip.rb +++ b/lib/facter/util/ip.rb @@ -1,11 +1,48 @@ # A base module for collecting IP-related # information from all kinds of platforms. -module Facter::IPAddress - def self.get_interfaces +module Facter::Util::IP + # A map of all the different regexes that work for + # 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]+)/ + }, + :bsd => { + :aliases => [:openbsd, :netbsd, :freebsd], + :ipaddress => /inet\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/, + :macaddress => /(?:ether|lladdr)\s+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/, + :netmask => /netmask\s+(\w{10})/ + }, + :sunos => { + :addr => /inet\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/, + :macaddress => /(?:ether|lladdr)\s+(\w?\w:\w?\w:\w?\w:\w?\w:\w?\w:\w?\w)/, + :netmask => /netmask\s+(\w{8})/ + } + } + + # Convert an interface name into purely alpha characters. + def self.alphafy(interface) + interface.gsub(/[:.]/, '_') + end + + 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 + def self.get_interfaces int = nil - output = Facter::IPAddress.get_all_interface_output() + output = Facter::Util::IP.get_all_interface_output() # We get lots of warnings on platforms that don't get an output # made. @@ -60,33 +97,16 @@ module Facter::IPAddress def self.get_interface_value(interface, label) tmp1 = [] - # LAK:NOTE This is pretty ugly - two case statements being used for most of the - # logic. These should be pulled into a small dispatch table. We don't have tests for this code, - # though, so it's not exactly trivial to do so. - case Facter.value(:kernel) - when 'Linux' - addr = /inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/ - mac = /(?:ether|HWaddr)\s+(\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/ - mask = /Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/ - when 'OpenBSD', 'NetBSD', 'FreeBSD' - addr = /inet\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/ - mac = /(?:ether|lladdr)\s+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/ - mask = /netmask\s+(\w{10})/ - when 'SunOS' - addr = /inet\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/ - mac = /(?:ether|lladdr)\s+(\w?\w:\w?\w:\w?\w:\w?\w:\w?\w:\w?\w)/ - mask = /netmask\s+(\w{8})/ - end + kernel = Facter.value(:kernel).downcase.to_sym - case label - when 'ipaddress' - regex = addr - when 'macaddress' - regex = mac - when 'netmask' - regex = mask + # 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. @@ -99,7 +119,7 @@ module Facter::IPAddress output_int = get_single_interface_output(interface) if interface != "lo" && interface != "lo0" - output_int.each { |s| + output_int.each do |s| if s =~ regex value = $1 if label == 'netmask' && Facter.value(:kernel) == "SunOS" @@ -107,7 +127,7 @@ module Facter::IPAddress end tmp1.push(value) end - } + end end if tmp1 diff --git a/spec/unit/data/6.0-STABLE_FreeBSD_ifconfig b/spec/unit/data/6.0-STABLE_FreeBSD_ifconfig new file mode 100644 index 0000000..3339a45 --- /dev/null +++ b/spec/unit/data/6.0-STABLE_FreeBSD_ifconfig @@ -0,0 +1,12 @@ +fxp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 + options=b<RXCSUM,TXCSUM,VLAN_MTU> + inet x.x.58.26 netmask 0xfffffff8 broadcast x.x.58.31 + inet x.x.58.27 netmask 0xffffffff broadcast x.x.58.27 + inet x.x.58.28 netmask 0xffffffff broadcast x.x.58.28 + inet x.x.58.29 netmask 0xffffffff broadcast x.x.58.29 + inet x.x.58.30 netmask 0xffffffff broadcast x.x.58.30 + ether 00:0e:0c:68:67:7c + media: Ethernet autoselect (100baseTX <full-duplex>) + status: active +lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 + inet 127.0.0.1 netmask 0xff000000
\ No newline at end of file diff --git a/spec/unit/ipmess.rb b/spec/unit/ipmess.rb new file mode 100644 index 0000000..a67216c --- /dev/null +++ b/spec/unit/ipmess.rb @@ -0,0 +1,19 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../spec_helper' + +require 'facter' + +describe "Messy IP facts" do + before do + Facter.loadfacts + end + + it "should replace the ':' in an interface list with '_'" do + # So we look supported + Facter.fact(:kernel).stubs(:value).returns("SunOS") + + Facter::Util::IP.expects(:get_interfaces).returns %w{eth0:1 eth1:2} + Facter.fact(:interfaces).value.should == %{eth0_1,eth1_2} + end +end diff --git a/spec/unit/util/ip.rb b/spec/unit/util/ip.rb index 059bdd1..73cf37c 100644 --- a/spec/unit/util/ip.rb +++ b/spec/unit/util/ip.rb @@ -4,34 +4,66 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'facter/util/ip' -describe Facter::IPAddress do +describe Facter::Util::IP do + [:freebsd, :linux, :netbsd, :openbsd, :sunos].each do |platform| + it "should be supported on #{platform}" do + Facter::Util::IP.supported_platforms.should be_include(platform) + end + end + it "should return a list of interfaces" do - Facter::IPAddress.should respond_to(:get_interfaces) + Facter::Util::IP.should respond_to(:get_interfaces) end it "should return an empty list of interfaces on an unknown kernel" do Facter.stubs(:value).returns("UnknownKernel") - Facter::IPAddress.get_interfaces().should == [] + Facter::Util::IP.get_interfaces().should == [] end it "should return a list with a single interface on Linux with a single interface" do sample_output_file = File.dirname(__FILE__) + '/../data/linux_ifconfig_all_with_single_interface' linux_ifconfig = File.new(sample_output_file).read() - Facter::IPAddress.stubs(:get_all_interface_output).returns(linux_ifconfig) - Facter::IPAddress.get_interfaces().should == ["eth0"] + Facter::Util::IP.stubs(:get_all_interface_output).returns(linux_ifconfig) + Facter::Util::IP.get_interfaces().should == ["eth0"] end + it "should return a value for a specific interface" do - Facter::IPAddress.should respond_to(:get_interface_value) + Facter::Util::IP.should respond_to(:get_interface_value) + end + + it "should not return interface information for unsupported platforms" do + Facter.stubs(:value).with(:kernel).returns("bleah") + Facter::Util::IP.get_interface_value("e1000g0", "netmask").should == [] + end + + it "should return interface information for directly supported platforms" do + sample_output_file = File.dirname(__FILE__) + "/../data/solaris_ifconfig_single_interface" + solaris_ifconfig_interface = File.new(sample_output_file).read() + + Facter::Util::IP.expects(:get_single_interface_output).with("e1000g0").returns(solaris_ifconfig_interface) + Facter.stubs(:value).with(:kernel).returns("SunOS") + + Facter::Util::IP.get_interface_value("e1000g0", "netmask").should == "255.255.255.0" + end + + it "should return interface information for platforms supported via an alias" do + sample_output_file = File.dirname(__FILE__) + "/../data/6.0-STABLE_FreeBSD_ifconfig" + ifconfig_interface = File.new(sample_output_file).read() + + Facter::Util::IP.expects(:get_single_interface_output).with("fxp0").returns(ifconfig_interface) + Facter.stubs(:value).with(:kernel).returns("FreeBSD") + + Facter::Util::IP.get_interface_value("fxp0", "macaddress").should == "00:0e:0c:68:67:7c" end it "should return a human readable netmask on Solaris" do sample_output_file = File.dirname(__FILE__) + "/../data/solaris_ifconfig_single_interface" solaris_ifconfig_interface = File.new(sample_output_file).read() - Facter::IPAddress.expects(:get_single_interface_output).with("e1000g0").returns(solaris_ifconfig_interface) + Facter::Util::IP.expects(:get_single_interface_output).with("e1000g0").returns(solaris_ifconfig_interface) Facter.stubs(:value).with(:kernel).returns("SunOS") - Facter::IPAddress.get_interface_value("e1000g0", "netmask").should == "255.255.255.0" + Facter::Util::IP.get_interface_value("e1000g0", "netmask").should == "255.255.255.0" end end |