rubyhashmappuppetfacter

Puppet - create NESTED custom fact


I have successfully created a .rb custom fact that parses a built-in fact to create a new value, however I am now trying to use it as nested custom fact for Puppet.

The hierarchy I want to create is similar to built-in facts, eg running Facter (or Facter -p) would show:

custom_parent => {
  custom_fact_1 => whatever
  custom_fact_2 => whatever2
}

and usage in a puppet manifest would be:

$custom_parent.custom_fact_1

So far I have tried leading syntax such as:

Facter.add (:custom_parent)=>(custom_fact_1) do
Facter.add (:custom_parent)(:custom_fact_1) do
Facter.add (:custom_parent.custom_fact_1) do
Facter.add (:custom_parent:custom_fact_1) do
Facter.add (custom_parent:custom_fact_1) do

...and many other variations however cannot get a nested custom fact array to create. I've Googled for a while and if anyone knows if it is possible I would be very grateful.

I did find that nested facts can be created using an array in a .yaml file in the /etc/puppetlabs/facter/facts.d/ directory as below, however this sets FIXED values and does not process logic which I require in my custom fact.

{
  "custom_parent":
  {
    "custom_fact_1": "whatever",
    "custom_fact_2": "whatever2",
  }
}

Thanks in advance.


Solution

  • Thank you @John Bollinger. Your example was very close however I found that I needed to use type => aggregate and chunk to get it to work. I also combined it with a defined function, with the end result being based on the code below.

    If you have any other suggestions to improve code conformity on this please feel free to point it out. Cheers

    # define the function to process the input fact
    def dhcp_octets(level)
      dhcp_split = Facter.value(:networking)['dhcp'].split('.')
      if dhcp_split[-level..-1]
        result = dhcp_split[-level..-1].join('.')
        result
      end
    end
    
    # create the parent fact
    Facter.add(:network_dhcp_octets, :type => :aggregate) do
      chunk(:dhcp_ip) do
        value = {}
    
    # return a child => subchild array
        value['child1'] = {'child2' => dhcp_octets(2)}
    
    # return child facts based on array depth (right to left)
        value['1_octets'] = dhcp_octets(1)
        value['2_octets'] = dhcp_octets(2)
        value['3_octets'] = dhcp_octets(3)
        value['4_octets'] = dhcp_octets(4)
    
    # this one should return an empty fact
        value['5_octets'] = dhcp_octets(5)
        value
      end
    end