with_subelements works where loop with subelements filter fails

I have the following tasks in a block, which I’ve modified to use the new ‘loop’ structure:

`

  • name: process ipv6 rules if they exist
    block:
  • name: create all ipv6 firewall log statements from ‘firewall’ variable
    iptables:
    ip_version: ipv6
    comment: “{{ item.0.comment|default(omit) }}”
    destination: “{{ item.0.destination|default(omit) }}”
    destination_port: “{{ item.0.destination_port|default(omit) }}”
    source: “{{ item.1 }}”
    source_port: “{{ item.0.source_port|default(omit) }}”
    protocol: “{{ item.0.protocol|default(omit) }}”
    jump: “LOG”
    chain: “{{ item.0.chain|default(‘INPUT’) }}”
    ctstate: “{{ item.0.state|default(‘NEW’) }}”
    in_interface: “{{ item.0.in_interface|default(omit) }}”
    out_interface: “{{ item.0.out_interface|default(omit) }}”
    limit: “3/minute”
    limit_burst: 10

log_prefix: "[ FIREWALL ] " # ( will be added in ansible 2.5 )

state: present
when: item.0.log is defined and item.0.log == ‘yes’
loop: “{{ firewall6.rules|subelements(‘source’) }}”
notify:

  • save ip6tables

  • name: apply ipv6 rules using ‘firewall’ variable defined in inventory vars
    iptables:
    ip_version: ipv6
    comment: “{{ item.0.comment|default(omit) }}”
    destination: “{{ item.0.destination|default(omit) }}”
    destination_port: “{{ item.0.destination_port|default(omit) }}”
    source: “{{ item.1 }}”
    source_port: “{{ item.0.source_port|default(omit) }}”
    protocol: “{{ item.0.protocol|default(omit) }}”
    jump: “{{ item.0.rule|default(‘ACCEPT’) }}”
    chain: “{{ item.0.chain|default(‘INPUT’) }}”
    ctstate: “{{ item.0.state|default(omit) }}”
    in_interface: “{{ item.0.in_interface|default(omit) }}”
    out_interface: “{{ item.0.out_interface|default(omit) }}”
    state: present
    loop: “{{ firewall6.rules|subelements(‘source’) }}”
    notify:

  • save ip6tables

when: firewall6 is defined and firewall6.rules is defined
`

When I run this I get the following error:

TASK [firewall : create all ipv6 firewall log statements from 'firewall' variable] ************************************* fatal: [172.20.0.88]: FAILED! => {"msg": "obj must be a list of dicts or a nested dict"} fatal: [172.20.0.77]: FAILED! => {"msg": "obj must be a list of dicts or a nested dict"} fatal: [172.20.0.55]: FAILED! => {"msg": "obj must be a list of dicts or a nested dict"}

I changed the first task to use ‘with_subelements’ as follows:

`

  • name: create all ipv6 firewall log statements from ‘firewall’ variable
    iptables:
    ip_version: ipv6
    comment: “{{ item.0.comment|default(omit) }}”
    destination: “{{ item.0.destination|default(omit) }}”
    destination_port: “{{ item.0.destination_port|default(omit) }}”
    source: “{{ item.1 }}”
    source_port: “{{ item.0.source_port|default(omit) }}”
    protocol: “{{ item.0.protocol|default(omit) }}”
    jump: “LOG”
    chain: “{{ item.0.chain|default(‘INPUT’) }}”
    ctstate: “{{ item.0.state|default(‘NEW’) }}”
    in_interface: “{{ item.0.in_interface|default(omit) }}”
    out_interface: “{{ item.0.out_interface|default(omit) }}”
    limit: “3/minute”
    limit_burst: 10

log_prefix: "[ FIREWALL ] " # ( will be added in ansible 2.5 )

state: present
when: item.0.log is defined and item.0.log == ‘yes’
with_subelements:

  • “{{ firewall6.rules }}”
  • source
    notify:
  • save ip6tables
    `

When I re-run the playbook it now skips the task, as intended:

TASK [firewall : create all ipv6 firewall log statements from 'firewall' variable] ************************************* skipping: [172.20.0.88] skipping: [172.20.0.77] skipping: [172.20.0.55]

Can anyone tell me why this is happening?

Thanks,
Guy

Also of note: firewall6.rules doesn’t exist on any of the hosts I’m running this playbook against, so it should be skipping the entire block, but it’s not.