Search code examples
arrayshashiterationpuppethiera

Puppet - iterate over hash


We're using puppet 3.8 (unfortunately can't move to puppet 4 yet)

I've got a hash in hiera that looks something like this:

hash_data:
  item1:
    field1:   'some data'
    array_data:
      - data1
      - data2
  item2:
    field1:   'other data'
    array_data:
      - data3
      - data4

I've put together a module with code something like:

class processor {
    $data = hiera_hash('hash_data', {})

    create_resources(processor::hash_entry, $data)
}

define processor::hash_entry ($field1, $array_data) {
#    .. do_something ..

# process array items
    processor::process_array { $array_data : 
        datavar = 'somevalue'
    }
}

define processor::process_array($element, $datavar) {
    # do something
}

this works fine as long at the array_data fields in the hash all contain unique fields. However, if I need to put non-unique data something like:

hash_data:
  item1:
    field1:   'some data'
    array_data:
      - data1
      - data2
  item2:
    field1:   'other data'
    array_data:
      - data3
      - data2                  ( **non-unique value **)

then we hit a duplicate resource. Can anyone suggest how I could process that hash?

Thanks


Solution

  • The issue begins here, where processor::process_array is given non-unique data as its name:

    define processor::hash_entry ($field1, $array_data) {
        processor::process_array { ${array_data}:
            # ...
    

    When processor::hash_entry is called twice with overlapping/identical array_data, this generates:

    Processor::Process_array[data1]
    Processor::Process_array[data2]
    Processor::Process_array[data3]
    Processor::Process_array[data2]
    

    which I would guess is the duplicate resource you report.

    If you prefix this with unique data, i.e. the "item1"/"item2" name of the processor::hash_entry resources (or field1 if appropriate) then they would be unique.

    Using the stdlib prefix() function, prefix all data* entries with the hash_entry name:

    define processor::hash_entry ($field1, $array_data) {
        $prefixed_array_data = prefix($array_data, "${title}-")
        processor::process_array { ${prefixed_array_data}:
            # ...
    

    This will generate:

    Processor::Process_array[item1-data1]
    Processor::Process_array[item1-data2]
    Processor::Process_array[item2-data3]
    Processor::Process_array[item2-data2]
    

    If you need to access the data2 value inside process_array without the prefix then you can always split the $title to get the data back out.

    define processor::process_array($element, $datavar) {
        $split_title = split($title, '-')
        $data = $split_title[1]
        # do something
    }