matching all current "ipaddress_ethX" facts

369 views
Skip to first unread message

cko

unread,
Nov 21, 2013, 7:32:44 AM11/21/13
to puppet...@googlegroups.com
Hi,

I'm currently trying to solve the following problem:

I wrote a module that matches the "$ipaddress" fact for certain IP subnets (like 20.20.2... or 30.30.2..). Depending on the subnet, the variable $proxy-server changes.

The problem is, that some of our physical machines have a random number of interfaces connected to many different subnets. In some cases the $ipadddress fact returns the correct subnet, lets call it "production server lan" and some don't.

Is there any way to make puppet check every available NIC for a specific subnet/ regex? Something like this:

if $ipaddress_eth* =~ /^20\.20\.\..*$/ {
   $proxy-server = foo
}
.

jcbollinger

unread,
Nov 21, 2013, 1:03:51 PM11/21/13
to puppet...@googlegroups.com



Puppet DSL does not support this directly, but it sounds like a good candidate for a custom function.  You could do a proof-of-concept with an inline template, even, but I recommend a bona fide function for your final implementation.


John

Jo Rhett

unread,
Nov 21, 2013, 4:36:52 PM11/21/13
to puppet...@googlegroups.com
Yep, write it out as such :)  Either if/then in the manifest, or write a custom function that iterates through all ipaddress facts.

--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/9e5f1c49-cf71-4eab-a11b-18a9d31b5b0a%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

-- 
Jo Rhett
Net Consonance : net philanthropy to improve open source and internet projects.




cko

unread,
Nov 29, 2013, 6:46:11 AM11/29/13
to puppet...@googlegroups.com
Thanks, i think i got something here:

Facter.add("ip_prodlan") do
   confine :kernel => "Linux"
   setcode do
      Facter::Util::Resolution.exec("/sbin/ifconfig | /bin/grep '20.20.\\|30.31.\\|200.30.80.\\|120.' | /bin/awk '{ print $2 }' | /bin/cut -d':' -f2 | /usr/bin/head -n1")
   end
end

I'm currently using the custom fact to print the production LAN ip address in /etc/motd .
It usually returns the correct value. But in some cases the "puppet agent -t" command changes the file in a different way than "service puppet restart" does. Any idea?

Another question:

I want my custom fact to do something like this:
if the "Resolution.exec" returns 0 (nothing) then ip_prodlan should use the value of the fact "$ipaddress".
Is it possible to do something like this?

jcbollinger

unread,
Dec 2, 2013, 1:18:32 PM12/2/13
to puppet...@googlegroups.com


On Friday, November 29, 2013 5:46:11 AM UTC-6, cko wrote:
Thanks, i think i got something here:

Facter.add("ip_prodlan") do
   confine :kernel => "Linux"
   setcode do
      Facter::Util::Resolution.exec("/sbin/ifconfig | /bin/grep '20.20.\\|30.31.\\|200.30.80.\\|120.' | /bin/awk '{ print $2 }' | /bin/cut -d':' -f2 | /usr/bin/head -n1")
   end
end



I really think that's a sub-optimal approach.  Facter is already providing all the facts you need for this job.  You ought to be analyzing those instead of creating a new one.  Here's an outline:
  1. Obtain a list of all defined network interfaces for the target node by splitting the value of the $::interfaces fact around commas.
  2. For each interface name test the value of the $::ipaddress_<interface_name> fact against the subnet mask(s) of interest.
  3. Take appropriate action and/or return a result.
That should ultimately be done in a custom function, but as I said, it could be prototyped via an inline template.

 
I'm currently using the custom fact to print the production LAN ip address in /etc/motd .
It usually returns the correct value. But in some cases the "puppet agent -t" command changes the file in a different way than "service puppet restart" does. Any idea?



If performing a catalog run via "puppet agent -t" exhibits inconsistent behavior then I have trouble believing that forcing one via "service puppet restart" is always consistent.  Do note, by the way, that the latter is a rather rough way to force a catalog run -- if the agent is running in daemon mode then you can trigger an immediate catalog run by sending it SIGUSR1.

Perhaps your interfaces are going up and down.  If the key interface happens to be down when Facter runs then its IP address probably will not be reported by ifconfig, so you might not see any of the subnets you're looking for.

 
Another question:

I want my custom fact to do something like this:
if the "Resolution.exec" returns 0 (nothing) then ip_prodlan should use the value of the fact "$ipaddress".
Is it possible to do something like this?



Probably, but don't.  Perform this sort of test and data selection in your manifests, not in Facter.


John

Jacob Fleming-Gale

unread,
Dec 2, 2013, 9:27:58 PM12/2/13
to puppet...@googlegroups.com
the has_ip_network function that's part of puppet-stdlib may help, it matches all interfaces against a network address and return a boolean if a match is found.



--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.

Stefan Schulte

unread,
Dec 4, 2013, 3:58:30 AM12/4/13
to puppet...@googlegroups.com
> if $ipaddress_eth*** =~ /^20\.20\.\..*$/ {
> $proxy-server = foo
> }
> .
>
> --

I'd recommend to write a custom fact that returns your "production
server lan" ipaddress first and then check only that fact against your
regular expression. The custom fact may look like this:


require 'ipaddr'
require 'facter/util/ip'

Facter.add(:ipaddress_production) do
setcode do
production_networks = [
IPAddr.new('20.20.2.0/24'),
IPAddr.new('30.30.2.0/24')
]
production_ip = nil

Facter::Util::IP.get_interfaces.each do |interface|
ip = Facter::Util::IP.get_interface_value(interface, 'ipaddress')
if production_networks.any? { |network| network.include? ip }
production_ip = ip
end
end
production_ip
end
end

-Stefan
Reply all
Reply to author
Forward
0 new messages