Fix task.resolved_action callbacks (#82003) (#83329)

* Fix task.resolved_action for callbacks when playbooks use action or local_action

* Fix using module_defaults with 'action' and 'local_action' task FA and add a test case

Fixes #81905

(cherry picked from commit f2435375a8)
pull/83398/head
Sloane Hertel 6 months ago committed by GitHub
parent 122d11491f
commit 76c7dfd968
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,3 @@
bugfixes:
- Fix the task attribute ``resolved_action`` to show the FQCN instead of ``None`` when ``action`` or ``local_action`` is used in the playbook.
- Fix using ``module_defaults`` with ``local_action``/``action`` (https://github.com/ansible/ansible/issues/81905).

@ -53,6 +53,17 @@ BUILTIN_TASKS = frozenset(add_internal_fqcns((
))) )))
def _get_action_context(action_or_module, collection_list):
module_context = module_loader.find_plugin_with_context(action_or_module, collection_list=collection_list)
if module_context and module_context.resolved and module_context.action_plugin:
action_or_module = module_context.action_plugin
context = action_loader.find_plugin_with_context(action_or_module, collection_list=collection_list)
if not context or not context.resolved:
context = module_context
return context
class ModuleArgsParser: class ModuleArgsParser:
""" """
@ -291,6 +302,11 @@ class ModuleArgsParser:
delegate_to = 'localhost' delegate_to = 'localhost'
action, args = self._normalize_parameters(thing, action=action, additional_args=additional_args) action, args = self._normalize_parameters(thing, action=action, additional_args=additional_args)
if action is not None and not skip_action_validation:
context = _get_action_context(action, self._collection_list)
if context is not None and context.resolved:
self.resolved_action = context.resolved_fqcn
# module: <stuff> is the more new-style invocation # module: <stuff> is the more new-style invocation
# filter out task attributes so we're only querying unrecognized keys as actions/modules # filter out task attributes so we're only querying unrecognized keys as actions/modules
@ -306,9 +322,7 @@ class ModuleArgsParser:
is_action_candidate = True is_action_candidate = True
else: else:
try: try:
context = action_loader.find_plugin_with_context(item, collection_list=self._collection_list) context = _get_action_context(item, self._collection_list)
if not context.resolved:
context = module_loader.find_plugin_with_context(item, collection_list=self._collection_list)
except AnsibleError as e: except AnsibleError as e:
if e.obj is None: if e.obj is None:
e.obj = self._task_ds e.obj = self._task_ds

@ -208,6 +208,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl
# But if it wasn't, we can add the yaml object now to get more detail # But if it wasn't, we can add the yaml object now to get more detail
raise AnsibleParserError(to_native(e), obj=ds, orig_exc=e) raise AnsibleParserError(to_native(e), obj=ds, orig_exc=e)
else: else:
# Set the resolved action plugin (or if it does not exist, module) for callbacks.
self.resolved_action = args_parser.resolved_action self.resolved_action = args_parser.resolved_action
# the command/shell/script modules used to support the `cmd` arg, # the command/shell/script modules used to support the `cmd` arg,

@ -10,5 +10,7 @@
- ping: - ping:
- collection_action: - collection_action:
- collection_module: - collection_module:
- formerly_action: - local_action:
- formerly_module: module: formerly_action
- action:
module: formerly_module

@ -10,16 +10,23 @@
- debug: - debug:
register: foo register: foo
- local_action:
module: debug
register: local_action_foo
- name: test that 'debug' task used default 'msg' param - name: test that 'debug' task used default 'msg' param
assert: assert:
that: foo.msg == "test default" that:
- foo.msg == "test default"
- local_action_foo.msg == "test default"
- name: remove test file - name: remove test file
file: file:
state: absent state: absent
- name: touch test file - name: touch test file
file: local_action:
module: file
state: touch state: touch
- name: stat test file - name: stat test file

@ -20,6 +20,10 @@ from __future__ import annotations
import unittest import unittest
from ansible.playbook.block import Block from ansible.playbook.block import Block
from ansible.playbook.task import Task from ansible.playbook.task import Task
from ansible.plugins.loader import init_plugin_loader
init_plugin_loader()
class TestBlock(unittest.TestCase): class TestBlock(unittest.TestCase):

@ -24,13 +24,16 @@ from unittest.mock import MagicMock
from units.mock.loader import DictDataLoader from units.mock.loader import DictDataLoader
from ansible import errors from ansible import errors
from ansible.playbook import helpers
from ansible.playbook.block import Block from ansible.playbook.block import Block
from ansible.playbook.handler import Handler from ansible.playbook.handler import Handler
from ansible.playbook.task import Task from ansible.playbook.task import Task
from ansible.playbook.task_include import TaskInclude from ansible.playbook.task_include import TaskInclude
from ansible.playbook.role.include import RoleInclude from ansible.playbook.role.include import RoleInclude
from ansible.plugins.loader import init_plugin_loader
from ansible.playbook import helpers
init_plugin_loader()
class MixinForMocks(object): class MixinForMocks(object):

Loading…
Cancel
Save