default filter on with_items with from_json

I’m running into the infamous issue where with_items isn’t skipped if when evaluates to false (https://github.com/ansible/ansible/issues/13791). That said, I’m at loss as to how to workaround my particular issue.

Consider these two tasks (simplified for discussion):

`
#> cat b.yml

I'm running into the infamous issue where with_items isn't skipped if when
evaluates to false (https://github.com/ansible/ansible/issues/13791). That
said, I'm at loss as to how to workaround my particular issue.

It's not that infamous, it's just how Jinja work, and when you understand the concept it is easy to deal with.

Consider these two tasks (simplified for discussion):

#> cat b.yml
---
- hosts: 127.0.0.1
  connection: local
  gather_facts: False
  tasks:
  - name: get json
    shell: "echo '{ \"a\": [ 1,2,3 ] }'"
    register: b
    when: X=='1'
  - name: echo a array
    debug: msg="{{ item }}"
    with_items: "{{ (b.stdout | from_json).a }}"
    when: X=='1'

When X=0 the variable b will be defined, it contains data about the sipped reason.
But b will not contain the key stdout so this variable need to be filtered through default filter.

Since b.stdout is filter through from_json the default filter need to provide a empty json string to satisfy the filter.

   with_items: "{{ (b.stdout | from_json).a }}"

becomes

   with_items: "{{ (b.stdout | default('{}') | from_json).a }}"

but this will also fail since the empty {} json string doesn't contain a key name "a" so this also need to go through the default filter.
Since with_items need a list this must be an empty list , so it becomes

   with_items: "{{ (b.stdout | default('{}') | from_json).a | default() }}"

So the principle is, if a variable is not defined it need to go through the default filter.

I hope this explanation gave some meaning.

Thanks very much, Kai. This does help my understanding. I was trying to use default() after the b.stdout to generate the JSON (i.e., have default generate ‘{ “a”: “” }’) and wasn’t having any luck because of all the nested quotes. I still consider it counterintuitive that Ansible evaluates with_items: even if when: skips it, but no use arguing here.

Thanks again for your help. Appreciate it.

Rob

That's because when is evaluated for each element in with_items, so with_items must run before when.
Remember that you can use the item variable in when, just to illustrate

   - debug: msg="I run"
     when: item == True
     with_items:
       - True
       - False
       - True

with_items must run first so when has the correct value for the variable item.

Ah, yes. Makes sense now. Thanks Kai.

Rob