Table of contents
1.
Introduction⛳
2.
👉Usage of Puppet Code
3.
👉Designing System Configurations in Puppet
3.1.
➡️The Roles and Profiles Method
3.2.
➡️Roles and Profiles Example
3.3.
➡️Designing Advanced Profiles
3.4.
➡️Designing Convenient Roles
4.
👉About Hiera in Puppet
4.1.
🔶Hiera Hierarchies
4.1.1.
💠Hierarchies Interpolate Variables 
4.1.2.
💠Hiera Searches the Hierarchy in Order
4.1.3.
💠Layered Hierarchies 
4.2.
🔶Hiera Configuration Layers
4.2.1.
💠The Global Layer
4.2.2.
💠The Environmental Layer
4.2.3.
💠The Module Layer
5.
👉Getting Started with Hiera
5.1.
⭕Create a hiera.yaml Config File
5.2.
⭕The Hierarchy 
5.3.
⭕Write data: Create a Test Class 
5.4.
⭕Write Data: Set Values in Common Data
5.5.
⭕Write Data: Set Per-Operating System Data
5.6.
⭕Write Data: Set Per-Node Data 
5.7.
⭕Testing Hiera Data on the Command Line 
6.
👉Configuring Hiera
6.1.
🔶Location of hiera.yaml Files
6.2.
🔶Config file syntax
6.2.1.
💠The Default Configuration
6.2.2.
💠The Default Keys
6.2.3.
💠The Hierarchy key
6.2.4.
💠The default_hierarchy Key
6.3.
🔶Configuring a Hierarchy Level: Built-in Backends
6.3.1.
💠Specifying File Paths
6.4.
🔶Configuring a Hierarchy Level: hiera-eyaml
6.5.
🔶Configuring a Hierarchy Level: Legacy Hiera 3 Backends
6.6.
🔶Configuring a Hierarchy Level: General Format
7.
👉Creating and Editing Data
7.1.
🔶Set the Merge Behavior For a Lookup
7.2.
🔶Merge Behaviors
7.2.1.
💠First
7.2.2.
💠Unique
7.2.3.
💠Hash
7.2.4.
💠Deep
7.3.
🔶Set Merge Behavior at Lookup Time
7.4.
🔶Set lookup_options to Refine the Result of a Lookup
7.4.1.
💠The lookup_options Format
7.4.2.
💠Location for Setting lookup_options 
7.4.3.
💠Defining Merge Behavior lookup_options 
7.4.4.
💠Overriding Merge Behavior 
7.4.5.
💠Overriding Merge Behavior in a Call to lookup()
7.4.6.
💠Make Hiera Return Data by Casting to a Specific Data Type
7.5.
🔶Use a Regular Expression in lookup_options
7.6.
🔶Interpolation
7.7.
🔶Interpolate a Puppet Variable
7.8.
🔶Interpolation Functions
7.8.1.
💠The lookup and hiera Function
7.8.2.
💠The alias Function
7.8.3.
💠The literal Function
7.8.4.
💠The scope Function
7.9.
🔶Using Interpolation Functions
8.
👉Looking Up Data with Hiera
8.1.
🔶The Puppet lookup Function
8.2.
🔶The Puppet lookup Command
8.3.
🔶Access Hash and Array elements Using a key.subkey Notation
8.4.
🔶Hiera Dotted Notation
9.
👉Writing New Data Backends
9.1.
🔶data_hash Backends
9.2.
🔶lookup_key Backends
9.3.
🔶data_dig Backends
9.4.
🔶Hiera Calling Conventions for Backend Functions
9.5.
🔶The Options Hash
10.
👉Upgrading To Hiera 5
10.1.
🔶Considerations For hiera-eyaml Users
10.2.
🔶Considerations For Custom Backend Users
10.3.
🔶Considerations For Custom data_binding_terminus Users
10.4.
🔶Enable the Environment Layer for Existing Hiera Data
10.5.
🔶Convert a Version 3 hiera.yaml to Version 5
10.6.
🔶Convert an Experimental(Version 4) hiera.yaml to Version 5
10.7.
🔶Convert Experimental Data Provider Functions to a Hiera 5 data_hash Backend
10.8.
🔶Updated Classic Hiera Function Calls
10.9.
🔶Adding Hiera Data to a Module
10.9.1.
💠Module Data With the params.pp Pattern
10.9.2.
💠Module Data With One-off Custom Hiera Backend
10.9.3.
💠Module Data With YAML Data Files
11.
👉Puppet Language
12.
👉Puppet Man Pages
13.
Frequently Asked Questions
13.1.
What is Puppet?
13.2.
What is DevOps?
13.3.
What language is Puppet built on?
13.4.
Is Puppet an open-source tool?
13.5.
What are the requirements for designing system configurations in puppet
14.
Conclusion
Last Updated: Mar 27, 2024
Medium

About Hiera in Puppet

Author Aashna Luthra
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction⛳

You can automate and manage server setup using a tool called puppet. Puppet is composed of various packages, which are collectively known as the puppet platform. You organize, save, and execute your puppet code using this platform. You can also use hiera in puppet.

intro_image

In this article, we will study about hiera in puppet.

👉Usage of Puppet Code

Modules are used to store puppet code. Use the tested and pre-built modules on Puppet Forge, a repository of hundreds of modules created by Puppet developers and the Puppet community. Modules control particular infrastructure operations like installing and configuring applications. Code and data are both found in modules. What enables you to alter your configuration is the data. 

You can isolate the data from the code and store it in one place using a tool named Hiera. This enables you to establish known parameters and variants, guardrails, and parameters so that your code is thoroughly tested and you can evaluate all the parameter edge cases.

👉Designing System Configurations in Puppet

Designing system configurations in puppet typically involves managing all of the software, services, and configuration, necessary for a user on a specific system. 

➡️The Roles and Profiles Method

The roles and profiles technique can make the code reusable, reconfigurable, and refactorable. It also helps to keep complexity under control.

➡️Roles and Profiles Example

This example shows the complete roles and profiles workflow. Use it to comprehend the roles and profiles approach in its entirety. By modifying this example code to a greater level of complexity, other examples demonstrate how to create complicated configurations.

➡️Designing Advanced Profiles

We gradually redesign or refactor our basic roles and profiles to address real-world issues. With a few slight modifications, the end outcome is the Jenkins profile that Puppet uses in production.

➡️Designing Convenient Roles

There are various methods for creating roles, and you must choose the one that works best for you and your team. Start with specific roles and only move from them in small, careful stages.

👉About Hiera in Puppet

Hiera in Puppet is for two purposes:

  • Key-value pairs should be used to store the configuration data.
  • Look up the information a specific module requires for a particular node while compiling the catalog.

This is achieved by:

  • Auto Parameter searching for classes in the catalog
  • Calls for explicit lookups

The "defaults, with overrides" pattern is used by Hiera's hierarchical lookups, allowing you to declare common data just once and override it when the default doesn't function. Hiera specifies data sources using Puppet facts, allowing you to organize overrides to match your infrastructure. Although employing facts for this purpose is typical, data sources can also be defined without using facts.

🔶Hiera Hierarchies

Hiera searches for information using a hierarchy, an ordered collection of data sources.

hiera.yaml configuration file is used to set up hierarchies. The hierarchy instructs Hiera on accessing a specific data source at each level. Typically, a hierarchy is structured as follows:

---
version: 5
defaults:  # used for any hierarchy level that leaves out these keys.
  datadir: data         # The hiera.yaml directory is relative to this path.
  data_hash: yaml_data  # Use the built-in YAML backend.


hierarchy:
  - name: "Per-node data"                   # Human-readable name.
    path: "nodes/%{trusted.certname}.yaml"  # File path, relative to datadir.
                                   # ^^^ IMPORTANT: include the file extension!


  - name: "Per-datacenter business group data" # Uses custom facts.
    path: "location/%{facts.whereami}/%{facts.group}.yaml"


  - name: "Global business group data"
    path: "groups/%{facts.group}.yaml"


  - name: "Per-datacenter secret data (encrypted)"
    lookup_key: eyaml_lookup_key   # Uses non-default backend.
    path: "secrets/%{facts.whereami}.eyaml"
    options:
      pkcs7_private_key: /etc/puppetlabs/puppet/eyaml/private_key.pkcs7.pem
      pkcs7_public_key:  /etc/puppetlabs/puppet/eyaml/public_key.pkcs7.pem


  - name: "Per-OS defaults"
    path: "os/%{facts.os.family}.yaml"


  - name: "Common data"
    path: "common.yaml"

💠Hierarchies Interpolate Variables 

In most hierarchical levels, variables are integrated into their configuration:

path: "os/%{facts.os.family}.yaml"

Variable syntax with percent and brackets is a Hiera interpolation token. It is comparable to the $expression interpolation tokens used in the Puppet language. Wherever an interpolation token is used, Hiera calculates the variable's value and adds it to the hierarchy.

The facts.os.family accesses members of hashes and arrays using the Hiera unique key.subkey notation. In the Puppet language, it is equivalent to $facts['os']['family'], but the 'dot' notation generates an empty string rather than issuing an error if some data is missing. Be careful to avoid having an empty interpolation match an unwanted path.

💠Hiera Searches the Hierarchy in Order

