listansiblenshashtable

Inserting default values into list of dicts in Ansible


I have a list of web applications and their configs. Simplified data structure would look like this (list of dicts)

web_app_details: 
- web_sourcedir: UWT_Optimus_UI
  web_destdir: 'E:\alexsapp'
  loadUserProfile: false

- web_sourcedir: UWT_Optimus_UI
  web_destdir: 'E:\bodhi'

Now, there are some default values I don't want the user to specify every single time (single dict)

defaults_only:
  identityType: LocalSystem
  enable32BitAppOnWin64: false
  loadUserProfile: true

If the user does not provide a value in any field within the defaults_only dictionary, the defaults should apply. Otherwise, the defaults should be discarded.

So the result would be:

web_app_details: 
- web_sourcedir: UWT_Optimus_UI
  web_destdir: 'E:\alexsapp'
  identityType: LocalSystem
  enable32BitAppOnWin64: false
  loadUserProfile: false  # Because user provided the override value

- web_sourcedir: UWT_Optimus_UI
  web_destdir: 'E:\bodhi'
  identityType: LocalSystem
  enable32BitAppOnWin64: false
  loadUserProfile: true

I tried a few things such as

  1. Call a Powershell script to do this outside Ansible
  2. Duplicate the default dictionary as many times as in web_app_detail and then use combine filter
  3. Insert null values with a JMESPath query:
- name: Pad web_app_details with null values
  set_fact:   
    web_app_details_with_defaults: "{{ web_app_details | json_query(jmesquery) }}"
  vars:
    jmesquery: 
      "[*].{web_sourcedir: web_sourcedir, web_destdir: web_destdir, web_cleancopy: web_cleancopy }"

But nothing works.
Can someone please help?


Solution

  • You could recreate that list adding the default with a combine filter.

    This will take advantage of the fact that a property defined in both dictionaries would be overridden by the dictionary you are combining with.

    So, you'll end up with this set_fact task:

    - set_fact:
        web_app_details_with_defaults: >-
          {{
            web_app_details_with_defaults | default([]) + [
              defaults_only | combine(item)
            ]
          }}
      loop: "{{ web_app_details }}"
    

    Given the couple of tasks:

    - set_fact:
        web_app_details_with_defaults: >-
          {{
            web_app_details_with_defaults | default([]) + [
              defaults_only | combine(item)
            ]
          }}
      loop: "{{ web_app_details }}"
      vars:
        defaults_only:
          identityType: LocalSystem
          enable32BitAppOnWin64: false
          loadUserProfile: true
          
        web_app_details:
          - web_sourcedir: UWT_Optimus_UI
            web_destdir: 'E:\alexsapp'
            loadUserProfile: false
    
          - web_sourcedir: UWT_Optimus_UI
            web_destdir: 'E:\bodhi'
    
    - debug:
        var: web_app_details_with_defaults
    

    This yields the expected:

    web_app_details_with_defaults:
    - enable32BitAppOnWin64: false
      identityType: LocalSystem
      loadUserProfile: false
      web_destdir: E:\alexsapp
      web_sourcedir: UWT_Optimus_UI
    - enable32BitAppOnWin64: false
      identityType: LocalSystem
      loadUserProfile: true
      web_destdir: E:\bodhi
      web_sourcedir: UWT_Optimus_UI