Writing structured facts

I've wrote some ruby code which will run on a linux server and return details about the server as a fact. It does this by connecting to amazon and retrieving some json (it runs two separate commands one to retrieve a list of disks - e.g /dev/sda1, /dev/xvdb and then it maps this to a volumeID via another query).

I've made some small amendments to the output and added some values I'm interested in. The code runs multiple times and returns multiple hashes (one for each disk - maybe I should merge them?). Anyway here's an example of a server which has two disks below (this is just some debug output):

Hash is {"/dev/sda1"=>{"disk_mapping"=>"", "is_lvm_partitioned"=>"false", "volumeid"=>"vol1234"}}.
Hash is {"/dev/xvdb1"=>{"disk_mapping"=>"xvdb1", "is_lvm_partitioned"=>"true", "volumeid"=>"vol5678"}}.

The next thing I want to to is turn this into a structured fact (with the devices: /dev/sda1, /dev/xvdb1 as the "keys"). Here's a rough idea of how I've done it (I've skipped a lot of the irrelevant code).

json_string = {
  "#{path}" => {
  "disk_mapping"       => "#{disk_mapping}",
  "is_lvm_partitioned" => "#{is_lvm_partitioned}",
  "volumeid"           => "#{getVolumes}"
  }
}.to_json
hash = JSON.parse(json_string)
if hash.is_a? Hash then
  debug_msg("Hash is #{hash}.")
  hash["#{path}"].each do |key, child|
    debug_msg("Setting key: #{key} child: #{child}.")
  end
end

I've never really wrote any ruby before so this is copied from multiple places, but besides aggregated facts I can't find a way to do this; I've tried to do something like this:

Facter.add(:test["#{path}"]["#{key}"]) do
  setcode do
    #{child}
  end
end

So I guess in order I want to know:

  1. Should I merge the hash somehow? I originally assumed I did but found this incredibly hard due to not knowing how many hash's I'd have.
  2. Should I be using an aggregated fact or a "standard" one?
  3. How do I retain the structure of the hash and then call it with a single query (e.g facts test).
  4. Any examples which are similar to my code (the puppet ones I've found quite hard to follow).

Here's what I'm looking for at the end:

[root@blah ~]# facter test
{
  /dev/sda1 => {
    disk_mapping => "",
    is_lvm_partitioned => "false",
    volumeid => "vol1234"
  },
  /dev/xvdb => {
    disk_mapping => "xvdb1",
    is_lvm_partitioned => "true",
    volumeid => "vol5678"
  }
}

Thanks.

1 answer

  • answered 2022-05-07 18:27 keeer

    I was way off...

    hash_template = {}
    hash = hash_template.merge!({
      "#{path}" => {
      "disk_mapping"       => "#{disk_mapping}",
      "is_lvm_partitioned" => "#{is_lvm_partitioned}",
      "volumeid"           => "#{getVolumes}"
      }
    }
    if hash.is_a? Hash then
      Facter.add(:test) do
        setcode do
          begin
            "#{hash}"
          rescue
            nil
          end
        end
      end
    end
    

    This can only be retrieved/viewed by calling it (within as puppet manifest):

    if $test {
      notify { "Test fact is set as $test": }
    }
    

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum