xit
xit

Reputation: 145

Creating nested Puppet fact (Ruby) by iterating over gem query output

I have working Ruby code to query DNS details and create Puppet custom facts (puppet 5, Facter 3.11.6) however I am trying to modify it to create nested facts from the key/value pairs that the query obtains.

Code that works to set individual facts with the key name is:

  require 'resolv'
  Resolv::DNS::Config.default_config_hash.each do | key, value |
    if !value.nil?
      Facter.add("dns_#{key}") do
        if value.is_a?(Array)
          setcode { value.join(',') }
        else
          setcode { value }
        end
      end
    end
  end

which creates individual facts thus:

dns_nameserver => 192.168.1.1,192.168.1.2
dns_ndots => 1
dns_search => test.domain

My failed attempt so far to create a nested fact under the parent fact of 'DNS' is:

require 'resolv'
Facter.add("dns") do
  value ={}
  Resolv::DNS::Config.default_config_hash.each do | key, result |
    if !result.nil?
      if result.is_a?(Array)
        setcode { value['#{key}'] = result.join(',') }
      else
        setcode { value['#{key}'] = result }
      end
    end
  end
end

which gives a limited result of just:

dns => 1

Other code I have tried seems to put an array output into the string and multiple IPs are quoted inside square brackets over 2 lines instead of being output as per the first code block at top of page.

The fact structure I am TRYING to achieve (by modifying the top of page code) is:

dns => {
  nameserver => 192.168.1.1,192.168.1.2,
  ndots => 1,
  search => test.domain,
}

Thanks in advance for any assistance.

Upvotes: 0

Views: 507

Answers (1)

xit
xit

Reputation: 145

I finally got this with the assistance from a poster who put some great code leads here, but unfortunately removed it soon afterward. Here is the code that works:

require 'resolv'
Facter.add(:networking_dns) do
  setcode do
    Resolv::DNS::Config.default_config_hash.each_with_object({}) do | (key, value), sub|
      if !value.nil?
        sub[key] = value
        sub
      end
    end
  end
end

Now for some explanatory notes (please feel free to correct me or offer any optimisations to this):

# the resolv gem is required
require 'resolv'
# create the parent fact (has no value of its own)
Facter.add(:networking_dns) do
# start building instructions in the fact
  setcode do
# use the resolv gem to lookup values in /etc/resolv.conf and add .each to process all key/value pairs returned
# also add _with_object({}) and sub in the variables to set a blank value for sub.  Saves doing it separately.  Sub can be any name but denotes the declaration for the nested facts
    Resolv::DNS::Config.default_config_hash.each_with_object({}) do | (key, value), sub|
# create facts only when the value is not nil
      if !value.nil?
        sub[key] = value
        sub
# using a closing blank entry for a nested fact is critical or they won't create!  Place this outside of the case statement to prevent blank values
      end
    end
  end
end
# use the appropriate number of ends and indent for readability

Thanks to the person who posted their guidance here before removing it. I would like to upvote you if you post again.

Any tips on optimisation to the able solution are welcome, as I'm still grasping Ruby (spent hours on this!)

Upvotes: 1

Related Questions