Hiera verifies the concrete data sources in the order they were written after replacing the variables to create a list of them. In general, Hiera moves on to the next source until it finds one that does exist; then, it uses it if the data source doesn't exist or doesn't specify a value for the current key. The usual merging approach may not always apply; for instance, Hiera can combine the data from all sources and use it.

Priority is given to earlier data sources over newer ones. The node-specific data in the example above has the highest priority and can take precedence over data at any other level.

Business group data is divided between local and global sources, with the local source taking precedence over the latter. All nodes always send common data last.

💠Layered Hierarchies 

Each layer of the data used by Hiera has its own hiera.yaml file.

Every layer can set up an autonomous hierarchy. Hiera combines them into a single super-hierarchy: global → environment → module.

Consider the environment hierarchy in the previous example. If the global hierarchy also included the following:

---
version: 5
hierarchy:
  - name: "Data exported from our old self-service config tool"
    path: "selfserve/%{trusted.certname}.json"
    data_hash: json_data
    datadir: data

Additionally, the default data hierarchy for the NTP module was as follows:

---
version: 5
hierarchy:
  - name: "OS values"
    path: "os/%{facts.os.name}.yaml"
  - name: "Common values"
    path: "common.yaml"
defaults:
  data_hash: yaml_data
  datadir: data

The combined hierarchy used by thrush.example.com in a lookup for the ntp::servers key would be as follows:

  • <CODEDIR>/data/selfserve/thrush.example.com.json
  • <CODEDIR>/environments/production/data/nodes/thrush.example.com.yaml
  • <CODEDIR>/environments/production/data/location/belfast/ops.yaml
  • <CODEDIR>/environments/production/data/groups/ops.yaml
  • <CODEDIR>/environments/production/data/os/Debian.yaml
  • <CODEDIR>/environments/production/data/common.yaml
  • <CODEDIR>/environments/production/modules/ntp/data/os/Ubuntu.yaml
  • <CODEDIR>/environments/production/modules/ntp/data/common.yaml

🔶Hiera Configuration Layers

Hiera uses three distinct configuration levels. Before doing a lookup, each layer's hierarchy is linked into a single super-hierarchy. The three layers are searched in the following sequence: global → environment → module.

💠The Global Layer

The default location of the global layer's configuration file is $confdir/hiera.yaml. By altering the hiera_config setting in puppet.conf, you can modify the location. One global hierarchy exists in Hiera. Since it comes before the environment layer, it can be used for short-term overrides, such as when your operations team wants to skip the usual change processes. 

When migrating your backends to support Hiera 5, it's crucial to keep in mind that the global layer is the only area where legacy Hiera 3 backends can be used. It is compatible with hiera.yaml v5hiera.yaml v3(deprecated), and other configuration formats.

💠The Environmental Layer

By default, the <ENVIRONMENT DIR>/hiera.yaml directory is where the environment layer's configuration file can be found. Most of your Hiera data hierarchy definition takes place at the environment layer. Each Puppet environment has a unique hierarchy configuration that applies to all of the environment's nodes. These configuration formats are supported: v5 and v3 (deprecated).

💠The Module Layer

By default, a module's MODULE>/hiera.yaml contains the configuration file for a module layer. The class parameters of a module are given default values and merge behavior by the module layer. It is a practical replacement for the params.pp pattern.

The environment data specified by a user overrides the default data set by the module's creator because it comes last in Hiera's lookup order.

Each module is capable of having a unique hierarchical configuration. Only keys in the module's namespace can have data bound to them. For instance:

Lookup Key

Relevant Module Hierarchy

ntp::servers

ntp

jenkins::port

jenkins

secure_server

(none)

👉Getting Started with Hiera

This section explains the fundamental ideas and actions you need to get started using Hiera, such as how to write data and create a hiera.yaml configuration file.

⭕Create a hiera.yaml Config File

Hiera's configuration file's name is hiera.yaml and for each environment should be separate.

Make a new file called hiera.yaml in one of your environments' main directories. Add the following content by pasting it there:

# <ENVIRONMENT>/hiera.yaml
---
version: 5

hierarchy:
  - name: "Per-node data"                   # A name that is readable by people.
    path: "nodes/%{trusted.certname}.yaml"  # Relative file path to datadir.
                                   # ^^^ IMPORTANT: include the file extension!

  - name: "Per-OS defaults"
    path: "os/%{facts.os.family}.yaml"

  - name: "Common data"
    path: "common.yaml"

The result is that this file is in a format called YAML, which is used extensively throughout Hiera.

⭕The Hierarchy 

An ordered list of data sources is configured as a hierarchy in the hiera.yaml file.

In the order that they are written, Hiera searches these data sources. Lower-priority sources take precedence over higher-priority ones. Most hierarchy levels use variables to identify a data source, resulting in various nodes receiving diverse data.

Hiera's fundamental idea is a defaults-with-overrides pattern for data lookup, employing a list of data sources specific to each node.

⭕Write data: Create a Test Class 

When applying the catalog, a test class creates a temporary file on the agent and writes the data it receives there.

The first step is to develop a Puppet class for testing since Hiera is used with Puppet code.

1️⃣Create a module called profile if you haven't already done so to implement the roles and profiles technique. Profiles are wrapper classes that configure a layered technology stack using some component modules. 

2️⃣Create a class called hiera_test.pp using your profile module's Puppet Development Kit (PDK).

3️⃣To your hiera test.pp file, add the following code:

# /etc/puppetlabs/code/environments/production/modules/profile/manifests/hiera_test.pp
class profile::hiera_test (
  Boolean             $ssl,
  Boolean             $backups_enabled,
  Optional[String[1]] $site_alias = undef,
) {
  file { '/tmp/hiera_test.txt':
    ensure  => file,
    content => @("END"),
               Data from profile::hiera_test
               -----
               profile::hiera_test::ssl: ${ssl}
               profile::hiera_test::backups_enabled: ${backups_enabled}
               profile::hiera_test::site_alias: ${site_alias}
               |END
    owner   => root,
    mode    => '0644',
  }
}

The test class requests configuration information via class parameters. Using the lookup key CLASS NAME>::PARAMETER NAME>, Puppet searches Hiera for class parameters.

4️⃣Create a manifest with the class included:

# site.pp

include profile::hiera_test

5️⃣Compile the catalog and note that it fails because some values are necessary.

6️⃣Set these keys in your Hiera data to provide the missing class parameters and their values. You can include the settings in your common, OS, or per-node data, depending on where in your hierarchy you wish to put them.

7️⃣Recompile and note that the parameters are now found automatically.

Parameter

Hiera key

$ssl

profile::hiera_test::ssl

$backups_enabled

profile::hiera_test::backups_enabled

$site_alias

profile::hiera_test::site_alias

⭕Write Data: Set Values in Common Data

In the level at the bottom of your hierarchy, set values in your shared data.

This hierarchy level stores the data in a YAML file using the YAML backend. The following details should be put together to determine where to store that file:

✔️The directory of the current setting.

✔️A subdirectory of the environment is the data directory. It is by default <ENVIRONMENT>/data.

✔️File path determined by hierarchy level.

In this case, /etc/puppetlabs/code/environments/production/ + data/ + common.yaml.

Set values for two of the class's parameters by opening that YAML file in an editor.

# /etc/puppetlabs/code/environments/production/data/common.yaml
---
profile::hiera_test::ssl: false
profile::hiera_test::backups_enabled: true

You can exclude the third argument, $site_alias, from the data because the default value for it is defined in the code.

⭕Write Data: Set Per-Operating System Data

The second level of the hierarchy uses the os fact to find its data file. According to the present node's operating system, it can employ a variety of data files.

Assume that your developers use MacBook notebooks with the Darwin OS family for this example. Set $backups_enabled to false to prevent data from being sent to your production backup server when a developer is running an app instance on their laptop. 

If you don't have any Mac laptops running Puppet, pick an OS family that matters to your infrastructure.

Follow the below steps to write data by setting per-operating system data.

1️⃣Find the data file by entering the value you want to target in place of %{facts.os.family}.

/etc/puppetlabs/code/environments/production/data + os/ + Darwin +.yaml  

2️⃣Add the content listed below.

# /etc/puppetlabs/code/environments/production/data/os/Darwin.yaml
---
profile::hiera_test::backups_enabled: false

3️⃣Compile to verify that the override is implemented.

⭕Write Data: Set Per-Node Data 

You can set data by name for each node because the top level of the example hierarchy uses the value of $trusted['certname'] to identify its data file. In this example, we'll assume you have a server called jenkins-prod-03.example.com, set up to serve this application at the hostname ci.example.com and configured to use SSL. Pick the name of a real server you can use to test this out.

1️⃣Replace %{trusted.certname} with the name of the node you're aiming for to find the data file.

/etc/puppetlabs/code/environments/production/data/ + nodes/ + jenkins-prod-03.example.com + .yaml

2️⃣In an editor, open that data file in step 1, and then add the following information:

# /etc/puppetlabs/code/environments/production/data/nodes/jenkins-prod-03.example.com.yaml
---
profile::hiera_test::ssl: true
profile::hiera_test::site_alias: ci.example.com

3️⃣Compile to verify that the override is implemented.

⭕Testing Hiera Data on the Command Line 

It is crucial to double-check the data a node receives as you set Hiera data or restructure your hierarchy. The puppet lookup command facilitates interactive data testing. For example:

puppet lookup profile::hiera_test::backups_enabled --environment production --node jenkins-prod-03.example.com

