The data stored in Hiera can be retrieved by the Puppet Master while compiling the catalog using the Hiera functions. In our manifests, we can have something like the following:
$dns_servers = hiera("dns_servers")
Note that the name of the Puppet variable need not be the same as the Hiera one, so the preceding command can also be something like this:
$my_dns_servers = hiera("dns_servers")
This assigns the top value to the $my_dns_servers
variable (the first one found while crossing the hierarchy of data sources) retrieved by Hiera for the key dns_servers
.
We can also merge arrays and hashes here, so, in order to retrieve an array of all the values in the hierarchy's data sources of a given key and not just the first one, we can use hiera_array()
:
$my_dns_servers = hiera_array("dns_servers")
If we expect a hash value for a given key, we can use the hiera()
function to retrieve the top value found, or hiera_hash()
to merge all the found values in a single hash:
$openssh_settings = hiera_hash("openssh_settings")
All these Hiera functions may receive additional parameters, as follows:
The following code shows the usage of additional parameters:
$my_dns_servers = hiera("dns_servers","8.8.8.8","$country")
With a hash, it is possible to express complex and structured data that has to be managed inside the Puppet code.
Remember that Hiera always returns the value of the first defined level keys, for example, we have a hash with nested hashes, as shown in the following code:
network::interfaces_hash: eth0: ipaddress: 10.0.0.193 netmask: 255.255.255.0 network: 10.0.0.0 broadcast: 10.0.0.255 gateway: 10.0.0.1 post_up: - '/sbin/ifconfig eth3 up' - '/sbin/ifconfig eth4 up' eth2: enable_dhcp: true eth3: auto: false method: manual eth4: auto: false method: manual
We can create a variable inside our Puppet code that loads it:
$int_hash = hiera('network::interfaces_hash')
Then, refer to single values inside its data structure with the following code:
$ip_eth0 = $int_hash['eth0']['ipaddress']
If we need to access this value from a template, we can directly write it in our erb
file:
ipaddress <%= @int_hash['eth0']['ipaddress'] %>
With Puppet 3 Hiera is shipped directly within the core code, but the integration goes far beyond: an automatic Hiera lookup is done for each class' parameter using the $class::$argument
key; this functionality is called data bindings or automatic parameter lookup.
An example is the following class definition:
class openssh ( $template = 'openssh/sshd.config.erb', ) { . . . }
The value of $template
will be evaluated according to the following logic:
class { 'openssh': template => 'site/openssh/sshd_config.erb', }
openssh::template
.'openssh/sshd.config.erb'
is used.To emulate a similar behavior on Puppet versions earlier than version 3, we would write something like the following:
class openssh ( $template = hiera("openssh::template",'openssh/sshd.config.erb'), ) { . . . }
This strong integration has definitively boosted the adoption of Hiera and is changing the way Puppet code is organized and classes are declared.
Before Puppet 2.6, we could declare classes by just including them, optionally more than once in our catalog, using the following code:
include openssh
And, we could manage the behavior of the class just by setting variables and having them dynamically evaluated inside the class with something like the following code:
class openssh { file { 'sshd_config': content => template($openssh_template), } }
This approach suffered the risks of having inconsistent values due to dynamic scoping of variables and parse ordering. Also, when using variables inside the module's code, it wasn't easy to understand which variables could affect the class's behavior, and there was not a public API, which is easily accessible.
The introduction of parameterized classes in Puppet 2.6 allowed classes to expose their arguments in a clear way using the following code:
class openssh ( $template = 'openssh/sshd.config.erb', ) { . . . }
In order to pass them explicitly and consistently in a class declaration, use the following code:
class { 'openssh': template => 'site/openssh/sshd_config.erb', }
But the fact that we can declare a specific class, using parameters, only once in a node's catalog presented new challenges on how our custom code had to be organized. We could not include classes wherever needed but we had to reorganize our manifests in order to avoid duplicate declarations.
From Puppet 3 onwards, it is possible to have the best of both worlds, we can use the original way to include classes:
include openssh
But we can also be sure that the template parameter is always and consistently evaluated according to the value of the Hiera key openssh::template
.