Custom fact producing different results

45 views
Skip to first unread message

tont...@gmail.com

unread,
Nov 10, 2017, 5:06:40 PM11/10/17
to Puppet Users
Hi,

I've got a custom fact called is_internal that produces a Boolean value:

# puppet apply -e 'notice(type($is_internal))'
Notice: Scope(Class[main]): Boolean

I'm using it in my puppet.conf template like this:

server=<%if @is_internal == true -%>puppetmaster-internal<% else -%>puppetmaster<% end -%>

The fact is relatively simple, it checks to see if any interface matches the regexp 10.0.1, and if so, it sets is_internal to true (I'm including the fact below).

Strangely, two machines with the same node definition are producing different results. On machine A if I run puppet, is_internal is evaluated to be false, and the template is set to have 'puppetmaster-internal', but on machine B it somehow evaluates to be 'true' and sets the value to the non-internal one in the template.

As you can see from the interfaces configuration, neither machine has 10.0.1.x configured for their interface (they use 10.0.2.x), see below for the output of 'ip addr ls'.

Both machines respond with 'false' when I do `facter -p is_internal`, yet, when Machine B has puppet run, for some reason it is evaluated to be true via puppet:

Machine A:
# facter -p is_internal
false
# puppet apply -e 'notice($is_internal)'
Notice: Scope(Class[main]): false

Machine B:
# facter -p is_internal
false
# puppet apply -e 'notice($is_internal)'
Notice: Scope(Class[main]): true

Both run 4.8.2 puppet version and facter 2.4.6. What could possibly make Machine B change this value when it is run through puppet?!

Thanks for any ideas, I'm going absolutely insane with this.

Machine A:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-public state UP group default qlen 1000
    link/ether 00:30:48:7c:d7:78 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-private state UP group default qlen 1000
    link/ether 00:30:48:7c:d7:79 brd ff:ff:ff:ff:ff:ff
5: br-private: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 00:30:48:7c:d7:79 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.11/24 brd 10.0.2.255 scope global br-private
       valid_lft forever preferred_lft forever
    inet6 fe80::230:48ff:fe7c:d779/64 scope link
       valid_lft forever preferred_lft forever
6: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-public state UNKNOWN group default qlen 500
    link/ether fe:0a:cf:dd:a8:b2 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc0a:cfff:fedd:a8b2/64 scope link
       valid_lft forever preferred_lft forever
10: tap1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-public state UNKNOWN group default qlen 500
    link/ether fe:1e:ec:4c:ac:6c brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc1e:ecff:fe4c:ac6c/64 scope link
       valid_lft forever preferred_lft forever


Machine B:

root@mesange-pn:/var/lib/puppet/lib/facter# ip a ls
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-public state UP group default qlen 1000
    link/ether 00:30:48:7e:52:18 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-private state UP group default qlen 1000
    link/ether 00:30:48:7e:52:19 brd ff:ff:ff:ff:ff:ff
5: br-private: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 00:30:48:7e:52:19 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.10/24 brd 10.0.2.255 scope global br-private
       valid_lft forever preferred_lft forever
    inet 10.0.2.1/32 scope global br-private:0
       valid_lft forever preferred_lft forever
    inet6 fe80::230:48ff:fe7e:5219/64 scope link
       valid_lft forever preferred_lft forever
9: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-public state UNKNOWN group default qlen 500
    link/ether fe:2d:b0:c6:2b:58 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc2d:b0ff:fec6:2b58/64 scope link
       valid_lft forever preferred_lft forever
10: tap1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-public state UNKNOWN group default qlen 500
    link/ether fe:69:06:4b:83:19 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc69:6ff:fe4b:8319/64 scope link
       valid_lft forever preferred_lft forever

require 'facter/util/ip'
 
def has_address(interface)
  ip = Facter::Util::IP.get_interface_value(interface, 'ipaddress')
  if ip.nil?
    false
  else
    true
  end
end
 
def is_internal(interface)
  rfc1918 = Regexp.new('^10\.0\.1\.')
  ip = Facter::Util::IP.get_interface_value(interface, 'ipaddress')
  if rfc1918.match(ip)
    true
  else
    false
  end
end
 
def find_networks
  found_public = found_internal = false
  Facter::Util::IP.get_interfaces.each do |interface|
    if has_address(interface)
      if is_internal(interface)
        found_internal = true
      else
        found_public = true
      end
    end
  end
  [found_public, found_internal]
end
 
# these facts check if any interface is on a public or internal network
# they return the string true or false
# this fact will always be present

Facter.add(:is_internal) do
  confine :kernel => Facter::Util::IP.supported_platforms
  setcode do
    found_public, found_internal = find_networks
    found_internal
  end
end

Facter.add(:interfaces_internal) do
  confine :kernel => Facter::Util::IP.supported_platforms
  setcode do
    iface=""
    Facter::Util::IP.get_interfaces.each do |interface|
      if has_address(interface)
        if is_internal(interface)
          iface += "," unless iface.empty?
          iface = iface + Facter::Util::IP.alphafy(interface)
        end
      end
    end
    iface
  end
end

tont...@gmail.com

unread,
Nov 15, 2017, 1:03:12 PM11/15/17
to Puppet Users

Any ideas for debugging this?

Garrett Honeycutt

unread,
Nov 16, 2017, 1:19:10 PM11/16/17
to puppet...@googlegroups.com
>     inet 127.0.0.1/8 <http://127.0.0.1/8> scope host lo
>        valid_lft forever preferred_lft forever
>     inet6 ::1/128 scope host
>        valid_lft forever preferred_lft forever
> 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
> master br-public state UP group default qlen 1000
>     link/ether 00:30:48:7c:d7:78 brd ff:ff:ff:ff:ff:ff
> 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
> master br-private state UP group default qlen 1000
>     link/ether 00:30:48:7c:d7:79 brd ff:ff:ff:ff:ff:ff
> 5: br-private: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
> noqueue state UP group default
>     link/ether 00:30:48:7c:d7:79 brd ff:ff:ff:ff:ff:ff
>     inet 10.0.2.11/24 <http://10.0.2.11/24> brd 10.0.2.255 scope
> global br-private
>        valid_lft forever preferred_lft forever
>     inet6 fe80::230:48ff:fe7c:d779/64 scope link
>        valid_lft forever preferred_lft forever
> 6: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
> master br-public state UNKNOWN group default qlen 500
>     link/ether fe:0a:cf:dd:a8:b2 brd ff:ff:ff:ff:ff:ff
>     inet6 fe80::fc0a:cfff:fedd:a8b2/64 scope link
>        valid_lft forever preferred_lft forever
> 10: tap1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
> pfifo_fast master br-public state UNKNOWN group default qlen 500
>     link/ether fe:1e:ec:4c:ac:6c brd ff:ff:ff:ff:ff:ff
>     inet6 fe80::fc1e:ecff:fe4c:ac6c/64 scope link
>        valid_lft forever preferred_lft forever
>
>
> Machine B:
>
> root@mesange-pn:/var/lib/puppet/lib/facter# ip a ls
> 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
> group default
>     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
>     inet 127.0.0.1/8 <http://127.0.0.1/8> scope host lo
>        valid_lft forever preferred_lft forever
>     inet6 ::1/128 scope host
>        valid_lft forever preferred_lft forever
> 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
> master br-public state UP group default qlen 1000
>     link/ether 00:30:48:7e:52:18 brd ff:ff:ff:ff:ff:ff
> 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
> master br-private state UP group default qlen 1000
>     link/ether 00:30:48:7e:52:19 brd ff:ff:ff:ff:ff:ff
> 5: br-private: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
> noqueue state UP group default
>     link/ether 00:30:48:7e:52:19 brd ff:ff:ff:ff:ff:ff
>     inet 10.0.2.10/24 <http://10.0.2.10/24> brd 10.0.2.255 scope
> global br-private
>        valid_lft forever preferred_lft forever
>     inet 10.0.2.1/32 <http://10.0.2.1/32> scope global br-private:0
> --

Hi,

Suggest writing unit tests. The practice of writing them often exposes
issues with your implementation.

Here's a simple one that shows how you can define your expectations and
stub out commands.

https://github.com/ghoneycutt/puppet-module-ssh/blob/master/spec/unit/facter/ssh_spec.rb

BTW, you might want to think of another approach than relying on the
network as a source of truth. As your network grows and changes, you
will have tight coupling between what your systems do and the IP's they
have.

Best regards,
-g


--
Garrett Honeycutt
@learnpuppet
Puppet Training with LearnPuppet.com
Mobile: +1.206.414.8658
Reply all
Reply to author
Forward
0 new messages