This gives back the word true. To efficiently employ the puppet lookup command:

✔️Run the command on a node connected to your Puppet Server or a node with access to a complete copy of your Puppet code and configuration.

✔️The node you are testing against should have made at least one communication with the server so that the lookup command can access its information (otherwise you need to supply the facts yourself on the command line).

✔️To provide the command access to your live data, ensure that the command uses the global confdir and codedir. Include –codedir and –confdir in the command line if you're not executing puppet lookup as root user.

✔️When using PuppetDB, you can use --node to use any node's facts in a lookup by specifying –node<NAME>. Hiera can automatically obtain the actual facts for that node to resolve data.

✔️Provide facts in a YAML or JSON file and include that file as part of the command with the --facts<FILE> if you do not use PuppetDB or wish to test for a set of facts that do not exist. Run facter -p –json > facts.json to obtain a file containing all the facts rather than create one from scratch. Copy the facts.json file to your Puppet Server node, make any necessary changes, and then paste it from a node similar to the one you wish to analyse.

For several systems, the Puppet Development Kit includes preconfigured fact sets. If you wish to test against platforms you don't have or if you want "typical facts" for a particular platform, you can use those.

✔️Try rerunning the command with –explain if you are not receiving the values you anticipate. Hiera outputs a thorough explanation of the data sources it examined and the results it discovered with the –explain flag.

👉Configuring Hiera

Hiera.yaml is the name of the Hiera configuration file. It configures the hierarchy for a certain layer of data. This section explains about configuring hiera.

🔶Location of hiera.yaml Files

In a typical deployment, numerous hiera.yaml files are included. The module and environment layers of Hiera's configuration hierarchy generally contain several instances.

The locations of each layer's configuration files are:

Layer

Location

Example 

Global

$confdir/hiera.yaml

 

/etc/puppetlabs/puppet/hiera.yaml C:\ProgramData\PuppetLabs\puppet\etc\hiera.yaml

Environmental

<ENVIRONMENT>/hiera.yaml

 

/etc/puppetlabs/code/environments/production/hiera.yaml C:\ProgramData\PuppetLabs\code\environments\production\hiera.yaml

Module

<MODULE>/hiera.yaml

 

/etc/puppetlabs/code/environments/production/modules/ntp/hiera.yaml C:\ProgramData\PuppetLabs\code\environments\production\modules\ntp\hiera.yaml

The following order is followed by Hiera's data search: global➡ environment➡ module.

🔶Config file syntax

There is a hash with up to four top-level keys in the YAML file hiera.yaml. In the hiera.yaml file, the following keys are found:

✔️version - Essential. It must be 5 without any quotation marks.

✔️defaults: A hash that can be used to establish a default datadir, backend, and hierarchy level parameters.

✔️hierarchy: An array of hashes used to set the hierarchy's tiers.

✔️default_hierarchy: It is an array of hashes that establishes a default hierarchy that will only be used if the standard hierarchy entries are unsuccessful. Only acceptable in a module's hiera.yaml file.

version: 5
defaults:  # Any hierarchy level that doesn't include these keys is used.
  datadir: data         # The hiera.yaml directory is relative to this path.
  data_hash: yaml_data  # Use the built-in YAML backend.

hierarchy:
  - name: "Per-node data"                   # Human-readable name.
    path: "nodes/%{trusted.certname}.yaml"  # Relative file path to datadir.
                                   # ^^^ IMPORTANT: include the file extension!


  - name: "Per-datacenter business group data" # Uses custom facts.
    path: "location/%{facts.whereami}/%{facts.group}.yaml"


  - name: "Global business group data"
    path: "groups/%{facts.group}.yaml"


  - name: "Per-datacenter secret data (encrypted)"
    lookup_key: eyaml_lookup_key   # Uses a non-default backend.
    path: "secrets/nodes/%{trusted.certname}.eyaml"
    options:
      pkcs7_private_key: /etc/puppetlabs/puppet/eyaml/private_key.pkcs7.pem
      pkcs7_public_key:  /etc/puppetlabs/puppet/eyaml/public_key.pkcs7.pem


  - name: "Per-OS defaults"
    path: "os/%{facts.os.family}.yaml"


  - name: "Common data"
    path: "common.yaml"

💠The Default Configuration

version: 5
hierarchy:
  - name: Common
    path: common.yaml
defaults:
  data_hash: yaml_data
  datadir: data

 

Only if the file is present and specifies version: 5 are these defaults applied. It disables Hiera for that layer if hiera.yaml is missing. Different defaults apply if it specifies a different version.

💠The Default Keys

You can omit the lookup function and datadir keys from your hierarchy levels by setting default values for those keys using the defaults key. A hash with the keys datadiroptions, and one of the mutually exclusive lookup function keys must be the value of defaults. A hash can have up to three keys.

Any file-based hierarchy level that doesn't define its datadir will use datadir as the default value. The datadir is the directory containing the data in the same directory as the hiera.yaml configuration file if it is not specified.

options: a generic value for options applied to any hierarchy level without a specific value.

Any hierarchy level that doesn't define its lookup function keys is used. That must be one of:

✔️data_hash : Key-value pairs are hashed by the data hash (typically from a data file)

✔️lookup_key: generates values one key at a time (typically for a custom data provider)

✔️data_dig: Key by key values are produced using data dig (for a more advanced data provider)

✔️hiera3_backend: An old Hiera 3 backend is called out by the data provider hiera3 backend (global layer only).

The YAML, JSON, and HOCON built-in data providers have a key called data hash and a value called yaml_data, json_data, or hocon_data respectively. 

💠The Hierarchy key

The hierarchy key sets the hierarchy's tiers. An array of hashes must be the value of the hierarchy. The hash's keys should be four spaces indented to align with the first key. To visually separate hashes, place an empty line between them. For instance:

hierarchy:
  - name: "Per-node data"
    path: "nodes/%{trusted.certname}.yaml"

  - name: "Per-datacenter business group data"
    path: "location/%{facts.whereami}/%{facts.group}.yaml"

💠The default_hierarchy Key

A top-level key is the default hierarchy. When and only when the ordinary hierarchy's lookup fails to yield a value, it is started. The usual merging rules are applicable inside this default hierarchy. Environment or global layers cannot contain the default hierarchy.

The values found in the default_hierarchy have no impact on the values found in the regular hierarchy if lookup_options are used, and vice versa. The lookup function only uses the merge parameter in the typical hierarchy. It has no impact on how a value is put together in the default_hierarchy. Use of the lookup_options found in the default hierarchy is the only way to change that.

🔶Configuring a Hierarchy Level: Built-in Backends

YAML, JSON, and HOCON are the three built-in backends for Hiera. These all use files as their data sources. These backends can be used in any hierarchy, and you can also mix them with unique backends. Set default settings for the datadir and data_hash keys if most of your data is in a single file type.

The following keys are required for each hierarchy level of YAML/JSON/HOCON:

✔️name — This level's name is displayed in debug messages and --explain output.

✔️The data files for this hierarchy level are path, paths, glob, globs, or mapped_paths (choose one).

  • These paths require a file extension, permit variable interpolation, and are relative to the datadir.
  • mapped_paths do not support glob expansion.

✔️data_hash: specifies which backend to use. It can be omitted if a default is set. One of the following must apply to the value:

  • For YAML, use yaml_data.
  • For JSON, use json_data
  • For HOCON, use hocon_data.

✔️datadir: Data files are saved in the datadir directory. If the default is set, it may be omitted.

  • The entire path to the data directory is /etc/puppetlabs/code/environments/production/data if the config file is located at /etc/puppetlabs/code/environments/production/hiera.yaml and the datadir is set to data.
  • The datadir can be set to an absolute path in the global layer, but it must always be relative to the other layers.
  • Interpolating variables is supported by datadir.

💠Specifying File Paths

Key

Data Type

Expected Value

path

String

One file path.

paths

Array

There are countless file paths. When many files are present, Hiera searches each one in the order they were written, acting as if it were a sub hierarchy.

glob

String

One glob pattern akin to a shell that might match any number of files. If more than one file is discovered, Hiera scans them all in alphabetical order.

globs

Array

numerous shell-like glob designs are possible. If more than one file is discovered, Hiera scans them all in alphabetical order (ignoring the order of the globs).

 

mapped_paths

Array or Hash

A fact that consists of an assortment (or hash) of values. These values are expanded by Hiera to create an array of paths.

🔶Configuring a Hierarchy Level: hiera-eyaml

A native interface for the Hiera eyaml extension is included in Hiera 5 (Puppet 4.9.3 and later), which retains data encrypted on a disc but permits Puppet to read it during catalog building. The eyaml backend in hiera.yaml is similar to the conventional built-in backends, with a few exceptions: it uses a lookup_key rather than data_hash, and it needs an options key to find the decryption keys. It should be noted that the eyaml backend can read both plain-text and encrypted yaml files.

These keys are required for each level of the eyaml hierarchy:

✔️name — This level's name is displayed in debug messages and ---explain output.

✔️lookup_key: Which backend should be used? eyaml_lookup_key must be the value and should be used instead of using the data hash setting. 

✔️The data files for this hierarchy level are path, paths, mapped paths, glob, or globs (choose one). These paths require a file extension, permit variable interpolation, and are relative to the datadir. Normally, you'll use .eyaml in this situation. They function the same way they do with more common backends.

