Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

loop_control/label shows wrong value when referencing task-level var #38899

Closed
agaffney opened this issue Apr 17, 2018 · 8 comments · Fixed by #39818
Closed

loop_control/label shows wrong value when referencing task-level var #38899

agaffney opened this issue Apr 17, 2018 · 8 comments · Fixed by #39818
Labels
affects_2.5 This issue/PR affects Ansible v2.5 bug This issue/PR relates to a bug. support:core This issue/PR relates to code supported by the Ansible Engineering Team.

Comments

@agaffney
Copy link
Contributor

agaffney commented Apr 17, 2018

ISSUE TYPE
  • Bug Report
COMPONENT NAME

loop_control/label

ANSIBLE VERSION
ansible 2.5.0
CONFIGURATION
ANSIBLE_PIPELINING(/etc/ansible/ansible.cfg) = True
DEFAULT_SCP_IF_SSH(/etc/ansible/ansible.cfg) = True
RETRY_FILES_ENABLED(/etc/ansible/ansible.cfg) = False
OS / ENVIRONMENT

N/A

SUMMARY

When using the loop_control/label feature and referencing a task-level var, the var seems to be evaluated only once.

STEPS TO REPRODUCE
- hosts: localhost
  gather_facts: no
  tasks:
    - name: test stuff
      vars:
        foo: '{{ item|int }}'
      debug:
        var: foo
      with_sequence: start=1 count=3
      loop_control:
        label: '{{ foo }}'
EXPECTED RESULTS
PLAY [localhost] **************************************************************************************************************************************************************************************************************************************************************

