Unexpected behavior change in loop over debug task in 2.14.2 -> 2.16 upgrade

john.elion
Fri, 28 Jun 2024 13:53:39 +0000
Get Help

My development team has used “complex variables” (i.e., references to specific dictionary fields) in loops over the debug task for a long time. Example:

- debug:
     var: "{{ item }}"
  with_items:
  - result.rc
  - result.stdout
  - result.stderr

We have done this in order to avoid dumping the whole dictionary, which can be much longer. Recently, we were unexpectedly upgraded from Ansible 2.14.2 to Ansible 2.16. We find that this behavior no longer works. Instead of printing the values for each field in the list, it now prints something that looks like a recursive reference error (i.e., “dict.field” is displayed as “{{ dict.field }}”).

A simple playbook (shown below, with output from both versions) demonstrates the change in behavior. (While trying to find a workaround, we have found that replacing “with_items” with “loop” gives us a workaround in both versions, but we’re not sure why.)

This happens even if we just put the dictionary variable as a single entry in the loop.

Is the use of a dictionary field (instead of just a plain, undecorated variable name) allowed in the debug task? Can loops be applied to the debug task? Is the change in behavior expected?

Thank you.

Playbook:

- hosts: installer
  gather_facts: false
  vars:
    result:
      rc: 0
      stdout: 'TASK OUTPUT'
      stderr: 'ERROR OUTPUT'
  tasks:
  - debug:
      var: "{{ item }}"
    with_items:
    - result.rc
    - result.stdout
    - result.stderr

  - debug:
      var: "{{ item }}"
    loop:
    - result.rc
    - result.stdout
    - result.stderr

Results on 2.14.2 (got what I expected)

PLAY [installer] ***************************************************************

TASK [debug] *******************************************************************
ok: [paas-installer] => (item=result.rc) => {
    "ansible_loop_var": "item",
    "item": "result.rc",
    "result.rc": "0"
}
ok: [paas-installer] => (item=result.stdout) => {
    "ansible_loop_var": "item",
    "item": "result.stdout",
    "result.stdout": "TASK OUTPUT"
}
ok: [paas-installer] => (item=result.stderr) => {
    "ansible_loop_var": "item",
    "item": "result.stderr",
    "result.stderr": "ERROR OUTPUT"
}

TASK [debug] *******************************************************************
ok: [paas-installer] => (item=result.rc) => {
    "ansible_loop_var": "item",
    "item": "result.rc",
    "result.rc": "0"
}
ok: [paas-installer] => (item=result.stdout) => {
    "ansible_loop_var": "item",
    "item": "result.stdout",
    "result.stdout": "TASK OUTPUT"
}
ok: [paas-installer] => (item=result.stderr) => {
    "ansible_loop_var": "item",
    "item": "result.stderr",
    "result.stderr": "ERROR OUTPUT"
}

PLAY RECAP *********************************************************************
paas-installer             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Results on 2.16 (first debug task has unexpected results):

PLAY [installer] ***************************************************************

TASK [debug] *******************************************************************
ok: [paas-installer] => (item=result.rc) => {
    "ansible_loop_var": "item",
    "item": "result.rc",
    "result.rc": "{{result.rc}}"
}
ok: [paas-installer] => (item=result.stdout) => {
    "ansible_loop_var": "item",
    "item": "result.stdout",
    "result.stdout": "{{result.stdout}}"
}
ok: [paas-installer] => (item=result.stderr) => {
    "ansible_loop_var": "item",
    "item": "result.stderr",
    "result.stderr": "{{result.stderr}}"
}

TASK [debug] *******************************************************************
ok: [paas-installer] => (item=result.rc) => {
    "ansible_loop_var": "item",
    "item": "result.rc",
    "result.rc": "0"
}
ok: [paas-installer] => (item=result.stdout) => {
    "ansible_loop_var": "item",
    "item": "result.stdout",
    "result.stdout": "TASK OUTPUT"
}
ok: [paas-installer] => (item=result.stderr) => {
    "ansible_loop_var": "item",
    "item": "result.stderr",
    "result.stderr": "ERROR OUTPUT"
}

PLAY RECAP *********************************************************************
paas-installer : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Version details:
2.14.2 installation

ansible [core 2.14.2]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/var/paas/tmp/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.11/site-packages/ansible
  ansible collection location = /var/paas/tmp/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.11.5 (main, Sep 22 2023, 15:34:29) [GCC 8.5.0 20210514 (Red Hat 8.5.0-20)] (/usr/bin/python3.11)
  jinja version = 3.1.2
  libyaml = True

Upgraded 2.16 installation

ansible [core 2.16.3]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/var/paas/tmp/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.12/site-packages/ansible
  ansible collection location = /var/paas/tmp/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.12.1 (main, Feb 21 2024, 10:25:11) [GCC 8.5.0 20210514 (Red Hat 8.5.0-21)] (/usr/bin/python3.12)
  jinja version = 3.1.2
  libyaml = True

4 posts - 3 participants