Puppet Hiera access global object in more specific file

391 views Asked by At

I'm struggling to understand the hiera way of working with data, it seems to me like plain yaml using frontmatter to include global data files would be simpler and more powerful.

In any case, I want to accomplish something like this:

# global.yaml
collection1: &collection1
    foo: 1
collection2: &collection2
    bar: 2
collection3: &collection3
    baz: 3

# development_environment.yaml
collection:
    <<: *collection1
    <<: *collection2

# production_environment.yaml
collection:
    <<: *collection2
    <<: *collection3

Essentially, so that I can maintain a couple of lists of things in a single place and then combine them in different ways depending on the environment. Hiera has an option for merging top level keys vs deep merging, but I can't find anything about including data from higher up in the hierarchy (for my particular problem I could also get it working reasonably well if there were a way to overwrite the data in the global file rather than merge it in to the more specific file but that doesn't seem possible either).

How can I do this? Am I stuck manually duplicating the base data in all my different environments?

I realize that I could put an environment case statement in puppet code to choose which base collections to include, but that breaks the separation of concerns of keeping data in hiera and code in puppet. If I have to do that, I may as well skip hiera altogether and put my data in puppet modules.

1

There are 1 answers

0
bartavelle On

You can do it by manually loading the list of collections and iterating over it :

# global.yaml
collection1:
    foo: 1
collection2:
    bar: 2
collection3:
    baz: 3

# development_environment.yaml
collection:
    - collection1
    - collection2

# production_environment.yaml
collection:
    - collection2
    - collection3

Now you can write something like that :

# this variable will contain something like ['collection1','collection2']
$collections = hiera('collection')
# Now get all the corresponding values
$hashparts = $collections.map |$r| { $x = hiera($r); $x } # [{"baz"=>3}, {"bar"=>2}]
# Now we merge all the parts
$hash = $hashparts.reduce |$a,$b| { $x = merge($a,$b); $x } # {"baz"=>3, "bar"=>2}

This is ugly, but should do what you expect. The deal about $x = function(); $x is here because of the unfortunate decision that all the lambda functions can be used in any context (statement, or value), so we don't know at parsing time whether we expect the last "token" of the "block" to be a statement or an expression.