Monday, September 30, 2013

Puppet and nested hashes in hiera

In Puppet, representing your data like a normal mortal would do leads you nowhere.
You must model your data in a way that Puppet can access.
This is driving me absolutely crazy, in Puppet there are only straight lines and if you want to bend, you must compose 100 straight lines at a small angle.
So, this highly normalized representation of an array of keystores is not usable by Puppet:

---

keystores:
  - keystorename : dev.jks:
    type : identity
    password : 111111
    certificates: 
      - name : pippo.cer
        alias : pippo   
      - name : pluto.cer
        alias : pluto      
       
  - keystorename : trust.jks
    type : trust
    password : 111111
    certificates: 
      - name : pippo.cer
        alias : pippo   
      - name : pluto.cer
        alias : pluto   


because Puppet cannot extract an array of "keystorename" from it. You can do:
$keystores = hiera('keystores')

#this generates a String
$keystorename = $keystores[1]['keystorename'] 


but you cannot say
#this generates an Array
$keystorename = $keystores[]['keystorename']
#FAILS!!!

Nor you can access the element of the array which has a given keystorename. I really miss here the query capability of XPath. There doesn't seem to be a XPath for YAML.
Look on Puppet hash documentation and you will find almost no help.

The workaround is to denormalize my data, using named instances and listing these names in a separate array keystorefiles:

---
keystorefiles:
  - dev.jks
  - trust.jks

keystores:
  dev.jks:
    type : identity
    password : 111111
    certificates: 
      - name : pippo.cer
        alias : pippo   
      - name : pluto.cer
        alias : pluto     
       
  trust.jks:
    type : trust
    password : 111111
    certificates: 
      - name : pippo.cer
        alias : pippo   
      - name : pluto.cer
        alias : pluto      



and then you can access the data:
$keystorefiles = hiera('keystorefiles')
create_jks_store {$keystorefiles:}

define create_jks_store {
  $keystores = hiera('keystores')
  $keystore = $keystores[$name]
  notify { $keystore['type']:}  
}

notice the trick $keystore = $keystores[$name] to retrieve the individual named instance (dev.jks or trust.jks).

It takes a lot of effort to twist your brain to think this way.



3 comments:

Yamakasi said...

Hi,

Good example, thanks!

Is this not possible without the keystorefiles section in some way or above each hiera part ?

vernetto said...

in fact eventually we have removed that extra variable, and declared this way:

keystores:
dev.jks:
jksfilename : dev.jks
type : identity
password : mypassword

trust.jks:
jksfilename : trust.jks
type : trust
password : mypassword


and to build the array of files [dev.jks, trust.jks] you do:

$keystorefiles = keys($keystores)

How I miss the power of a true OO language.... never parsing configuration has been so hard...

Yamakasi said...

Hi,

Thank you for your very quick response!

As I'm moving from a simple create_resources() and new to this, indeed it's brain-kicking... do you have a small example of a "real" manifest ?

Thanks!

Matt