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

Unable to access ansible_failed_task attributes if at least one contains a template #74036

Closed
egmar opened this issue Mar 25, 2021 · 8 comments · Fixed by #74290
Closed

Unable to access ansible_failed_task attributes if at least one contains a template #74036

egmar opened this issue Mar 25, 2021 · 8 comments · Fixed by #74290
Labels
affects_2.10 This issue/PR affects Ansible v2.10 bug This issue/PR relates to a bug. P3 Priority 3 - Approved, No Time Limitation support:core This issue/PR relates to code supported by the Ansible Engineering Team.

Comments

@egmar
Copy link
Contributor

egmar commented Mar 25, 2021

Summary

Unable to access ansible_failed_task attributes if at least one contains a template
Looks like Ansible recursively processes templates inside rescue block when trying to access values in ansible_failed_task variable.

Issue Type

Bug Report

Component Name

block, rescue, ansible_failed_task

Ansible Version

ansible 2.10.7
  python version = 3.9.1 (default, Jan 20 2021, 00:00:00) [GCC 10.2.1 20201125 (Red Hat 10.2.1-9)]

Configuration

CACHE_PLUGIN(ansible.cfg) = jsonfile
CACHE_PLUGIN_CONNECTION(ansible.cfg) = ./.ansible_facts
DEPRECATION_WARNINGS(ansible.cfg) = False

OS / Environment

Fedora release 33 (Thirty Three)

Steps to Reproduce

- name: test
  hosts: localhost
  connection: local
  gather_facts: false
  vars:
    - data: {}
  tasks:
    - block:
        - debug:
            msg: "{{ data.value }}"
      rescue:
        - debug:
            msg: "{{ ansible_failed_task.action }}"

Expected Results

The task in rescue should end successfully and print the name of action module which led to failures

Actual Results

$ ansible-playbook test-rescue.yml 
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [test] *********************************************************************************************************************************************************************************************************************************************************

TASK [debug] ********************************************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'value'\n\nThe error appears to be in 'project/test-rescue.yml': line 10, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n    - block:\n        - debug:\n          ^ here\n"}

TASK [debug] ********************************************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: {'args': {'msg': '{{ data.value }}'}, 'action': 'debug', 'async_val': 0, 'async': 0, 'changed_when': [], 'delay': 5, 'delegate_to': None, 'delegate_facts': None, 'failed_when': [], 'loop': None, 'loop_control': None, 'notify': None, 'poll': 15, 'register': None, 'retries': 3, 'until': [], 'loop_with': None, 'name': '', 'connection': 'local', 'port': None, 'remote_user': None, 'vars': {}, 'module_defaults': [], 'environment': [], 'no_log': None, 'run_once': None, 'ignore_errors': None, 'ignore_unreachable': None, 'check_mode': False, 'diff': False, 'any_errors_fatal': False, 'throttle': 0, 'timeout': 0, 'debugger': None, 'become': False, 'become_method': 'sudo', 'become_user': None, 'become_flags': None, 'become_exe': None, 'when': [], 'tags': [], 'collections': [], 'uuid': '38deade1-8d54-13e2-e7bb-000000000007', 'finalized': False, 'squashed': False, 'parent': {'delegate_to': None, 'delegate_facts': None, 'name': '', 'connection': 'local', 'port': None, 'remote_user': None, 'vars': {}, 'module_defaults': None, 'environment': None, 'no_log': None, 'run_once': None, 'ignore_errors': None, 'ignore_unreachable': None, 'check_mode': False, 'diff': False, 'any_errors_fatal': False, 'throttle': 0, 'timeout': 0, 'debugger': None, 'become': False, 'become_method': 'sudo', 'become_user': None, 'become_flags': None, 'become_exe': None, 'when': [], 'collections': [], 'tags': [], 'dep_chain': None, 'eor': False}, 'parent_type': 'Block', '_ansible_internal_redirect_list': ['debug']}: 'dict object' has no attribute 'value'\n\nThe error appears to be in 'project/test-rescue.yml': line 13, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n      rescue:\n        - debug:\n          ^ here\n"}

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

ansibot commented Mar 25, 2021

Files identified in the description:

If these files are incorrect, 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.10 This issue/PR affects Ansible v2.10 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 Mar 25, 2021
@egmar
Copy link
Contributor Author

egmar commented Mar 25, 2021

!component lib/ansible/plugins/strategy/init.py

@egmar
Copy link
Contributor Author

egmar commented Mar 25, 2021

!component =lib/ansible/plugins/strategy

@ansibot
Copy link
Contributor

ansibot commented Mar 25, 2021

Files identified in the description:

  • lib/ansible/plugins/strategy

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

click here for bot help

@mkrizek
Copy link
Contributor

mkrizek commented Mar 25, 2021

This should be fixed in devel branch. Can you test your playbook against that branch to see if it fixes your issue?

The PR that fixes the issue is #73881. Backport PRs for 2.9 and 2.10 releases were created.

needs_info

@ansibot ansibot added the needs_info This issue requires further information. Please answer any outstanding questions. label Mar 25, 2021
@egmar egmar changed the title Unable to access ansible_failed_task attributes if at least one containes a template Unable to access ansible_failed_task attributes if at least one contains a template Mar 25, 2021
@egmar
Copy link
Contributor Author

egmar commented Mar 25, 2021

@mkrizek yes, same issue on latest devel

$ ansible-playbook ../test-rescue.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [test] ******************************************************************************************************************************

TASK [debug] *****************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'value'\n\nThe error appears to be in '/home/egor/test-rescue.yml': line 9, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n    - block:\n        - debug:\n          ^ here\n"}

TASK [debug] *****************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: {'args': {'msg': '{{ data.value }}'}, 'action': 'debug', 'async_val': 0, 'async': 0, 'changed_when': [], 'delay': 5, 'delegate_to': None, 'delegate_facts': None, 'failed_when': [], 'loop': None, 'loop_control': None, 'notify': None, 'poll': 15, 'register': None, 'retries': 3, 'until': [], 'loop_with': None, 'name': '', 'connection': 'local', 'port': None, 'remote_user': None, 'vars': {}, 'module_defaults': [], 'environment': [], 'no_log': None, 'run_once': None, 'ignore_errors': None, 'ignore_unreachable': None, 'check_mode': False, 'diff': False, 'any_errors_fatal': False, 'throttle': 0, 'timeout': 0, 'debugger': None, 'become': False, 'become_method': 'sudo', 'become_user': None, 'become_flags': None, 'become_exe': None, 'when': [], 'tags': [], 'collections': [], 'uuid': '00155d74-aa5a-af1b-8c9b-000000000007', 'finalized': True, 'squashed': True}: 'dict object' has no attribute 'value'\n\nThe error appears to be in '/home/egor/test-rescue.yml': line 12, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n      rescue:\n        - debug:\n          ^ here\n"}

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

$ ansible --version
ansible [core 2.11.0b3.post0]  (devel 46b02e125f) last updated 2021/03/25 19:41:43 (GMT +200)
  config file = None
  configured module search path = ['/home/egor/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/egor/ansible/lib/ansible
  ansible collection location = /home/egor/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/egor/ansible/bin/ansible
  python version = 3.8.5 (default, Jul 28 2020, 12:59:40) [GCC 9.3.0]
  jinja version = 2.10.1
  libyaml = True

@egmar egmar changed the title Unable to access ansible_failed_task attributes if at least one contains a template Unable to access ansible_failed_task attributes if at least one contains a template Mar 25, 2021
@sivel
Copy link
Member

sivel commented Mar 25, 2021

This is related to #56345 (comment)

Effectively a templating error should not be recoverable. But we currently lack the right mechanism to convey that from the worker back into the main process.

Short term, we probably should use wrap_var on ansible_failed_task to make it unsafe for further templating.

@ansibot ansibot removed the needs_info This issue requires further information. Please answer any outstanding questions. label Mar 25, 2021
@samdoran samdoran added P3 Priority 3 - Approved, No Time Limitation and removed needs_triage Needs a first human triage before being processed. labels Mar 25, 2021
@egmar
Copy link
Contributor Author

egmar commented Mar 25, 2021

@sivel not sure about unrecoverable part. We got to this problem, by trying to safe-guard any potential issues with roles loaded using include_role and we can't control whether they have all templating safe-guards, so it was logical to us to rescue on error and push the custom crafted message to an external system.

Anyway, I briefly made a fix as suggested:

$ git diff
diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py
index 70dea1ea6f..816597f2ab 100644
--- a/lib/ansible/plugins/strategy/__init__.py
+++ b/lib/ansible/plugins/strategy/__init__.py
@@ -50,6 +50,7 @@ from ansible.playbook.task_include import TaskInclude
 from ansible.plugins import loader as plugin_loader
 from ansible.template import Templar
 from ansible.utils.display import Display
+from ansible.utils.unsafe_proxy import wrap_var
 from ansible.utils.vars import combine_vars
 from ansible.vars.clean import strip_internal_keys, module_response_deepcopy

@@ -572,7 +573,7 @@ class StrategyBase:
                         self._variable_manager.set_nonpersistent_facts(
                             original_host.name,
                             dict(
-                                ansible_failed_task=original_task.serialize(),
+                                ansible_failed_task=wrap_var(original_task.serialize()),
                                 ansible_failed_result=task_result._result,
                             ),
                         )

this doesn't cause the failure anymore (assuming I understood correctly following):

Short term, we probably should use wrap_var on ansible_failed_task to make it unsafe for further templating.

mkrizek added a commit to mkrizek/ansible that referenced this issue Apr 15, 2021
jborean93 pushed a commit that referenced this issue Apr 15, 2021
* Prevent ansible_failed_task from further templating

Fixes #74036

* Add changelog
mkrizek added a commit to mkrizek/ansible that referenced this issue Apr 16, 2021
* Prevent ansible_failed_task from further templating

Fixes ansible#74036

* Add changelog

(cherry picked from commit 664531d)
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue May 4, 2021
v2.10.9

Major Changes
- ansible-test - Tests run with the ``centos6`` and ``default`` test containers now use a PyPI proxy container to access PyPI when Python 2.6 is used. This allows tests running under Python 2.6 to continue functioning even though PyPI is discontinuing support for non-SNI capable clients.

Minor Changes
- Switch to hashlib.sha256() for ansible-test to allow for FIPs mode.

Bugfixes
- Prevent ``ansible_failed_task`` from further templating (ansible/ansible#74036)
- ansible-test - Avoid publishing the port used by the ``pypi-test-container`` since it is only accessed by other containers. This avoids issues when trying to run tests in parallel on a single host.
- ansible-test - Fix docker container IP address detection. The ``bridge`` network is no longer assumed to be the default.
- ansible-test - ensure the correct unit test target is given when the ``__init__.py`` file is modified inside the connection plugins directory
- ansible.utils.encrypt now handles missing or unusable 'crypt' library.
- facts - detect homebrew installed at /opt/homebrew/bin/brew
- interpreter discovery - Debian 8 and lower will avoid unsupported Python3 version in interpreter discovery
- undeprecate hash_merge setting and add more docs clarifying its use and why not to use it.
- wait_for module, move missing socket into function to get proper comparrison in time.
@ansible ansible locked and limited conversation to collaborators May 13, 2021
relrod pushed a commit that referenced this issue May 17, 2021
sivel pushed a commit to sivel/ansible that referenced this issue Jul 8, 2021
…ible#74290)

* Prevent ansible_failed_task from further templating

Fixes ansible#74036

* Add changelog.
(cherry picked from commit 664531d)

Co-authored-by: Martin Krizek <martin.krizek@gmail.com>
relrod pushed a commit that referenced this issue Jul 9, 2021
) (#75220)

* Prevent ansible_failed_task from further templating
Fixes #74036
* Add changelog.
(cherry picked from commit 664531d)

Co-authored-by: Martin Krizek <martin.krizek@gmail.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.10 This issue/PR affects Ansible v2.10 bug This issue/PR relates to a bug. P3 Priority 3 - Approved, No Time Limitation 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.

5 participants