iterate over array of hash in puppet erb template

862 Views Asked by At

I have following values defined in hieradata in puppet

globals::myservers:
  - fqdn: "host1.example.com"
    port: 22
    protocol: "ssh"
  - fqdn: "host2.example.com"
    port: 22
    protocol: "ssh"

and I would like it to print the following values with above data

my_servers = host1.example.com host2.example.com
2

There are 2 best solutions below

1
16c7x On

Your hiera data looks like you have an array called myservers with each element containing a hash.

# Build a =data structure the same as you have in hiera.
$myservers = [ {fqdn => 'host1', port => '22' }, {fqdn => 'host2', port => '22' } ]

# Use the map function to extract all the values for fqdn into an array.
$fqdnarray = $myservers.map |$item| { $item[fqdn] }

# use the join function to turn the array into a string.
$fqdnstring = join($fqdnarray,',')

# Print the output
notify { 'Hosts message':
  message => "my_servers = ${fqdnstring}"
}

You should be able to drop the above code straight into a file, let's call it test.pp and then run puppet apply test.pp on a machine with a Puppet agent on to see what it does.

0
John Bollinger On

The first thing to do is to load the data into Puppet. The specified Hiera key is appropriate for automatically binding the data to a parameter $myservers of a class named globals:

class globals(
  Array[Hash[String, String]] $myservers
) {
  # ... do something with $myservers ...
}

If you do not already have such a class, however, then you can alternatively look up the data from within any other class or any defined type:

class mymodule::any_class {
  $myservers = lookup('globals::myservers', Array[Hash[String, String]])
  # ... do something with $myservers ...
}

Having obtained the data, the question is how to write an ERB template that iterates over it and formats it as desired. This is not hard, provided that you know some Ruby (that's what the 'R' stands for in ERB, after all). The wanted template might be something like this ...

my_servers = <%= @myservers.map { |server| server['fqdn'] } .join(' ') %>

Inside the template, the Ruby @myservers variable is bound to the $myservers Puppet variable from the local scope from which the template is evaluated. The scriptlet extracts the 'fqdn' members of all the array elements and joins their string representations together with space separators.

As for invoking the template evaluation, you have your choice of putting the template into a separate file and using the template() function, or putting it directly into your manifest and using inline_template(). For example,

  $formatted_server_list = inline_template(
      "my_servers = <%= @myservers.map { |server| server['fqdn'] } .join(' ') %>")
  notify { "${formatted_server_list}": }