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

Working with the command line on a YAML backend

When we use a backend based on files such as JSON or YAML, which are the most commonly used, we have to recreate on the filesystem the hierarchy defined in our hiera.yaml file; the files that contain Hiera data must be placed in these directories.

Let's see Hiera in action. Provide a sample hierarchy configuration as follows:

:hierarchy:
  - "nodes/%{::fqdn}"
  - "env/%{::env}"
  - common

:yaml:
  :datadir: /etc/puppet/hieradata

We have to create a directory structure as follows:

mkdir -p /etc/puppet/hieradata/nodes
mkdir -p /etc/puppet/hieradata/env

Then, work on the YAML files as shown:

vi /etc/puppet/hieradata/nodes/web01.example42.com.yaml
vi /etc/puppet/hieradata/env/production.yaml
vi /etc/puppet/hieradata/env/test.yaml
vi /etc/puppet/hieradata/common.yaml

The previous files are plain YAML files where we can specify the values for any Hiera-managed variable. These values can be strings, arrays, or hashes.

We can place our default settings in /etc/puppet/hieradata/common.yaml as follows:

---
# A simple string assigned to a key
timezone: 'Europe/Rome'

# A string with variable interpolation
nagios_server: "nagios.%{::domain}"

# A string with another variable defined in Hiera (!)
dns_nameservers: "%{hiera('dns_servers')}"

# A string assigned to a key that maps to the
# template parameter of the openssh class (on Puppet3)
openssh::template: 'site/common/openssh/sshd_config.erb'

# An array of values
ldap_servers:
  - 10.42.10.31
  - 10.42.10.32

# An array with a single value
ntp::ntp_servers:
  - 10.42.10.71

# A hash of values
users:
  al:
    home: '/home/al'
    comment: 'Al'
  jenkins:
    password: '!'
    comment: 'Jenkins'

Given the previous example, execute a Hiera invocation as follows:

hiera ldap_servers

It will return the following array:

["10.42.10.31", "10.42.10.32"]

If we define a different value for a key in a data source that is higher in the hierarchy, that value is returned. Let's create a data source for the test environment by editing the file /etc/puppet/hieradata/env/test.yaml as follows:

---
ldap_servers:
- 192.168.0.31
users:
  qa:
    home: '/home/qa'
    comment: 'QA Tester'

Consider a normal Hiera lookup for the ldap_servers key as follows:

hiera ldap_servers

It will still return the common value ["10.42.10.31", "10.42.10.32"].

However, we can explicitly pass the env variable as follows:

hiera ldap_servers env=test

The returned value is the one for the test env as follows:

["192.168.0.31"]

If we have a more specific setting for a given node, that value is returned. Suppose we edit the file ldap.example42.com.yaml in /etc/puppet/hieradata/nodes/ with the following code:

---
ldap_servers:
- 127.0.0.1

When we query Hiera and refer to a specific node's FQDN using the following command:

hiera ldap_servers fqdn=ldap.example42.com

The result is the one from the higher source in the hierarchy:

["127.0.0.1"]

Note

We have seen that by default, Hiera returns the first value found while traversing the data sources' hierarchy, from the first to the last. When more backends are specified, the whole hierarchy of the first backend is fully traversed, and then the same is done for the second and so on.

Hiera also provides some alternate lookup options. When we deal with arrays, for example, we can decide to merge all the values found in the hierarchy instead of returning the first one found. We make our query to specify the -a or --array option as follows:

hiera -a ldap_servers fqdn=ldap.example42.com

The result contains all the entries for the ldap_servers key in all the data sources of our hierarchy as follows:

["127.0.0.1", "10.42.10.31", "10.42.10.32"]

Note that the value defined for the env=test case is not returned unless we specify it using the following command:

hiera -a ldap_servers fqdn=ldap.example42.com env=test

In this case, the output would be as follows:

["127.0.0.1", "192.168.0.31", "10.42.10.31", "10.42.10.32"]

When working with hashes, interesting things can be done.

Let's see what's the value of the users key for the test environment:

hiera users env=test

The output is the hash we configured in test.yaml:

{"qa"=>{"home"=>"/home/qa", "comment"=>"QA Tester"}}

As it normally does, Hiera returns the first value it encounters while traversing the hierarchy, but in this case, we might prefer to have a hash that contains all the values found. Similar to the -a option for arrays, we have at our disposal the -h (--hash) option for hashes:

hiera -h users env=test

The result is a hash that contains all the users defined in different data sources:

{"al"=>{"home"=>"/home/al", "comment"=>"Al"},
 "jenkins"=>{"password"=>"!", "comment"=>"Jenkins"},
 "qa"=>{"home"=>"/home/qa", "comment"=>"QA Tester"}}

Note that hashes are not ordered according to the matching order as arrays are.

Let's perform one more experiment. Let's add a new user specific to our ldap.example42.com node and give different values to a parameter that is already defined in the common data source. We edit the file ldap.example42.com.yaml in vi /etc/puppet/hieradata/nodes/ with the following code:

users:
  openldap:
    groups: 'apps'
  jenkins:
    ensure: absent

Consider a hash lookup as follows:

hiera -h users fqdn=ldap.example42.com env=test

As expected, this would return all the users found in all the hierarchy levels:

{"al"=>{"home"=>"/home/al", "comment"=>"Al"},
 "jenkins"=>{"ensure"=>"absent"},
 "qa"=>{"home"=>"/home/qa", "comment"=>"QA Tester"},
 "openldap"=>{"groups"=>"apps"}}

Let's take a look at the parameters of the jenkins user; being defined both at the node level and in the common data source, the returned value is the one for the higher data source in the hierarchy.

Hiera's management of hashes can be quite powerful, and we can make optimal use of it. For example, we can use them inside Puppet manifests with the create_resources function, with the hash of users data and a single line of code as follows:

create_resources(user, hiera_hash($users))

Based on highly customizable Hiera data, we can manage all the users of our nodes.

Note

We can tune how Hiera manages the merging of hashes with the merge_behavior global setting, which allows deeper merging at a single-key levels. Read the official documentation at http://docs.puppetlabs.com/hiera/1/lookup_types.html#hash-merge for more details.

Quite often, we need to understand where a given key is set in our hierarchy and what values will be computed for it. The -d (debug) option is rather useful for this. The previous line will return an output as follows:

hiera -d -h users fqdn=ldap.example42.com env=test
DEBUG: 2013-12-07 13:11:07 +0100: Hiera YAML backend starting
DEBUG: <datetime>: Looking up users in YAML backend
DEBUG: <datetime>: Looking for data source nodes/ldap.example42.com
DEBUG: <datetime>: Found users in nodes/ldap.example42.com
DEBUG: <datetime>: Looking for data source env/test
DEBUG: <datetime>: Found users in env/test
DEBUG: <datetime>: Looking for data source common
DEBUG: <datetime>: Found users in common
{"al"=>{"home"=>"/home/al", "comment"=>"Al"},
 "jenkins"=>{"ensure"=>"absent"},
 "qa"=>{"home"=>"/home/qa", "comment"=>"QA Tester"},
 "openldap"=>{"groups"=>"apps"}}

This output also tells us where Hiera is actually looking for data sources.

In a real Puppet environment, it is quite useful to use the --yaml option, which, when used with a real facts file of a node, allows us to evaluate exactly how Hiera computes its keys for real servers.

On the Puppet Master, the facts of all the managed clients are collected in $vardir/yaml/facts, so this is the best place to see how Hiera evaluates keys for different clients:

hiera --yaml /var/lib/puppet/yaml/facts/<node>.yaml ldap_servers

Hiera can use other sources to retrieve the facts of a node and return its key values accordingly. We can interrogate the Puppet Master's inventory service with the following command:

hiera -i ldap.example42.com ldap_servers

As an alternative, we can query mcollective (from a machine where the mco client is installed):

hiera -m ldap.example42.com ldap_servers