✔️datadir: Data files are saved in the datadir directory. If the default is set, it may be omitted. The same principles apply as they do to ordinary backends.

✔️options: A hash of hiera-eyaml-specific options primarily used to set up decryption. The following keys must be present in this hash for the default encryption algorithm:

          ➡pkcs7_private_key: PKCS7 private key location specified by pkcs7 private key.     

          ➡pkcs7_public_key: public key location specified by pkcs7 public key.

          If you use a different encryption plugin, look up the encryption options in the plugin's  

documentation. To replace the pkcs7 options, set an encrypt_method option and certain plugin-specific parameters.

          In this hash, regular strings may be used as keys; symbols are unnecessary.

The options and file path keys support variable interpolation.

a hierarchy-level illustration

hierarchy:
  - name: "Per-datacenter secret data (encrypted)"
    lookup_key: eyaml_lookup_key
    path: "secrets/%{facts.whereami}.eyaml"
    options:
      pkcs7_private_key: /etc/puppetlabs/puppet/eyaml/private_key.pkcs7.pem
      pkcs7_public_key:  /etc/puppetlabs/puppet/eyaml/public_key.pkcs7.pem

🔶Configuring a Hierarchy Level: Legacy Hiera 3 Backends

You can employ specialized data backends created for Hiera 3 in your global hierarchy if you rely on them. The environment and module layers do not support them. These keys are required for each level of the legacy hierarchy:

✔️name — This level's name is displayed in debug messages and —explain output.

✔️path or paths — The data files for this hierarchy level are path or paths.

        ⏹️Even though you would have left it out in the v3 hiera.yaml file, you still need to 

             include the file extension for backends that work with files.

        ⏹️Don't use a file extension for backends that don't support files.

✔️hiera3_backend —  is the recommended legacy backend. You would enter this name in the :backends key of the config file for version 3.

✔️datadir: Data files are saved in the datadir directory. Only set this if your backend's backend-specific options demand the a:datadir setting. 

        ⏹️The entire path to the data directory is /etc/puppetlabs/code/environments/production/data if the config file is located at /etc/puppetlabs/code/environments/production/hiera.yaml and the datadir is set to data. Remember that Hiera v3 uses "hieradata" rather than "data"

        ⏹️You can set the datadir in the global layer to an absolute path.

✔️options — A hash containing any backend-specific settings (apart from datadir) that your backend requires. This would have been in a top-level key named after the backend in the v3 configuration. Regular strings are acceptable as keys. They are changed into symbols for the backend by Hiera.

Using legacy backends, the example below illustrates pretty much identical hiera.yaml files for versions 3 and 5:

# hiera.yaml v3
---
:backends:
  - mongodb
  - xml

:mongodb:
  :connections:
    :dbname: hdata
    :collection: config
    :host: localhost

:xml:
  :datadir: /some/other/dir

:hierarchy:
  - "%{trusted.certname}"
  - "common"

# hiera.yaml v5
---
version: 5
hierarchy:
  - name: MongoDB
    hiera3_backend: mongodb
    paths:
      - "%{trusted.certname}"
      - common
    options:
      connections:
        dbname: hdata
        collection: config
        host: localhost

  - name: Data in XML
    hiera3_backend: xml
    datadir: /some/other/dir
    paths:
      - "%{trusted.certname}.xml"
      - common.xml

🔶Configuring a Hierarchy Level: General Format

Hiera supports custom backends. The following keys are required for the hash that represents each hierarchy level:

✔️name — This level's name is displayed in debug messages and ---explain output.

✔️A backend key, one of which must be:

     ⏹️data_hash

     ⏹️lookup_key

     ⏹️data_dig - A more specialized version of lookup_key called data dig is appropriate when the backend is a database. Unlike lookup_keydata_dig resolves dot-separated keys.

     ⏹️hiera3_backend - (global layer only)

✔️path or URI (Universal Resource Identifier) key - if the backend so requests. These keys support variable interpolation. There are provided the following path/URI keys:

      ⏹️path

      ⏹️paths

      ⏹️mapped_paths

      ⏹️glob

      ⏹️globs

      ⏹️uri

      ⏹️uris- These URIs, often known as paths, function similarly for built-in backends. Any backend that supports a path automatically supports paths, glob, and globs because Hiera handles the task of finding files. Any data source type can be represented by uri (string) and uris (array). Before calling the backend, Hiera does not check if URIs can be resolved, and it is not required to comprehend any specific URI schema. A backend can only use the options key to locate its data and omit the path/URI key entirely.

✔️datadir — The location of the data files: The path points to the directory containing hiera.yaml. Only necessary if the backend uses the path(s) and glob(s) keys; optional if a default is set.

✔️options — A hash of additional options for the backend, such as database login information or where to find a decryption key. Variable interpolation is supported for all values in the options hash.

The function's name that implements the backend API must be the value of any key you use. Remember that the decision is made here by the person who implemented the specific backend, not the user.

👉Creating and Editing Data

This section discusses merge behaviour and interpolation, two crucial features of using Hiera.

🔶Set the Merge Behavior For a Lookup

In Hiera, various values for a given key are frequently found in distinct data sources. By default, Hiera only returns the first value it discovers, but it has the option to keep looking and combine all the values it finds.

✔️There are two ways to configure the merge behavior for a lookup:

       ⏹️At lookup time: Although it supports the lookup method, automated class parameter lookup is not supported.

       ⏹️Using the lookup_options key in Hiera data. Both manual and automatic lookups can use this. Additionally, it enables module authors to define default actions that users can override.

✔️Both of these methods allow you to define a merge behavior as a string, such as 'first,' or a hash, such as { "strategy" => "first"}. The hash syntax can be used with different merging types and deep merges (which provide more options).

🔶Merge Behaviors

You can pick between the firstuniquehash, and deep merge behaviors. One of the following identifiers should be used when describing a merging behavior:

✔️'first', {'strategy' => 'first'}, or nothing.

✔️'unique' or {'strategy' => 'unique'}.

✔️'hash' or {'strategy' => 'hash'}.

✔️'deep' or {'strategy' => 'deep', <OPTION> => <VALUE>, ...}. Valid options:

         ⏹️'knockout_prefix' - string or undef; disabled by default.

         ⏹️'sort_merged_arrays' - Boolean; default is false

         ⏹️'merge_hash_arrays' - Boolean; default is false

💠First

The first value for the key is returned in a first-found lookup, and the remaining values are ignored. This is how Hiera usually acts.

Specify this merge behavior with one of these:

  • 'first'
  • {'strategy' => 'first'}
  • lookup($key)
  • Nothing (because it’s the default)

💠Unique

To create a merged, flattened array with all matching values for a key, a unique merge, also known as an array merge, combines any number of array and scalar (string, number, boolean) values. All redundant values are eliminated. If any of the values are hashes, the lookup fails. From highest priority to lowest priority, the outcome is arranged.

Specify this merge behavior with one of these:

  • 'unique'
  • lookup($key, { 'merge' => 'unique' })
  • {'strategy' => 'unique'}

💠Hash

To create a merged hash of all keys that match their corresponding values, a hash merge combines the keys and values of any number of hashes. If any of the values are not hashes, then none of the matches are valid, and the lookup fails. Hiera uses the value from the data source with the highest priority when multiple source hashes with the same key exist; it does not recursively merge the values.

Puppet hashes maintain the sequential sequence of its keys. Hiera starts with the data source with the lowest priority when merging hashes. It changes the current keys in place and adds new keys to the end of the hash for each source with a higher priority.

# web01.example.com.yaml
mykey:
  d: "per-node value"
  b: "per-node override"
# common.yaml
mykey:
  a: "common value"
  b: "default value"
  c: "other common value"
