简体   繁体   中英

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.

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 } 

There are no "nested" facts. There are "structured" facts, however, and these may have hashes as their values. To the extent that Facter presents output that you characterize as "nested", that's surely what you're looking at.

Since the elements of a structured fact's value are not facts in their own right, they need to be specified in the resolution of the fact itself:

Facter.add (:custom_parent) do
    {
        :custom_fact_1 => 'whatever',
        :custom_fact_2 => 'whatever2',
    }
end

The whatever and whatever2 do not need to be literal strings; they can be more or less arbitrary Ruby expressions. Of course, you can also set the members separately from creating the hash (but in the same fact resolution):

Facter.add (:custom_parent) do
    value = new Hash()
    value[:custom_fact_1] = 'whatever'
    value[:custom_fact_2] = 'whatever2'
    value
end

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM