How to return default hash keys in hiera_hash() call

hierahierarchypuppet

In an attempt to clean up my client's Hiera data for Puppet, and drastically reduce the number of Hiera calls in the Puppet manifests, I'm changing constructs like

some_name::key1: a_value_1
some_name::key2: a_value_2
[...]
some_name::keyX: a_value_X

into

some_name:
  key1: a_value_1
  key2: a_value_2
  [...]
  keyX: a_value_X

So that instead of having X hiera() calls, I have only one hiera_hash() call. This works perfectly until you run into a situation like this:

# some_manifest.pp

hiera(some_name::key1, default_value_1)
hiera(some_name::key2, default_value_2)
[...]
hiera(some_name::keyX, default_value_X)

The problem here is that I can't find a way to provide default values for all keys in a clean and concise way. hiera_hash(key_to_be_searched, default_hash) returns the value of default_hash if key_to_be_searched isn't found in it's hierarchy. But you can't make it check if a hash (found in the hierarchy) contains (at least) all keys defined in default_hash.

For example, if I have this bit of hiera data:

test:
  foo: bar
  bar: baz

Together with this bit of DSL:

$test_default = {
  foo => '1',
  bar => '2',
  baz => 'foo',
}
$test = hiera_hash(test, $test_default)

I would expect (or rather, want) $test to contain:

  foo => 'bar',
  bar => 'baz',
  baz => 'foo',

But, as far as I can tell, that's not a possibility. What Puppet returns in this example is this:

  foo => 'bar',
  bar => 'baz',

Is there anyone here who has a solution to this problem? In the current environment I estimate the number of Hiera calls in a Puppet run to be reduced anywhere between five- and ten-fold by restructuring the data in the way I want to. It also makes for way cleaner code.

Best Answer

You need the hash merge function from the stdlib module.

merge: Merges two or more hashes together and returns the resulting hash.

Example:

$hash1 = {'one' => 1, 'two' => 2}
$hash2 = {'two' => 'dos', 'three' => 'tres'}
$merged_hash = merge($hash1, $hash2)
# The resulting hash is equivalent to:
# $merged_hash =  {'one' => 1, 'two' => 'dos', 'three' => 'tres'}

When there is a duplicate key, the key in the rightmost hash "wins."

So in your case

$test = merge( $test_default, hiera_hash(test, {}) )

Note 1

You should use hiera_hash only if you need to deep-merge hashes from multiple hierarchy layers. I suppose with your approach, you do want that.

Note 2

A flat list of keys is usually easier to handle, and it is also the only way to leverage automatic class parameter lookup. It is a safe practice to adhere to the standard data layout.

Yes, there can be performance implications.

Related Topic