Search code examples
puppethiera

Puppet: set default values for nested hashes


I am creating a class which creates a ssh keys pair for users.

In Hiera it looks like this:

ssh::default_user_keys::entries:
  root:
    privkey: ENC[PKCS7,MIIH/QYJKoZIhvcNAQcDoIIH7jCCB+oCAQAx...]
    pubkey: BiQYJKoZIhvcNAQcDoIIBejCCAXYC...
  user1:
    privkey: ENC[PKCS7,MIIH/Bf0mv0aa7JRbEWWONfVMJBOX2I7x...]
    keydir: /srv/data/user1/.ssh
  user2:
    privkey: ENC[PKCS7,MIIBiQYJKoZIhvcNAQcDoIIBejCCAXYCAQAx...]
    keytype: id_ecdsa

If some values are not specified in Hiera, they must be picked up from default values in the manifest.

So my question is how to write the manifest correctly? This is my pseudo code I try to make working:

class ssh::default_user_keys_refact (
  Hash $entries = lookup('ssh::default_user_keys_refact::entries', "merge" => 'hash'),
) {
  $entries.each |String $user, Hash $item = {} | {

    set_default { $item:
      privkey => undef,
      pubkey  => undef,
      keydir  => "/home/${user}/.ssh",
      keytype => id_rsa,
      comment => undef,
    }
    
    $sshpriv = $item[privkey]
    file { "${keydir}/$[keytype}":
      ensure  => file,
      owner   => $user,
      mode    => '0600',
      content => $sshpriv,
    }
  }
}

Do you have ideas how to make this pseudo code working? Or in other words, how to set up default values for nested hiera hash in puppet manifest?

puppet versions is 6.

Thank you in advance.


Solution

  • Or in other words, how to set up default values for nested hiera hash in puppet manifest?

    The fact that the hashes for which you want to provide defaults are nested inside others in the Hiera data isn't much relevant, because at the point of use they have been plucked out. With that being the case, you can accomplish this fairly easily by leveraging Puppet (not Hiera) hash merging. It might look something like this:

    $entries.each |String $user, Hash $props| {
    
      # Merge with default values
      $full_props = { 
        'keydir'  => "/home/${user}/.ssh",
        'keytype' => 'id_rsa'
      } + $props
    
      file { "${full_props['keydir']}/${full_props['keytype']}":
        ensure  => 'file',
        owner   => $user,
        mode    => '0600',
        content => $full_props['privkey'],
      }
    }
    

    That's by no means the only way, but it's clean and clear, and it scales reasonably well.