dictionaryansiblekeyansible-filter

How can I keep keys in Ansible non recursively?


I want to remove some keys (nesting level 0) from a list of dictionnaries so that I can apply the unique filter and get some sort of classification of my list items. If I use the ansible.utils.keep_keys filter, I get undesired results, because it only works recursively. This may result in kept unmatched keys on nesting level 0 if some subkey matches the filter. Further more, this filter behaves strangely if lists of integers are involved, e. g.:

- debug:
    msg: "{{ my_list | keep_keys(target=['key0', 'key1']) | unique }}"
  vars:
    my_list:
      - key0: A
        key1: B
        key2:
          - 1
        key3: foo
      - key0: A
        key1: B
        key2:
          - 2
        key4: bar

results in:

msg:
  - key0: A
    key1: B
    key2:
    - 1
  - key0: A
    key1: B
    key2:
    - 2

instead of:

msg:
  - key0: A
    key1: B

remove_keys is not an option, because it also works recursively and the number of unwanted keys is way bigger than the number of desired keys. As keep_keys does not offer an option to work non recursively, I assume there must be another way to achieve this, but I cannot figure it out.

Is there a way to keep keys in Ansible non recursively, besides developing my own filter?


Solution

  • Use Jinja. For example,

      keep: [key0, key1]
      result: |
        {% filter from_yaml %}
        {% for i in my_list %}
        - {{ dict(keep|zip(keep|map('extract', i))) }}
        {% endfor %}
        {% endfilter %}
    

    gives

      result:
        - {key0: A, key1: B}
        - {key0: A, key1: B}
    

    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        my_list:
          - key0: A
            key1: B
            key2: [1]
            key3: foo
          - key0: A
            key1: B
            key2: [2]
            key4: bar
    
        keep: [key0, key1]
        result: |
          {% filter from_yaml %}
          {% for i in my_list %}
          - {{ dict(keep|zip(keep|map('extract', i))) }}
          {% endfor %}
          {% endfilter %}
            
      tasks:
    
        - debug:
            var: result|to_yaml
        - debug:
            var: result|unique