Installing and configuring Hiera
From Puppet 3.x, Hiera has been officially integrated, and it is installed as a dependency when we install Puppet.
On Puppet 2.x, we need to install Hiera separately on the node where the Puppet Master resides: we need both the hiera
and hiera-puppet
packages, either via the OS native packaging system or via gem
.
Hiera is not required on the clients unless they operate in a Masterless setup.
Its configuration file is hiera.yaml
, and its path depends on how it is invoked, which can be either of the following ways:
- When invoked from Puppet, the path will be
/etc/puppet/hiera.yaml
(/etc/puppetlabs/puppet/hiera.yaml
for Puppet Enterprise) - When invoked from the CLI or when used within Ruby code, the path is
/etc/hiera.yaml
It makes sense to create a symlink, and be sure to always use and edit the same file using the following command:
ln -s /etc/hiera.yaml /etc/puppet/hiera.yaml
The file is a YAML hash, where the top-level keys are Ruby symbols with a colon (:) prefix, which may either be global or backend-specific settings.
Global settings
Global settings are general configurations that are independent of the used backend. They are listed as follows:
:hierarchy
: This is a string or an array that describes the data sources to be looked for. Data sources are checked from the top to bottom and may be dynamic, that is, contain variables (we reference them with%{variablename}
). The default value iscommon
.:backends
: This is a string or an array that defines the backends to be used. The default value isyaml
.:logger
: This is a string of a logger where messages are sent. The default value isconsole
.:merge_behavior
: This is a string that describes how hash values are merged across different data sources. The default value isnative
; the first key found in the hierarchy is returned. Alternative values such asdeep
anddeeper
require thedeep_merge
Ruby Gem.
Backend-specific settings
Any backend may have its specific settings; the following are used by the native YAML, JSON, and Puppet ones:
:datadir
: This is a string. It is used by the JSON and YAML backends, and it is the directory where the data sources that are defined in the hierarchy can be found. We can place variables (%{variablename}
) here for a dynamic lookup.:datasource
: This is a string. It is used by the Puppet backend. This is the name of the Puppet class where we need to look for variables.
The hiera.yaml examples
The default content for the hiera.yaml
configuration file is as follows:
--- :backends: yaml :yaml: :datadir: /var/lib/hiera :hierarchy: common :logger: console
Using these settings, Hiera key-values are read from a YAML file with the path /var/lib/hiera/common.yaml
.
A real-world configuration that uses the extra GPG backend may look like the following YAML:
--- :backends: - yaml - gpg :hierarchy: - "%{::environment}/nodes/%{::fqdn}" - "%{::environment}/roles/%{::role}" - "%{::environment}/zones/%{::zone}" - "%{::environment}/common" :yaml: :datadir: /etc/puppet/hieradata :gpg: :datadir: /etc/puppet/gpgdata :key_dir: /etc/puppet/gpgkeys
Note
The previous example uses custom $::role
and $::zone
variables that identify the function of the node and its data center, zone, or location. They are not native facts, so we should define them as custom facts or as top scope variables.
Also, an example like the previous one expects to have modules that fully manage the differences in operating systems so that we don't have to manage in our hierarchy different settings for a different OS.
Beware of the hierarchy array. If the individual values begin with a variable to interpolate, we need to quote them with double quotes ("
).
The following is an example with the usage of the file backend to manage not only key-value entries but also whole files:
--- :backends: - yaml - file - gpg :hierarchy: - "%{::env}/fqdn/%{::fqdn}" - "%{::env}/role/%{::role}" - "%{::env}/zone/%{::zone}" - "%{::env}/common" :yaml: :datadir: /etc/puppet/data :file: :datadir: /etc/puppet/data :gpg: :key_dir: /etc/puppet/gpgkeys :datadir: /etc/puppet/gpgdata
Note
Besides the added backend with its configuration, an alternate approach is used to manage different environments (intended as the operational environments of the nodes, for example, Production, Staging, Test, and Development).
Here, to identify the node's operational environment, we use a custom top scope variable or fact called $::env
and not Puppet's internal variable $::environment
. The difference is important since it can lead to confusion.
The $::environment
variable is used to map different Puppet environments to different directories for modules and manifests. This is useful, for example, to test our Puppet code on some servers.
Our custom $::env
variable (we could call it in any other way, such as $::tier
or $::stage
) identifies the operational environment of the node, whether it's used for development or testing, or provides production services. We can use such a variable to manage our configuration logic accordingly.