TASK [test stuff] *************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => (item=1) => {
    "foo": "1"
}
ok: [localhost] => (item=2) => {
    "foo": "2"
}
ok: [localhost] => (item=3) => {
    "foo": "3"
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0   
ACTUAL RESULTS
PLAY [localhost] **************************************************************************************************************************************************************************************************************************************************************

TASK [test stuff] *************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => (item=1) => {
    "foo": "1"
}
ok: [localhost] => (item=1) => {
    "foo": "2"
}
ok: [localhost] => (item=1) => {
    "foo": "3"
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0  
@ansibot
Copy link
Contributor

ansibot commented Apr 17, 2018

Files identified in the description:
None

If these files are inaccurate, please update the component name section of the description or use the !component bot command.

click here for bot help

@ansibot ansibot added affects_2.5 This issue/PR affects Ansible v2.5 bug This issue/PR relates to a bug. needs_triage Needs a first human triage before being processed. support:core This issue/PR relates to code supported by the Ansible Engineering Team. labels Apr 17, 2018
@ryansb ryansb removed the needs_triage Needs a first human triage before being processed. label Apr 17, 2018
@par02
Copy link

par02 commented May 1, 2018

I encountered this same issue in 2.4.4 after upgrading from 2.4.2 due to a memory issue (2.4.2 displayed the labels correctly).

The playbook I found this in was a lot more complicated, but by experimenting I was able to satisfy myself that only the label was displayed incorrectly. The loop variable items still seem to be correct in the underlying data, and actions using that data appear correct.
Importantly: the loop correctly reports both "changed" and "failed" status for each iteration.

I tested the example above with addition of a register, so that the internal loop data can be seen. From this it is clear that "_ansible_item_label" should be changed but isn't. (However, I'm unsure about the other "_ansible.." loop variables - in this simple example, the values are the same for each item.)

Hopefully this helps:

Modified playbook

- hosts: localhost
  gather_facts: no

  tasks:
    - name: test stuff
      vars:
        foo: '{{ item|int }}'
      debug:
        var: foo
      with_sequence: start=1 count=3
      loop_control:
        label: '{{ foo }}'
      register: baz

    - name: show stuff
      debug:
        var: baz

Results

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

TASK [test stuff] ****************************************************************
ok: [localhost] => (item=1) => {
    "foo": "1"
}
ok: [localhost] => (item=1) => {
    "foo": "2"
}
ok: [localhost] => (item=1) => {
    "foo": "3"
}

TASK [show stuff] ****************************************************************
ok: [localhost] => {
    "baz": {
        "changed": false,
        "msg": "All items completed",
        "results": [
            {
                "_ansible_ignore_errors": null,
                "_ansible_item_label": "1",
                "_ansible_item_result": true,
                "_ansible_no_log": false,
                "_ansible_verbose_always": true,
                "changed": false,
                "failed": false,
                "foo": "1",
                "item": "1"
            },
            {
                "_ansible_ignore_errors": null,
                "_ansible_item_label": "1",
                "_ansible_item_result": true,
                "_ansible_no_log": false,
                "_ansible_verbose_always": true,
                "changed": false,
                "failed": false,
                "foo": "2",
                "item": "2"
            },
            {
                "_ansible_ignore_errors": null,
                "_ansible_item_label": "1",
                "_ansible_item_result": true,
                "_ansible_no_log": false,
                "_ansible_verbose_always": true,
                "changed": false,
                "failed": false,
                "foo": "3",
                "item": "3"
            }
        ]
    }
}

PLAY RECAP ***********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0

@jschwanz
Copy link

jschwanz commented May 1, 2018

I'm on 2.4.4 as well, and see this when using with_subelements.

Playbook

- hosts: localhost
  gather_facts: False
  vars:
    myvar:
      - x: "first x value"
        y:
          - "y1": "first y1 value"
            "y2": "first y2 value"
      - x: "second x value"
        y:
          - "y1": "second y1 value"
            "y2": "second y2 value"
  tasks:
    - name: the with_subelements way
      debug:
        msg: "{{ item.1.y1 }}"
      with_subelements:
        - "{{ myvar }}"
        - "y"
      loop_control:
        label: "{{ item.0.x }}"

    - name: the lookup way
      debug:
        msg: "{{ item.1.y1 }}"
      with_items:
        - "{{ lookup('subelements', myvar, 'y') }}"
      loop_control:
        label: "{{ item.0.x }}"

Actual Results

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

TASK [the with_subelements way] ************************************************
ok: [localhost] => (item=first x value) => {
    "msg": "first y1 value"
}
ok: [localhost] => (item=first x value) => {
    "msg": "second y1 value"
}

TASK [the lookup way] **********************************************************
ok: [localhost] => (item=first x value) => {
    "msg": "first y1 value"
}
ok: [localhost] => (item=first x value) => {
    "msg": "second y1 value"
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0

Expected Results

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

TASK [the with_subelements way] ************************************************
ok: [localhost] => (item=first x value) => {
    "msg": "first y1 value"
}
ok: [localhost] => (item=second x value) => {
    "msg": "second y1 value"
}

TASK [the lookup way] **********************************************************
ok: [localhost] => (item=first x value) => {
    "msg": "first y1 value"
}
ok: [localhost] => (item=second x value) => {
    "msg": "second y1 value"
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0

@agaffney
Copy link
Contributor Author

agaffney commented May 7, 2018

@bcoca do you know what changed that is causing this? You indicated on IRC that it probably had something to do with task-level vars caching.

@sivel
Copy link
Member

sivel commented May 7, 2018

A git bisect indicates that this was caused be 4546e7d

@sivel
Copy link
Member

sivel commented May 7, 2018

It seems to be the side effect of moving templar = Templar(...) out of the for loop. This indicates that some set of vars being used in Templar are not being mutated, but instead overwritten.

@agaffney
Copy link
Contributor Author

agaffney commented May 7, 2018

That seems to fit with what bcoca had said on IRC. The previous code re-instantiated the Templar class on each loop iteration, but now it only happens once for the task.

@agaffney
Copy link
Contributor Author

agaffney commented May 7, 2018

This could probably be fixed by just bringing back the line to re-instantiate the Templar class for each loop iteration. This would result in n+1 instantiations of Templar for a task that loops n times, vs. the previous n instantiations from before this fix, but would satisfy the intentions of bcoca's change.

agaffney added a commit to agaffney/ansible that referenced this issue May 7, 2018
agaffney added a commit to agaffney/ansible that referenced this issue May 7, 2018
agaffney added a commit to agaffney/ansible that referenced this issue May 7, 2018
bcoca pushed a commit that referenced this issue May 7, 2018
* Update vars for loop_control on each loop iteration (fixes #38899) (#39818)

(cherry picked from commit 01e8139)

* Changelog snippet for cherry-pick of #39818
oolongbrothers pushed a commit to oolongbrothers/ansible that referenced this issue May 12, 2018
oolongbrothers pushed a commit to oolongbrothers/ansible that referenced this issue May 14, 2018
oolongbrothers pushed a commit to oolongbrothers/ansible that referenced this issue May 14, 2018
oolongbrothers pushed a commit to oolongbrothers/ansible that referenced this issue May 15, 2018
oolongbrothers pushed a commit to oolongbrothers/ansible that referenced this issue May 15, 2018
@ansible ansible locked and limited conversation to collaborators May 7, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.5 This issue/PR affects Ansible v2.5 bug This issue/PR relates to a bug. support:core This issue/PR relates to code supported by the Ansible Engineering Team.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants