When we use a backend based on files such as JSON or YAML, which are the most commonly used, we have to recreate on the filesystem the hierarchy defined in our hiera.yaml
file, the files that contain Hiera data must be placed in these directories.
Let's see Hiera in action. Look at the following sample hierarchy configuration:
:hierarchy: - "nodes/%{::fqdn}" - "env/%{::env}" - common :yaml: :datadir: /etc/puppetlabs/code/hieradata
We have to create a directory structure as follows:
mkdir -p /etc/puppetlabs/code/hieradata/{nodes,env}
Then, work on the YAML files as shown:
vi /etc/puppetlabs/code/hieradata/nodes/web01.example42.com.yaml vi /etc/puppetlabs/code/hieradata/env/production.yaml vi /etc/puppetlabs/code/hieradata/env/test.yaml vi /etc/puppetlabs/code/hieradata/common.yaml
These files are plain YAML files where we can specify the values for any Hiera-managed key. These values can be strings, arrays, or hashes:
vi /etc/puppet/hieradata/common.yaml
--- # A simple string assigned to a key timezone: 'Europe/Rome' # A string with variable interpolation nagios_server: "nagios.%{::domain}" # A string with another variable defined in Hiera (!) dns_nameservers: "%{hiera('dns_servers')}" # A string assigned to a key that maps to the # template parameter of the openssh class (from Puppet 3) openssh::template: 'site/common/openssh/sshd_config.erb' # An array of values ldap_servers: - 10.42.10.31 - 10.42.10.32 # An array with a single value ntp::ntp_servers: - 10.42.10.71 # A hash of values users: al: home: '/home/al' comment: 'Al' jenkins: password: '!' comment: 'Jenkins'
Given the previous example, execute a Hiera invocation as follows:
hiera ldap_servers
It will return the following array:
["10.42.10.31", "10.42.10.32"]
If we define a different value for a key in a data source that is higher in the hierarchy, then that value is returned. Let's create a data source for the test
environment as follows:
vi /etc/puppet/hieradata/env/test.yaml
--- ldap_servers: - 192.168.0.31 users: qa: home: '/home/qa' comment: 'QA Tester'
A normal Hiera lookup for the ldap_servers
key will still return the common value, as follows:
hiera ldap_servers ["10.42.10.31", "10.42.10.32"]
If we explicitly pass the env
variable, the returned value is the one for the env
test as follows:
hiera ldap_servers env=test ["192.168.0.31"]
If we have a more specific setting for a given node, that value is returned:
vi /etc/puppet/hieradata/nodes/ldap.example42.com.yaml
--- ldap_servers: - 127.0.0.1
hiera ldap_servers fqdn=ldap.example42.com ["127.0.0.1"]
Hiera also provides some alternative lookup options. When we deal with arrays, for example, we can decide to merge all the values found in the hierarchy, instead of returning the first one found. Let's see how the result of the preceding command changes if the array lookup is specified (-a
option):
hiera -a ldap_servers fqdn=ldap.example42.com ["127.0.0.1", "10.42.10.31", "10.42.10.32"]
Note that the value defined for the env=test
case is not returned, unless we specify it:
hiera -a ldap_servers fqdn=ldap.example42.com env=test ["127.0.0.1", "192.168.0.31", "10.42.10.31", "10.42.10.32"]
When working with hashes, interesting things can be done.
Let's see what the value of the user's hash is for the test environment:
hiera users env=test {"qa"=>{"home"=>"/home/qa", "comment"=>"QA Tester"}}
As it normally does, Hiera returns the first value it meets while traversing the hierarchy, but in this case, we might prefer to have a hash containing all the values found. Similar to the -a
option for arrays, we have the -h
option for hashes at our disposal:
hiera -h users env=test {"al"=>{"home"=>"/home/al", "comment"=>"Al"}, "jenkins"=>{"password"=>"!", "comment"=>"Jenkins"}, "qa"=>{"home"=>"/home/qa", "comment"=>"QA Tester"}}
Let's make one further experiment, let's add a new user specific for our ldap.example42.com
node and give different values to a parameter already defined in the common data source:
vi /etc/puppet/hieradata/nodes/ldap.example42.com.yaml
users: openldap: groups: 'apps' jenkins: ensure: absent
A hash lookup merges the found values as expected:
hiera -h users fqdn=ldap.example42.com env=test
{"al"=>{"home"=>"/home/al", "comment"=>"Al"}, "jenkins"=>{"ensure"=>"absent"}, "qa"=>{"home"=>"/home/qa", "comment"=>"QA Tester"}, "openldap"=>{"groups"=>"apps"}}
Let's take a look at the parameters of the jenkins
user; being defined both at node level and in the common data source, the returned value is the one for the higher data source in the hierarchy.
Hiera's management of hashes can be quite powerful, and we can make optimal use of it. For example, we can use them inside Puppet manifests with the create_resources
function, with the hash of the users
data and a single line of code as follows:
create_resources(user, hiera_hash($users))
Based on highly customizable Hiera data, we can manage all the users of our nodes.
We can tune how Hiera manages the merging of hashes with the merge_behavior
global setting, which allows deeper merging at single key levels. Read the official documentation at http://docs.puppetlabs.com/hiera/1/lookup_types.html#hash-merge for more details.
Quite often, we need to understand where a given key is set in our hierarchy and what values will be computed for it. The -d
(debug) option is rather useful for this. The previous line will return the following output:
hiera -d -h users fqdn=ldap.example42.com env=test DEBUG: 2013-12-07 13:11:07 +0100: Hiera YAML backend starting DEBUG: <datetime>: Looking up users in YAML backend DEBUG: <datetime>: Looking for data source nodes/ldap.example42.com DEBUG: <datetime>: Found users in nodes/ldap.example42.com DEBUG: <datetime>: Looking for data source env/test DEBUG: <datetime>: Found users in env/test DEBUG: <datetime>: Looking for data source common DEBUG: <datetime>: Found users in common {"al"=>{"home"=>"/home/al", "comment"=>"Al"}, "jenkins"=>{"ensure"=>"absent"}, "qa"=>{"home"=>"/home/qa", "comment"=>"QA Tester"}, "openldap"=>{"groups"=>"apps"}}
This output also tells us where Hiera is actually looking for data sources.
In a real Puppet environment, it is quite useful to use the --yaml
option, which, used with a real facts file of a node, allows us to evaluate exactly how Hiera computes its keys for real servers.
On the Puppet Master, the facts of all the managed clients are collected in $vardir/yaml/facts
, so this is the best place to see how Hiera evaluates keys for different clients:
hiera --yaml /var/lib/puppet/yaml/facts/<node>.yaml ldap_servers
Hiera can use other sources to retrieve the facts of a node and return its key value accordingly. We can interrogate the Puppet Master's inventory service with the following command:
hiera -i ldap.example42.com ldap_servers
We can query mcollective
(from a machine where the mco
client is installed):
hiera -m ldap.example42.com ldap_servers