I am iterating over many entries in a hiera hash, and wish to remove identical duplicate lines from hiera by setting defaults in the manifest (such as ensure
, groups
, managehome
etc), and have the defaults overridden IF the duplicate key/value pair exists in hiera.
To date, everything I have tried fails to get the default values. I get the idea that I need to declare a resource, but am uncertain.
I have tried setting "default_values_hash" in the lookup and other methods, but nothing appears to pass defaults into the iteration and --debug output
This is a (pseudo) example of my manifest and hiera data. Any guidance is sincerely appreciated. Thank you.
class test (
Hash $testhash = lookup('test::hash', "merge" => 'hash'}),
){
$testhash.each |$key, $value| {
user { $key :
ensure => $value['ensure'],
name => $value['name'],
password => $value['password'],
groups => $value['groups'],
managehome => $value['managehome'],
}
}
}
include class test
in Hiera:
test::hash:
'fred':
name: fred
password: somepassword
groups: wheel
managehome: true
'mary':
name: mary
password: otherpassword
'john':
name: john
password: anotherpassword
'harry':
Setting resource defaults in the manifest (with capitalized User
) does not pass into the iteration, though it does if I keep all data in the manifest (too much data to do that).
The lookup
function gives you the ability to establish a default value for the hash itself, but not really for the keys and values inside the hash. Additionally, using the lookup
function as a class parameter value in Puppet will be superseded by automatic parameter bindings. In other words, your lookup
function in this context does nothing because Puppet is preferring automatic parameter bindings over it, and you are using those (this is definitely true for lookup
in conjunction with Hiera 5, which it appears you are using). I personally find this behavior annoying, but it is what it is. Edit: Never mind on that specific reasoning; the parameter is called $testhash
and not $hash
. If that parameter is coming from module data though, then the lookup
will still be ignored since Puppet only allows automatic parameter binding for module data.
I am surprised that the resource defaults are not working here for you. I have to believe that this is either unintended, or something was implemented wrong regarding them when you went that route.
Regardless, here is a guaranteed method for you. First, we implement per-expression default attributes: https://puppet.com/docs/puppet/5.3/lang_resources_advanced.html#per-expression-default-attributes
class test (
Hash $testhash = lookup('test::hash', "merge" => 'hash'}),
){
$testhash.each |String $key, Hash $value| {
user {
default:
ensure => present,
name => 'username',
password => 'userpassword',
groups => ['usergroups'],
managehome => false,
;
$key:
ensure => $value['ensure'],
name => $value['name'],
password => $value['password'],
groups => $value['groups'],
managehome => $value['managehome'],
;
}
}
}
One problem still remains here though, which is that you are establishing values for the attributes in the second block for all iterations. If those key-value pairs are undefined, Puppet will error instead of defaulting to another value. We need to instruct Puppet to only establish values for attributes if you have defined a value for them in the first place. Thankfully, we can do this with the *
attribute: https://puppet.com/docs/puppet/5.3/lang_resources_advanced.html#setting-attributes-from-a-hash
class test (
Hash $testhash = lookup('test::hash', "merge" => 'hash'}),
){
$testhash.each |String $key, Hash $value| {
user {
default:
ensure => present,
name => 'username',
password => 'userpassword',
groups => ['usergroups'],
managehome => false,
;
$key:
* => $value,
;
}
}
}
One recommendation here would be to make your lambda iterator variables $key, $value
a bit more transparently named. Another note is the caveat that for the *
attribute to work, your hash keys must match Puppet attribute names.
Updated question: In the situation where the hash has a key with a nil
value, you can set an empty hash as the default value for the key's value in the lambda iterator parameters. The empty hash will replace the undef
(Puppet nil
) for the $value
during that iteration. This will ensure that no attributes and values are included in the *
operator and that all the defaults will prevail.
class test (
Hash $testhash = lookup('test::hash', "merge" => 'hash'}),
){
$testhash.each |String $key, Hash $value = {}| {
user {
default:
ensure => present,
name => 'username',
password => 'userpassword',
groups => ['usergroups'],
managehome => false,
;
$key:
* => $value,
;
}
}
}