Extending Puppet
上QQ阅读APP看书,第一时间看更新

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 is common.
  • :backends: This is a string or an array that defines the backends to be used. The default value is yaml.
  • :logger: This is a string of a logger where messages are sent. The default value is console.
  • :merge_behavior: This is a string that describes how hash values are merged across different data sources. The default value is native; the first key found in the hierarchy is returned. Alternative values such as deep and deeper require the deep_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.