0

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.

Simon
  • 193
  • 1
  • 10
  • i'm using something like this and i don't have any problem "hiera_hash('useradmins',{}), i'm using an empty hash as default value and it works, why you say doesn't work? – c4f4t0r Feb 16 '15 at 12:12
  • I didn't say it doesn't work. I'm saying it doesn't do what I want it to do. I want to be able to provide default keys which should always be in the hash even if not defined in the hierarchy. I need this functionality in order to condense the X `hiera()` calls into one `hiera_hash()` call, but see no way to actually provide the functionality. Right now the default hash gets returned only if the key I search for is not found in the hierarchy, I want all keys defined in the default hash to be present in the returned hash. – Simon Feb 16 '15 at 12:17
  • but you are telling to hiera to looking for test and not count the keys, now i understand what you want, if you find the way :) let me know. – c4f4t0r Feb 16 '15 at 13:51
  • @c4f4t0r As per your request: there is an answer ;) – Simon Feb 26 '15 at 08:48

1 Answers1

2

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.

Felix Frank
  • 3,063
  • 1
  • 15
  • 22
  • Thanks for your answer! I do think you switched the array order in the example though. Since the right-most array always wins, I want the data coming from the hiera call to be the rightmost, no? – Simon Feb 19 '15 at 16:46
  • Absolutely - my bad. Will update to use the correct merge call. – Felix Frank Feb 19 '15 at 23:34