Combine Lists of Objects in Ansible I'm really trying to merge lists of objects along with defaults so I can loop over them and create resources in kubernetes. I've gotten it down to a simple(ish) playbook and will post it here.

- hosts: localhost
  vars:
    default_thing_1: 123
    default_thing_2: 456
    default_transport: train
    list_of_things:
      - name: foo
        common_thing_1: "sam"
      - name: bar
        common_thing_1: "sam"
        common_thing_2: "ham"
      - name: biz
        common_thing_1: "eggs"
  tasks:
    - name: Set the Things Facts
      set_fact:
        thing:
          i_am: "{{ item.common_thing_1 | default(default_thing_1) }}"
          eggs_ham: "{{ item.common_thing_2 | default(default_thing_2) }}"
      loop: "{{ list_of_things }}"
      register: things_fact_results
    - name: Set Optional Things Facts
      set_fact:
        thing:
          transport: "{{ item.transport | default(default_transport) }}"
      when: "item.common_thing_2 is defined and item.common_thing_2 == 'ham'"
      loop: "{{ list_of_things }}"
      register: transport_fact_results
    - name: Debug the Facts
      debug:
        msg: "{{ item.0 | combine(item.1|default({})) }}"
      loop: "{{
        things_fact_results.results |
        map(attribute='ansible_facts.thing') | list |
        zip(
          transport_fact_results.results |
          map(attribute='ansible_facts.thing') | list
        ) | list
      }}"


The output is as follows...

PLAY [localhost] ***********************************************************************************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************************************************************************
ok: [localhost]

TASK [Set the Things Facts] ************************************************************************************************************************************************************************
ok: [localhost] =&gt; (item={'name': 'foo', 'common_thing_1': 'sam'})
ok: [localhost] =&gt; (item={'name': 'bar', 'common_thing_1': 'sam', 'common_thing_2': 'ham'})
ok: [localhost] =&gt; (item={'name': 'biz', 'common_thing_1': 'eggs'})

TASK [Set Optional Things Facts] *******************************************************************************************************************************************************************
skipping: [localhost] =&gt; (item={'name': 'foo', 'common_thing_1': 'sam'}) 
ok: [localhost] =&gt; (item={'name': 'bar', 'common_thing_1': 'sam', 'common_thing_2': 'ham'})
skipping: [localhost] =&gt; (item={'name': 'biz', 'common_thing_1': 'eggs'}) 

TASK [Debug the Facts] *****************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! =&gt; {"msg": "Invalid data passed to 'loop', it requires a list, got this instead: [({'i_am': 'sam', 'eggs_ham': '456'}, AnsibleUndefined), ({'i_am': 'sam', 'eggs_ham': 'ham'}, {'transport': 'train'}), ({'i_am': 'eggs', 'eggs_ham': '456'}, AnsibleUndefined)]. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup."}

PLAY RECAP *****************************************************************************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   



I think if I'm reading the loop item that's what I'm looking for. Though I'm not sure why ansible is refusing to perform the loop.

Any help about how to merge lists of objects together with optional attributes that could or could not be set because k8s is pretty picky about what's being set and not when passing in objects.

Thanks.
loop requires a valid list. But we got here is,


[({'i_am': 'sam', 'eggs_ham': '456'}, AnsibleUndefined),
 ({'i_am': 'sam', 'eggs_ham': 'ham'}, {'transport': 'train'}),
 ({'i_am': 'eggs', 'eggs_ham': '456'}, AnsibleUndefined)]


Since no value is assigned to transport_fact_results when common_thing_2 is not defined.

if you remove the when condition it will work.

CODE:

- hosts: localhost
  vars:
    default_thing_1: 123
    default_thing_2: 456
    default_transport: train
    list_of_things:
      - name: foo
        common_thing_1: "sam"
      - name: bar
        common_thing_1: "sam"
        common_thing_2: "ham"
      - name: biz
        common_thing_1: "eggs"
  tasks:
    - name: Set the Things Facts
      set_fact:
        thing:
          i_am: "{{ item.common_thing_1 | default(default_thing_1) }}"
          eggs_ham: "{{ item.common_thing_2 | default(default_thing_2) }}"
      loop: "{{ list_of_things }}"
      register: things_fact_results
    - name: Set Optional Things Facts
      set_fact:
        thing:
          transport: "{{ item.transport | default(default_transport) }}"
      when: "item.common_thing_2 is defined and item.common_thing_2 == 'ham'"
      loop: "{{ list_of_things }}"
      register: transport_fact_results
    - name: Debug the Facts
      debug:
        msg: "{{ item.0 | combine(item.1|default({})) }}"
      loop: "{{
        things_fact_results.results |
        map(attribute='ansible_facts.thing') | list |
        zip(
          transport_fact_results.results |
          map(attribute='ansible_facts.thing') | list
        ) | list
      }}"


OUTPUT:

PLAY [localhost] ************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Set the Things Facts] *************************************************************************************************************************************************************************************
ok: [localhost] =&gt; (item={u'common_thing_1': u'sam', u'name': u'foo'})
ok: [localhost] =&gt; (item={u'common_thing_1': u'sam', u'common_thing_2': u'ham', u'name': u'bar'})
ok: [localhost] =&gt; (item={u'common_thing_1': u'eggs', u'name': u'biz'})

TASK [Set Optional Things Facts] ********************************************************************************************************************************************************************************
ok: [localhost] =&gt; (item={u'common_thing_1': u'sam', u'name': u'foo'})
ok: [localhost] =&gt; (item={u'common_thing_1': u'sam', u'common_thing_2': u'ham', u'name': u'bar'})
ok: [localhost] =&gt; (item={u'common_thing_1': u'eggs', u'name': u'biz'})

TASK [Debug the Facts] ******************************************************************************************************************************************************************************************
ok: [localhost] =&gt; (item=[{u'eggs_ham': u'456', u'i_am': u'sam'}, {u'transport': u'train'}]) =&gt; {
    "msg": {
        "eggs_ham": "456", 
        "i_am": "sam", 
        "transport": "train"
    }
}
ok: [localhost] =&gt; (item=[{u'eggs_ham': u'ham', u'i_am': u'sam'}, {u'transport': u'train'}]) =&gt; {
    "msg": {
        "eggs_ham": "ham", 
        "i_am": "sam", 
        "transport": "train"
    }
}
ok: [localhost] =&gt; (item=[{u'eggs_ham': u'456', u'i_am': u'eggs'}, {u'transport': u'train'}]) =&gt; {
    "msg": {
        "eggs_ham": "456", 
        "i_am": "eggs", 
        "transport": "train"
    }
}

PLAY RECAP ******************************************************************************************************************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0