Fix task.resolved_action callbacks (#82003)

* 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
pull/83332/head
Sloane Hertel 6 months ago committed by GitHub
parent 46168c8cc2
commit f2435375a8
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:
"""
@ -291,6 +302,11 @@ class ModuleArgsParser:
delegate_to = 'localhost'
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
# filter out task attributes so we're only querying unrecognized keys as actions/modules
@ -306,9 +322,7 @@ class ModuleArgsParser:
is_action_candidate = True
else:
try:
context = action_loader.find_plugin_with_context(item, collection_list=self._collection_list)
if not context.resolved:
context = module_loader.find_plugin_with_context(item, collection_list=self._collection_list)
context = _get_action_context(item, self._collection_list)
except AnsibleError as e:
if e.obj is None:
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
raise AnsibleParserError(to_native(e), obj=ds, orig_exc=e)
else:
# Set the resolved action plugin (or if it does not exist, module) for callbacks.
self.resolved_action = args_parser.resolved_action
# the command/shell/script modules used to support the `cmd` arg,

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

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

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

@ -24,13 +24,16 @@ from unittest.mock import MagicMock
from units.mock.loader import DictDataLoader
from ansible import errors
from ansible.playbook import helpers
from ansible.playbook.block import Block
from ansible.playbook.handler import Handler
from ansible.playbook.task import Task
from ansible.playbook.task_include import TaskInclude
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):

Loading…
Cancel
Save