`lookup('mykey', {merge => 'hash'})

Returns the following:

{
  a => "common value",
  b => "per-node override", # Use the higher-priority source's value while maintaining the #lower-priority source's order.
  c => "other common value",
  d => "per-node value",
}

Specify this merge behavior with one of these:

  • 'hash'
  • lookup($key, { 'merge' => 'hash' })
  • {'strategy' => 'hash'}

💠Deep

A deep merge creates a merged hash by combining the keys and values of any number of hashes. It is a compact External Node Classifier(ENC) with an array of class names. Hiera recursively merges the source hashes if the same key appears in more than one of them:

✔️Another deep merge is used to combine hash values.

✔️Merged array values are used. This is distinct from the singular merge. The result is sorted in the opposite direction of the unique merge, from lowest priority to highest. The outcome is not flattened and can therefore include nested arrays. The result may also alter based on the merge_hash_arrays, and sort_merged_arrays settings.

✔️In a first-found lookup, the highest priority value is used for scalar (String, Number, and Boolean) variables.

Specify this merge behavior with one of these:

  • 'deep'
  • include(lookup($key, { 'merge' => 'deep' }))
  • {'strategy' => 'deep', <OPTION> => <VALUE>, ...} — Adjust the merge behavior with additional options.

🔶Set Merge Behavior at Lookup Time

To override previously defined merging behavior for a key, use merge behavior at lookup time. To specify a merge behavior as a parameter or flag, use the lookup function or the puppet lookup command.

Function example:

# Merge several arrays of class names into one array:
lookup('classes', {merge => 'unique'})

Command line example:

$ puppet lookup classes --merge unique --environment production --explain

🔶Set lookup_options to Refine the Result of a Lookup

You can choose merge behavior and use the convert_to key to receive automatic type conversion when setting lookup_options, which helps you further filter the results of a lookup.

💠The lookup_options Format

The value of lookup_options is a hash. It follows the following format: 

lookup_options:
  <NAME or REGEXP>:
    merge: <MERGE BEHAVIOR>

💠Location for Setting lookup_options 

The default merging behavior for other keys in your data can be changed by setting the lookup options metadata keys in Hiera data sources, including module data. In any lookup that doesn't specifically override a key's configured merge behavior, Hiera uses that behavior.

💠Defining Merge Behavior lookup_options 

Set the lookup options key in your Hiera data source to configure merge behavior:

# <ENVIRONMENT>/data/common.yaml
lookup_options:
  ntp::servers:     # Name of key
    merge: unique   # Merge behavior as a string
  "^profile::(.*)::users$": # Regexp: `$users` parameter of any profile class
    merge:          # Merge behavior as a hash
      strategy: deep
      merge_hash_arrays: true

💠Overriding Merge Behavior 

A hash merge is carried out when lookup options are given to Hiera. For specific keys, higher-priority sources take precedence over lower-priority lookup options. A default merging behavior for a specific key can be configured in a module, and users of that module can define overrides in the environment layer. The following setup, as an illustration, specifies lookup_options for several keys in a module. The environment can override one of the keys, but the others keep their configuration.
 

# <MYMODULE>/data/common.yaml
lookup_options:
  mymodule::key1:
    merge:
      strategy: deep
      merge_hash_arrays: true
  mymodule::key2:
    merge: deep
  mymodule::key3:
    merge: deep
    
# <ENVIRONMENT>/data/common.yaml
lookup_options:
  mymodule::key1:
    merge: deep  # this overrides the merge_hash_arrays true

💠Overriding Merge Behavior in a Call to lookup()

The configured merge behavior is overridden when a merge behavior is specified as an argument to the lookup function. For instance, with the setup described:

lookup('mymodule::key1', 'strategy' => 'first')

The lookup_options setting uses strategy 'first' rather than 'deep' for the lookup of 'mymodule::key1'.

💠Make Hiera Return Data by Casting to a Specific Data Type

Use the lookup options key convert to, which accepts either a type name or an array of type names and arguments, to convert values from Hiera backends to rich data values that are not representable in YAML or JSON.

You get automatic type-checking with convert_to. For instance, an error is raised if you specify a convert_to the type "Enum['red', 'blue', 'green']". The value searched up is not one of those strings. When the Puppet code performing the lookup does not provide adequate type checking, you can use this to assert the type.

Specify the data type in string form for types with single-value constructors, such as Integer, String, Sensitive, or Timestamp.

For example, to turn a String value into an Integer

mymodule::mykey: "61"
lookup_options:
  mymodule::mykey:
    convert_to: "Integer"

To make a value Sensitive

mymodule::mykey: 61
lookup_options:
 mymodule::mykey:
   convert_to: "Sensitive"

Specify the type and the arguments in an array if the constructor needs them. Additionally, if a data type constructor accepts optional parameters, you can define it in this manner.

For instance, to translate the string "042" into an integer with a base ten detailed interpretation of the string:

mymodule::mykey: "061"
lookup_options:
  mymodule::mykey:
    convert_to:
      - "Integer"
      - 10

By default, the leading would be interpreted as an octal number (octal 061 is decimal 49):

To turn a non-array value into an array

mymodule::mykey: 61
lookup_options:
 mymodule::mykey:
   convert_to:
     - "Array"
     - true

🔶Use a Regular Expression in lookup_options

In lookup_options, you can simultaneously set merging behavior for multiple lookup keys by using regular expressions.

The merge behavior for profile::server::usersprofile::postgresql::users, and profile::jenkins::server::users is set by a regular expression key like '^profile::(.*)::users$'.  Based on Ruby's regular expressions, Puppet's regular expression support is used for regular expression lookup options. To use a regular expression in the lookup_options function:

✔️Create a quoted string using the pattern. Avoid using the forward-slash (/.../) regular expression delimiters from Puppet.

✔️The start-of-line metacharacter (^, commonly known as a carat) should be used to start the pattern. Hiera uses it as a literal key name rather than a regular expression if isn't the first character.

✔️If this data source is in a module, addand the module's namespace, composed of the module's complete name and the::namespace separator, after. For instance, the ntp module requires that each regular expression lookup option begins with ^ntp::. Any other approach will lead to mistakes.

All lookup keys that match that pattern are subject to the merge behavior you specify for that pattern. Hiera resolves conflicts when several lookup alternatives may be applicable for a given key. For instance, Hiera uses a literal option when one is provided (rather than a regular expression). Otherwise, Hiera applies the first regular expression, in the order they occur in the module code, that matches the lookup key.

🔶Interpolation

Using the syntax %{variable} in Hiera, you can interpolate or insert a variable's value into a string. Hiera employs interpolation twice:

  • The path, paths, glob, globs, uri, uris, datadir, mapped_paths, and options of a hierarchy level can all be interpolated with variables. This enables every node to receive a unique hierarchy.
  • Data: Interpolation can be used to prevent a recurrence. This can be done in one of two ways:

⏹️Refer to the fact directly rather than manually transcribing it if a value always involves the value of a fact (for instance, if you need to specify a mail server and have one mail server with a predictable name per domain).

⏹️Write out the value for one key and reuse it for the others using the lookup or alias interpolation functions if many keys need to share the same value. As a result, updating data is simpler because you only need to make a single modification to a specific value.

🔶Interpolate a Puppet Variable

The value of a Puppet top scope variable is the most typical thing to interpolate. The most practical and predictable variables for Hiera are the facts hash, trusted hash, and server_facts hash. Avoid using namespace variables from classes, local variables, Hiera-specific pseudo-variables, and namespaced variables from classes unless the class has already been evaluated(pseudo-variables are not supported in Hiera 5).

See Puppet variables given to Hiera if you are using the pseudo-variables in Hiera 3. Facts can be accessed by puppet in two different ways: collectively in the facts hash ($facts['networking']), and separately as top-scope variables ($networking).

When using distinct fact variables, be sure to give them the (empty) top-scope namespace, as in:

%{::networking} ✅

%{networking} ❌

A Puppet variable can be interpolated using its name without the leading dollar sign ($). When attempting to access a data structure member, use the Hiera key.subkey notation. To interpolate the value of $facts['networking']['domain’] for instance “smtpserver: "mail.%{facts.networking.domain}" should be written.

🔶Interpolation Functions

Interpolation functions can be used in Hiera data sources to insert non-variable values. These are not the same as Puppet functions; only Hiera interpolation tokens support them. Five interpolation methods exist:

✔️lookup - interpolates the value from a key's search in Hiera into a string.

✔️hiera- hiera is another word meaning lookup.

✔️alias- a key is looked up in Hiera using the alias function, and the value is used to replace the surrounding string. If the value is exactly one alias, the result has the same data type as the aliased key and is not converted to a string.

✔️literal - a method for writing the percent sign (%) literally without inadvertently interpolating anything.

✔️scope- An alternative method of interpolating a variable is scope. generally ineffective.

💠The lookup and hiera Function

The lookup and hiera interpolation functions return a value after looking up a key. Any other outcome will result in an error. The lookup must return a string. The hiera interpolation functions retrieve a value from a key and return it. Any other outcome will result in an error. The lookup must return a string.

Assume, for instance, that the MySQL profile requires a database server and that you have previously configured that hostname in the data. You can type:

# in location/pdx.yaml:
profile::mysql::public_hostname: db-server-01.pdx.example.com

# in location/bfs.yaml:
profile::mysql::public_hostname: db-server-06.belfast.example.com

# in common.yaml:
profile::wordpress::database_server: "%{lookup('profile::mysql::public_hostname')}"

💠The alias Function

You can reuse Hash, Array, Boolean, Integer, or String values by using the alias function. When you interpolate an alias in a string, Hiera completely replaces that string with the aliased value while maintaining the original data type. For instance:

original:
  - 'one'
  - 'two'
aliased: "%{alias('original')}"

💠The literal Function

The literal interpolation function allows you to escape a literal percent sign (%) in Hiera data to prevent interpolation from occurring where it is not desired. This is helpful, for instance, when working with Apache configuration files that contain text such as %{SERVER_NAME}. For instance:

server_name_string: "%{literal('%')}{SERVER_NAME}"

💠The scope Function

The scope interpolation function interpolates variables. It functions in the same way as variable interpolation. The function's argument is a variable's name. The following two values would be the same:

smtpserver: "mail.%{facts.domain}"
smtpserver: "mail.%{scope('facts.domain')}"

🔶Using Interpolation Functions

To insert non-variable values using an interpolation function, write the following:

  • Write the function's name
  • An opening parenthesis.
  • One argument should be passed to the function using single or double quote marks.
  • If the surrounding string contains single quotation marks, use double quotation marks instead.
  • A closing parenthesis.

For example:

wordpress::database_server: "%{lookup('instances::mysql::public_hostname')}"

👉Looking Up Data with Hiera

This section explains how Puppet looks up data with Hiera for class parameter values.

🔶The Puppet lookup Function

The lookup function uses Hiera to find a value for a given key. The lookup function fails compilation by default if no values are available and return the first value discovered. The lookup function can also be set up to combine many values into one. Hiera examines up to four hierarchy layers of data when looking up a key in the following order:

  • Global hierarchy.
  • The hierarchy of the current environment.
  • If the key has the format <MODULE NAME>::<SOMETHING>, then the indicated module's hierarchy will be displayed.
  • The lookup is repeated if steps 1-3 did not provide a value and the module's hierarchy contains a default_hierarchy element in its hiera.yaml file if not found.

🔶The Puppet lookup Command

The puppet lookup command is the command line interface (CLI) for Puppet's lookup feature. Using the puppet lookup command, you can perform Hiera lookup from the command line. It must be executed on a node that contains a copy of your Hiera data. You can use sudo to manage puppet lookup after logging onto a Puppet Server node.

This command's most famous version is:

puppet lookup <KEY> --node <NAME> --environment <ENV> --explain

You can test and explore your data by using the puppet lookup command, which searches your Hiera data and provides a value for the provided lookup key. The hiera command has been replaced. Hiera uses a node's facts to determine where to get the relevant data sources. puppet lookup by default uses information from the node you execute the command on, but by using the –node NAME option, you can obtain information for any other node. The lookup command, if feasible, uses the actual stored facts from PuppetDB for the given node. Pass facts from a JSON or YAML file using the --facts FILE option to pass facts if PuppetDB is not configured or if you want to offer additional fact values.

For example: 

Puppet Server node’s facts can be used to look up key_name

$ puppet lookup key_name

🔶Access Hash and Array elements Using a key.subkey Notation

Hiera's key.subkey notation can be used to access hash and array members. When doing the following actions, you can access hash and array elements:

  • Variable interpolation into hiera.yaml or a data file. Deeply nested data structures make up many of the most widely used variables, such as facts and trusted.
  • Using the lookup function or the puppet lookup command. Look up a single member of a hash or array using lookup('some_key.subkey'), if the value of lookup('some_key') is a hash or array.
  • Using interpolation methods that perform Hiera lookups, such as lookup and alias.

🔶Hiera Dotted Notation

Only literal keys are recognized in the Hiera dotted notation; arbitrary expressions are not supported. Literal dots can be included in a hash's key text. A hash holding all certificate extensions for a node, for instance, is the value of $trusted['extensions'], although some of its keys can be raw OID strings like "1.3.6.1.4.1.34380.1.2.1." The key.subkey notation in Hiera can be used to access those values, but you must enclose the affected subkey in single or double quotation marks. Use the opposite type of quote for the subkey and escape quotes (as required by your data file format) to prevent prematurely terminating the entire string if the compound as the real key is quoted (for instance, as needed for the lookup interpolation function).

For example:

aliased_key: "%{lookup('other_key.\"dotted.subkey\"')}"
# Or:
aliased_key: "%{lookup(\"other_key.'dotted.subkey'\")}"

👉Writing New Data Backends

The term "backend" refers to a special Puppet function that receives a specific set of parameters and whose return value adheres to a specific format. To find its data, the function is free to take any action. There are differences in the performance characteristics of various forms of data. Three different backend kinds, namely data_hash, lookup_key, and data_dig, are supported by Hiera to ensure that it functions effectively with all types of data sources.

🔶data_hash Backends

A complete data source is read at once by a data_hash backend function, which then delivers the contents as a hash. The built-in backends for YAML, JSON, and HOCON are all data_hash operations. The function must either invoke the not found method of the context object or return a hash of the lookup keys and their corresponding values. The hash could be null.

Example signature in puppet language:

function mymodule::hiera_backend(
  Hash                  $options,
  Puppet::LookupContext $context,
)

🔶lookup_key Backends

A single key is looked up, and its value is returned by a backend function called the lookup_key. For instance, the lookup key function in the hiera_eyaml backend is built-in. The function must either return a value for the requested key or call the not_found method of the context object. It may give a value of undef.

Example signature in puppet language:

function mymodule::hiera_backend(
  Variant[String, Numeric] $key,
  Hash                     $options,
  Puppet::LookupContext    $context,
)

🔶data_dig Backends

In contrast to a lookup_key function, which looks up a single key, a data_dig backend function looks up a single set of keys and subkeys.

Using key.subkey notation, Hiera enables you to look for specific elements of hash and array values. Use data_dig types in cases where:

✔️Lookups are relatively costly.

✔️The data source can separate elements from the hash and array values.

✔️The lookup function receives the key.subkey requests to access portions of big data structures.

The function must call the context object’s not_found method or return a value for the requested sequence of key segments. 

Example signature in puppet language:

function mymodule::hiera_backend(
  Array[Variant[String, Numeric]] $segments,
  Hash                            $options,
  Puppet::LookupContext           $context,
)

🔶Hiera Calling Conventions for Backend Functions

For each distinct key lookup, Hiera calls the data_hash function once per data source, the lookup_key functions once per data source, and the data_dig functions once per data source for each distinct sequence of key segments.

However, depending on the choices for the path, paths, uri, uris, glob, and globs, a given hierarchy level may refer to several data sources. Each hierarchy level is handled by Hiera as follows:

✔️When using the path, paths, glob, or globs settings, Hiera detects which files are present and makes a separate call to the function for each one. The function will not be invoked if no files are discovered.

✔️When using the uri or uris options, Hiera makes one call to the function for each URI.

✔️Hiera only calls the function once if none of the options are used.
 

If the inputs change, Hiera can invoke a function for a specific data source again. When Hiera.yaml interpolates a local variable into a file path, it executes the function again for scopes where the variable's value has changed. You must interpolate only facts, trustworthy facts, and server facts in the hierarchy because doing otherwise severely impacts performance.

🔶The Options Hash

The choices The following keys can be found in a hash, depending on whether path, glob, uri, or mapped_paths have been set:

✔️path: The complete disc location of a file. It is present only when path, paths, glob, globs, or mapped_paths are present in the hierarchy. Without the file, Hiera never calls the function.

✔️uri: A uri that your function can use to find a data source. Only when uri or uris are present in the hierarchy is it current. Before sending the URI to the function, Hiera does not validate it.

✔️Every key from the options is set for the hierarchy level. List any options your backend requires or accepts. The path and uri keys are reserved.

👉Upgrading To Hiera 5

Hiera 5 upgrade has various significant benefits. A real environment data layer makes it easier to use multiple backends in your hierarchy, create a custom backend, and make changes to your hierarchy routine and testable.

The built-in data formats used by Hiera 3 are also used by Hiera 5.

🔶Considerations For hiera-eyaml Users

For Hiera 5, we included a built-in hiera-eyaml backend in Puppet 4.9.3. This implies that you can transfer your current encrypted YAML data into the environment layer together with your other data.

🔶Considerations For Custom Backend Users

Await the release of new backends. However, upgrading will be more difficult if you continue to use custom Hiera 3 backends because you can't migrate legacy data to the environment layer until a Hiera 5 backend is available.

🔶Considerations For Custom data_binding_terminus Users

The puppet.conf file has an obsolete data_binding_terminus setting that modifies how automated class parameter search operates. Hiera (the default), none (deprecated; disables auto-lookup), or the name of a custom plug-in can be used to specify this option. The outcomes of automatic lookups for the same keys change from function-based lookups when a custom data_binding_terminus is used. 

It's safe to upgrade your configuration to Hiera 5 if you're one of the few people who use this functionality because you've already had to adapt your Puppet code to prevent that issue. It would help if you replace your custom terminus with a Hiera 5 backend because we deprecated that extension point. Integrate your Hiera 5 backend into your hierarchies, after which you should remove the data_binding_terminus setting.

Per-environment hierarchy configuration is one of Hiera 5's core features. Local hiera.yaml files are more logical and practical than one global hierarchy because you most likely store data in each environment.

🔶Enable the Environment Layer for Existing Hiera Data

The environment layer can be gradually enabled. The legacy Hiera functions transition to Hiera 5 mode in migrated environments, allowing them to access environment and module data without requiring code modifications.

In each environment:

✔️Verify your code for calls to Hiera functions that contain "hierarchy override parameters", which lead to mistakes.

✔️Add a local Hiera.yaml file.

✔️If you have any custom backends, update them.

✔️To keep this environment from being included in the global layer, rename the data directory. The global layer, verified before the environment layer, is still used by unmigrated environments. Choose a separate data directory name for migrated environments if you wish to keep both migrated and unmigrated environments during the migration process.

Since it is also the new default, the new name "data" is a wise decision. There is no set time limit or downtime associated with this process. The global hierarchy can gradually be eliminated or drastically reduced once all your environments have been transferred.

✔️If the optional hierarchy overrides an argument passed to any of the classic Hiera functions (hiera, hiera array, hiera hash, and hiera include) in your Puppet code, remove it.

The hierarchy override parameter in Hiera 5 is incorrect. Search for calls with two or more commas to quickly locate instances of this argument being used. Search your codebase using the following regular expression: 

hiera(_array|_hash|_include)?\(([^,\)]*,){2,}[^\)]*\)

This causes some false positives but aids in identifying flaws before the code is executed.

Alternately, move on to the next phase and correct issues as they arise. If you migrate a temporary branch of your control repo first, then point some canary nodes at it to ensure everything works as expected, you're probably using environments for code testing and promotion.

When you execute your canary nodes, you'll be proving your belief that you've never used hierarchy override arguments. If you discover any issues, you can correct them before merging your branch to production, just like you would with any code still under development.

✔️For the following two stages, pick a different name for the data directory. In Hiera 3, the default data directory name was <ENVIRONMENT>/hieradata, while in Hiera 5, the default is <ENVIRONMENT>/data. Use the new default if you previously used the old one. If you were already using data, make a different decision.

✔️Add a Hiera 5 hiera.yaml file to the environment. A Hiera configuration file that interacts with the environment's current data is required. See moving a version 3 hiera.yaml to version 5 if this is your first environment. Don't forget to mention the new datadir name. Copy the hiera.yaml file from a migrated environment and make any necessary adjustments if you've already migrated to at least one environment.

The generated file should be saved as <ENVIRONMENT>/hiera.yaml/etc/puppetlabs/code/environments/production/hiera.yaml, as an example.

✔️Install any custom backends that have been ported to Hiera 5 that your data depends on in the environment. As Puppet modules, Hiera 5 backends are distributed, allowing any environment to use a unique copy of them.

✔️Move the environment's data directory by renaming it from its previous name (hieradata) to its new name if you only use file-based Hiera 5 backends (data). The global layer still requires access to its data if you use a custom file-based Hiera 3 backend; thus, you must sort the files: Hiera 3 data remains in the old data directory while Hiera 5 data is moved to it. Move the remaining files to the new datadir after your custom backends have Hiera 5 versions. If you employ non-file backends without a data directory:

  • Decide that configuring this data in the global hierarchy is the best option and leave it indefinitely.
  • Make a new database table for moved data and move values into it as you switch environments. This is equal to moving the datadir.
  • Till the migration is finished, permit the global and environment layers to use the same configurations for this data.

✔️For each setting, repeat these steps. Most of your environments can be migrated using the merging features in your version control system if you manage your code by mapping environments to branches in a control repository.

✔️Delete the sections of your global hierarchy that you converted into environment hierarchies after migrating the environments with active node populations.

🔶Convert a Version 3 hiera.yaml to Version 5

The hiera.yaml file is supported in three different versions by Hiera 5: versions 3, 4, and 5. If you have been using Hiera 3, the hiera.yaml file at the global layer currently represents your setup.

Translation of a version 3 configuration to a version 5 involves two migration tasks:

✔️New v5 hiera.yaml files being made for environments.

✔️Your global configuration has to be updated to accommodate Hiera 5 backends.

Even though the global hierarchy has some unique capabilities, these two processes are essentially identical.

Consider this example hiera.yaml version 3 file: 

:backends:
  - mongodb
  - eyaml
  - yaml
:yaml:
  :datadir: "/etc/puppetlabs/code/environments/%{environment}/hieradata"
:mongodb:
  :connections:
    :dbname: hdata
    :collection: config
    :host: localhost
:eyaml:
  :datadir: "/etc/puppetlabs/code/environments/%{environment}/hieradata"
  :pkcs7_private_key: /etc/puppetlabs/puppet/eyaml/private_key.pkcs7.pem
  :pkcs7_public_key:  /etc/puppetlabs/puppet/eyaml/public_key.pkcs7.pem
:hierarchy:
  - "nodes/%{trusted.certname}"
  - "location/%{facts.whereami}/%{facts.group}"
  - "groups/%{facts.group}"
  - "os/%{facts.os.family}"
  - "common"
:logger: console
:merge_behavior: native
:deep_merge_options: {}

To upgrade this file from version 3 to version 5:

  1. Use strings as keys rather than symbols.

You have to use Ruby symbols as keys in Hiera 3. Short sequences that begin with a colon are symbols, such as hierarchy. Although symbols won't (yet) result in problems, you can use ordinary strings as keys in the version 5 configuration format. The leading colons on keys can be removed.

 

  1. Discard any settings that are no longer needed. Remove everything from this example except for the setting of the hierarchy.
  • The following settings should be deleted as they are no longer required: :logger, :merge behavior, :deep merge options
  • The following settings should be deleted but should be copied and pasted into a temporary file for future use: :backends:yaml or :mongodb
  1. Add a version key, with a value of 5:
version: 5
hierarchy:
# …
  1. Decide on a default data directory and backend.

Set a defaults key with values for datadir and one of the backend keys if most of your data is stored in one backend, such as YAML or JSON.

For Hiera 5, the backend names have been modified, and the backend configuration has been divided into three settings:

Hiera 3 Backend

Hiera 5 Backend Setting

yaml data_hash: yaml_data
json data_hash: json_data
eyaml lookup_key: eyaml_lookup_key
  1. Interpret the hierarchy. Hierarchies in versions 3 and 5 operate differently:
  • Hiera runs through the entire hierarchy for each backend in version 3 since hierarchy levels do not have designated backends.
  • Each hierarchy level in version 5 has a defined backend and its unique configuration for that backend.
  1. Remove hierarchy levels that use the pseudo-variables calling module, calling class, and calling class path permitted in Hiera 3. Use the module data layer or the glob pattern instead of these variables for anything you did. Version 5 of Hiera.yaml does not support these. Hierarchy levels that interpolate them should be removed.
  2. Convert built-in backends to version 5's configuration, which specifies the hierarchy as an array of hashes. Use the data hashkey to set the backend for hierarchy levels using built-in backends, such as YAML and JSONThe following keys are set:
  • name- a name that people can read.
  • path or paths: This is the path you added a file extension to in your version 3 hiera.yaml hierarchy.
  • data_hash- The backend to use yaml_data for YAML, json_data for JSON.
  • datadir: The data directory is named datadir. It is relative to the directory containing the hiera.yaml file in version 5.
     

You can omit data_hash and datadir if default settings have already been provided for them.

version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "Per-node data (yaml version)"
    path: "nodes/%{trusted.certname}.yaml" # Add file extension.
    # Omitting datadir and data_hash to use defaults.


  - name: "Other YAML hierarchy levels"
    paths: # Can specify an array of paths instead of one.
      - "location/%{facts.whereami}/%{facts.group}.yaml"
      - "groups/%{facts.group}.yaml"
      - "os/%{facts.os.family}.yaml"
      - "common.yaml"
  1. Backends for hiera-eyaml, which function similarly to the other built-in backends, can be translated. The distinctions are:

You must install the hiera-eyamlgem and use a different backend configuration. Instead of data_hashyaml, use lookup_keyeyaml_lookup_key. An options key with links to the public and private keys is required for each hierarchy level. This cannot have a global default.

- name: "Per-group secrets"
   path: "groups/%{facts.group}.eyaml"
   lookup_key: eyaml_lookup_key
   options:
     pkcs7_private_key: /etc/puppetlabs/puppet/eyaml/private_key.pkcs7.pem
     pkcs7_public_key:  /etc/puppetlabs/puppet/eyaml/public_key.pkcs7.pem

 

  1. Custom Hiera 3 backends can be translated. Use the version 3 backend in a version 5 hierarchy at the global layer if there is no update; it is incompatible with the environment layer. Use the previous value when configuring a legacy backend's backend-specific parameters. The version 3 configuration for MongoDB in the example has the following settings:
:mongodb:
  :connections:
    :dbname: hdata
    :collection: config
    :host: localhost

So, for a per-node MongoDB hierarchy level, write the following:

- name: "Per-node data (MongoDB version)"
   path: "nodes/%{trusted.certname}"      # No file extension
   hiera3_backend: mongodb
   options:    # Change keys to plain strings using old backend-specific options.
     connections:
       dbname: hdata
       collection: config
       host: localhost

You've converted the example setup into the following v5 config by performing the steps above:

version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "Per-node data (yaml version)"
    path: "nodes/%{trusted.certname}.yaml" # Add file extension
    # Omitting datadir and data_hash to use defaults.


  - name: "Per-node data (MongoDB version)"
    path: "nodes/%{trusted.certname}"      # No file extension
    hiera3_backend: mongodb
    options:    # Change keys to plain strings using old backend-specific options.
      connections:
        dbname: hdata
        collection: config
        host: localhost


  - name: "Per-group secrets"
    path: "groups/%{facts.group}.eyaml"
    lookup_key: eyaml_lookup_key
    options:
      pkcs7_private_key: /etc/puppetlabs/puppet/eyaml/private_key.pkcs7.pem
      pkcs7_public_key:  /etc/puppetlabs/puppet/eyaml/public_key.pkcs7.pem


  - name: "Other YAML hierarchy levels"
    paths: # Can specify an array of paths instead of a single one.
      - "location/%{facts.whereami}/%{facts.group}.yaml"
      - "groups/%{facts.group}.yaml"
      - "os/%{facts.os.family}.yaml"
      - "common.yaml"

🔶Convert an Experimental(Version 4) hiera.yaml to Version 5

There might be version 4 hiera.yaml files in your environments and modules if you used the experimental version of Puppet lookup, which is Hiera 5. These can be used by Hiera 5, although conversion is required, especially if you intend to use a backend other than YAML or JSON. Versions 4 and 5 of a format are comparable.

Take a look at this version 4 hiera.yaml file as an example:

# /etc/puppetlabs/code/environments/production/hiera.yaml
---
version: 4
datadir: data
hierarchy:
  - name: "Nodes"
    backend: yaml
    path: "nodes/%{trusted.certname}"


  - name: "Exported JSON nodes"
    backend: json
    paths:
      - "nodes/%{trusted.certname}"
      - "insecure_nodes/%{facts.networking.fqdn}"


  - name: "virtual/%{facts.virtual}"
    backend: yaml


  - name: "common"
    backend: yaml

Make the following adjustments to upgrade to version 5:

✔️Set the version key's value to 5.

✔️Every file path should have a file extension added; use "common.yaml" rather than "common."

✔️Add a path to any hierarchy levels that are missing one. Path no longer defaults in version 5 to the value of the name.

✔️Change the top-level datadir key to a defaults key if one exists. Pick a default backend. For example:

defaults:
  datadir: data
  data_hash: yaml_data

✔️Remove the backend key from each hierarchy level and replace it with a data_hash key. (If a default backend was set in the defaults key, it could be omitted here.)

v4 backend 

v5 equivalent 

backend: yaml data_hash: yaml_data
backend: json data_hash: json_data

✔️Disable Puppet lookup for an environment or module by deleting the environment_data_provider and data_provider settings. These settings are in the following locations:

  • environment_data_provider in puppet.conf.
  • environment_data_provider in environment.conf.
  • data_provider in a module’s metadata.json.

After being converted to version 5, the example looks like this:

# /etc/puppetlabs/code/environments/production/hiera.yaml
---
version: 5
defaults:
  datadir: data          # Datadir has moved into `defaults`.
  data_hash: yaml_data   # Default backend: New feature in v5.
hierarchy:
  - name: "Nodes"        # Can omit `backend` if using the default.
    path: "nodes/%{trusted.certname}.yaml"   # Add file extension!


  - name: "Exported JSON nodes"
    data_hash: json_data        # Specifying a non-default backend.
    paths:
      - "nodes/%{trusted.certname}.json"
      - "insecure_nodes/%{facts.networking.fqdn}.json"


  - name: "Virtualization platform"
    path: "virtual/%{facts.virtual}.yaml"   # Name and path are now separated.


  - name: "common"
    path: "common.yaml"

🔶Convert Experimental Data Provider Functions to a Hiera 5 data_hash Backend

A function that returned a hash could be created by setting data_provider = function in the experimental custom backend support of puppet lookup. You could change your function to a Hiera 5 data hash backend if you used it.

✔️Your initial function didn't accept any arguments. Change the signature so that it will now accept a Hash and an object Puppet:LookupContext

✔️Remove the data_provider setting, which allows a module to use Puppet lookup. This setting can be found in a module's metadata.json file.

✔️For the impacted environment or module, create a version 5 hiera.yaml file and add the following hierarchy level:

- name: <ARBITRARY NAME>

  data_hash: <NAME OF YOUR FUNCTION>

🔶Updated Classic Hiera Function Calls

Hiera function

Equivalent lookup call

hiera('secure_server') lookup('secure_server')
hiera_array('ntp::servers') lookup('ntp::servers', {merge => unique})
hiera_hash('users') lookup('users', {merge => hash}) or lookup('users', {merge => deep})
hiera_include('classes') lookup('classes', {merge => unique}).include

🔶Adding Hiera Data to a Module

Modules' class parameters require default values. Previously, using the "params.pp" pattern was the favored method. Instead, you can use Hiera 5's "data in modules" strategy.

💠Module Data With the params.pp Pattern

The params.pp pattern makes use of the class inheritance functionality of Puppet. Your module has one class that sets variables for the other classes. The name of this class is <MODULE>::params. This class employs conditional logic based on the target operating system and constructs values using Puppet code. The module's other classes derive from the params class. You can set the variables in the params class to default values in their parameter lists. When employing the params.pp pattern, the values defined in the params.pp defined class are only used as defaults when no values are found in Hiera. They cannot be used in lookup merges or Automatic Parameter Lookup (APL).

An example params class: 

# ntp/manifests/params.pp
class ntp::params {
  $autoupdate = false,
  $default_service_name = 'ntpd',

  case $facts['os']['family'] {
    'Debian': {
      $service_name = 'ntp'
    }
    'RedHat': {
      $service_name = $default_service_name
    }
  }
}

A class that makes use of the default parameter values set by the params class and derives from it: 

class ntp (
  $autoupdate   = $ntp::params::autoupdate,
  $service_name = $ntp::params::service_name,
) inherits ntp::params {
 ...
}

💠Module Data With One-off Custom Hiera Backend

You can change an existing params class to a hash-based Hiera backend using Hiera 5's proprietary backend architecture. Create a Puppet function that outputs a hash in order to build a Hiera backend.
 

Using the params class as a starting point:

# ntp/functions/params.pp
function ntp::params(
  Hash                  $options, # We ignore both of these arguments, but
  Puppet::LookupContext $context, # the function still needs to accept them.
) {
  $base_params = {
    'ntp::autoupdate'   => false,
# Keys must begin with the namespace of the module, in this case `ntp::`.
    'ntp::service_name' => 'ntpd',
# Use key names that can be looked up automatically using class parameters. 
#The `$service name` parameter of the `ntp` class corresponds to this key.
  }


  $os_params = case $facts['os']['family'] {
    'Debian': {
      { 'ntp::service_name' => 'ntp' }
    }
    default: {
      {}
    }
  }


#If this platform uses a non-standard service name, override it when merging the hashes.
  $base_params + $os_params
}

 

When a function is ready, instruct Hiera to use it by including it in the module layer of hiera.yamlpath, datadir, and options keys are unnecessary for a simple backend like this. If you want the same behavior as the earlier parameters, you can add it to the default_hierarch.  If you want the values to be merged with values of greater priority when a merging lookup is given, use the normal hierarchy and the params.pp pattern. Whether it makes sense to merge a value or not, you can divide the key-values so that some are in the hierarchy and others in the default_hierarchy.

Add it to the regular hierarchy:

# ntp/hiera.yaml
---
version: 5
hierarchy:
  - name: "NTP class parameter defaults"
    data_hash: "ntp::params"
#  We only require one hierarchy level since all the data is provided by a single function,.

The major classes in your module can be made simpler with Hiera-based defaults:

  • There is no requirement that they derive from another class.
  • The = operator does not require you to define a default value explicitly.
  • Instead, APL takes effect without a value for each argument. As with other values in Hiera, the function ntp::params is used in the example to retrieve the default parameters, which may then be modified or combined.
     
# ntp/manifests/init.pp
class ntp (
  # default values are in ntp/functions/params.pp
  $autoupdate,
  $service_name,
) {
 ...
}

💠Module Data With YAML Data Files

Basic Hiera YAML files can be used to manage the default data for your module. In your module layer hiera.yaml file, create a hierarchy:

# ntp/hiera.yaml
---
version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "OS family"
    path: "os/%{facts.os.family}.yaml"

  - name: "common"
    path: "common.yaml"

Place the required data files in the data directory after that:

# ntp/data/common.yaml
---
ntp::autoupdate: false
ntp::service_name: ntpd
# ntp/data/os/Debian.yaml
ntp::service_name: ntp

👉Puppet Language

To specify the intended state of your system, the user can use the declarative language provided by Puppet.

In documents referred to as manifests, the user will outline the ideal condition of the system. Manifests specify how the operating system and network resources should be set up, including files, packages, and services. Puppet then organizes these manifests into catalogs and applies each catalog to the associated node in the user's infrastructure to ensure the node is configured correctly.

The evaluation order is crucial to several aspects of the Puppet language. Variables, for instance, need to be set before they may be referenced. Puppet highlights places in the language reference where the sequencing of sentences is essential.

👉Puppet Man Pages

The command line tools for puppet are made up of a single puppet binary with numerous subcommands. These following subcommands form the core of Puppet’s tool set:

  • puppet agent - applies the client configuration retrieved from the puppet master to the local host.
  • puppet apply - applies a standalone Puppet manifest to the local system.
  • puppet cert - independent certificate issuing body. Although it can generate certificates, it is mainly used to sign certificate requests from puppet clients.
  • puppet master - the central puppet server which by default performs the role of a certificate authority.
  • puppet module - builds, sets up, and searches for modules on the Puppet Forge.
  • puppet resource - the resource abstraction layer shell which Uses the Puppet RAL to directly interact with the system.
  • puppet lookup - uses the command line to do Hiera lookups.
     

We hope you have learned everything about hiera in puppet. 🙌
Check out this problem - Redundant Braces

Frequently Asked Questions

What is Puppet?

With the aid of Puppet, you can manage and automate the configuration of servers. When using Puppet, specify the ideal state for the infrastructure systems you want to manage.

What is DevOps?

DevOps is a collection of cultural ideas, operational procedures, and technical resources that rapidly enhance an organization's ability to deliver products and services.

What language is Puppet built on?

Puppet is built using Ruby’s domain-specific language.

Is Puppet an open-source tool?

Puppet is an open-source tool. Puppet is also available in the enterprise version.

What are the requirements for designing system configurations in puppet

For designing system configurations in puppet, the roles and profile method, designing advanced profiles and designing convenient roles are needed.

Conclusion

In this blog, we explored about hiera in puppet and learned about the usage of puppet code. We further discussed puppet man pages and the Puppet language.

We hope this blog has helped you enhance your knowledge about hiera in puppet and if you want to learn more, check out our articles here.

You can refer to other similar articles as well

Refer to our guided paths on Coding Ninjas Studio to learn more about DSA, Competitive Programming, JavaScript, System Design, etc. Enroll in our courses and refer to the mock test and problems available. Also, look at the interview experiences for placement preparations. 

Happy Learning Ninja! 🥷
 

Live masterclass