ansibleansible-filter

Ansible lookup filter works only if more than one item in hashmap


I have this playbook:

- name: "This works"
  hosts: localhost
  tasks:
    - debug:
        msg: "{{ lookup('dict', foo) | map(attribute='key') | list}}"
      vars:
        foo:
          bar:
            type: v1
          baz:
            type: v2

- name: "This does not work"
  hosts: localhost
  tasks:
    - debug:
        msg: "{{ lookup('dict', foo) | map(attribute='key') | list}}"
      vars:
        foo:
          bar:
            type: v1

When running this, I get the following output:

PLAY [This works] *******************************************************************************************************************************************************************************************************************************
    
TASK [Gathering Facts] **************************************************************************************************************************************************************************************************************************
ok: [localhost]
   
TASK [debug] ************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        "bar",
        "baz"
    ]
}
    
PLAY [This does not work] ***********************************************************************************************************************************************************************************************************************
    
TASK [Gathering Facts] **************************************************************************************************************************************************************************************************************************
ok: [localhost]
    
TASK [debug] ************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "[AnsibleUndefined, AnsibleUndefined]"

You see, it prints out bar and baz as list in the first example, but instead of a list containing just bar in the second example, I get some AnsibleUndefined output.

What do I have to change to make these filters also work with a single-item dict?


Solution

  • This is because lookup does not always return a list. And in your second case, if you debug, you'll see it returns one single object which is not inside a list:

    {
        "key": "bar",
        "value": {
            "type": "v1"
        }
    }
    

    2 solutions to get around the problem:

    1. instruct lookup you want a list
    msg: {{ lookup('dict', foo, wantlist=true) | map(attribute='key') | list }}
    
    1. use query in place of lookup which always returns a list and is better suited for this kind of processing (loops, mapping)
    msg: {{ query('dict', foo) | map(attribute='key') | list }}
    

    Reference: