Support configuring callback plugins with --extra-vars (#84661)

* Support configuring callback plugins with --extra-vars

Callback plugins define variable names in the documentation for ConfigManager

Variable values can be omitted

* Added default callback variable configuration for display_skipped_hosts

Fixes #84469

Co-authored-by: Matt Clay <matt@mystile.com>
This commit is contained in:
Sloane Hertel
2025-11-18 20:04:22 -05:00
committed by GitHub
parent af9009b00d
commit 7ebc9fa5d6
8 changed files with 54 additions and 3 deletions

View File

@@ -0,0 +1,3 @@
minor_changes:
- callback plugins - support configuration using extra variables.
- default callback plugin - add variable configuration for ``display_skipped_hosts`` (https://github.com/ansible/ansible/issues/84469).

View File

@@ -40,6 +40,7 @@ from ansible.module_utils.common.text.converters import to_native
from ansible.parsing.dataloader import DataLoader
from ansible.playbook.play_context import PlayContext
from ansible.playbook.task import Task
from ansible.plugins.callback import CallbackBase
from ansible.plugins.loader import callback_loader, strategy_loader, module_loader
from ansible.plugins.callback import CallbackBase
from ansible._internal._templating._engine import TemplateEngine
@@ -111,6 +112,16 @@ class AnsibleEndPlay(Exception):
self.result = result
def _resolve_callback_option_variables(callback: CallbackBase, variables: dict[str, object], templar: TemplateEngine) -> None:
"""Set callback plugin options using documented variables."""
callback_variables = {
var_name: variables[var_name]
for var_name in C.config.get_plugin_vars(callback.plugin_type, callback._load_name)
if var_name in variables
}
callback.set_options(var_options=templar.template(callback_variables))
class TaskQueueManager:
"""
@@ -248,8 +259,10 @@ class TaskQueueManager:
if not stdout_callback:
raise AnsibleError(f"Could not load {self._stdout_callback_name!r} callback plugin.")
templar = TemplateEngine(loader=self._loader, variables=self._variable_manager._extra_vars)
stdout_callback._init_callback_methods()
stdout_callback.set_options()
_resolve_callback_option_variables(stdout_callback, self._variable_manager._extra_vars, templar)
self._callback_plugins.append(stdout_callback)
@@ -303,7 +316,7 @@ class TaskQueueManager:
# really a bug in the plugin itself which we ignore as callback errors are not supposed to be fatal.
if callback_obj:
callback_obj._init_callback_methods()
callback_obj.set_options()
_resolve_callback_option_variables(callback_obj, self._variable_manager._extra_vars, templar)
self._callback_plugins.append(callback_obj)
else:
display.warning("Skipping callback '%s', as it does not create a valid plugin instance." % callback_name)

View File

@@ -19,6 +19,9 @@ class ModuleDocFragment(object):
ini:
- key: display_skipped_hosts
section: defaults
vars:
- name: ansible_display_skipped_hosts
version_added: "2.21"
display_ok_hosts:
name: Show 'ok' hosts
description: "Toggle to control displaying 'ok' task/host results in a task."

View File

@@ -0,0 +1,2 @@
indirect_extra: false
ansible_display_skipped_hosts: "{{ indirect_extra }}"

View File

@@ -23,3 +23,20 @@ fi
# test connection tracking
ANSIBLE_CALLBACKS_ENABLED=track_connections ansible-playbook "$@" -i ../../inventory connection_name.yml | tee "${OUTFILE}"
grep "FOUND EXPECTED EVENTS" "${OUTFILE}"
# test configuring display_skipped_hosts using --extra-vars
hide_skipped="$(ansible-playbook skip_hosts.yml -v --extra-vars @./callback_vars.yml "$@")"
if [[ "$hide_skipped" == *skip_reason* ]]; then
echo "Failed to configure display_skipped_hosts (false)"
exit 1
fi
include_skipped="$(ansible-playbook skip_hosts.yml -v --extra-vars @./callback_vars.yml --extra-vars indirect_extra=true "$@")"
if [[ "$include_skipped" != *skip_reason* ]]; then
echo "Failed to configure display_skipped_hosts (true)"
exit 1
fi
include_skipped="$(ansible-playbook skip_hosts.yml -v --extra-vars @./callback_vars.yml --extra-vars indirect_extra='{{ omit }}' "$@")"
if [[ "$include_skipped" != *skip_reason* ]]; then
echo "Failed to omit display_skipped_hosts (default true)"
exit 1
fi

View File

@@ -0,0 +1,5 @@
- hosts: localhost
gather_facts: false
tasks:
- command: /bin/false
when: false

View File

@@ -8,6 +8,11 @@ DOCUMENTATION = """
short_description: does stuff
description:
- does some stuff
options:
ok_msg:
default: "usercallback says ok"
vars:
- name: on_ok
"""
@@ -22,4 +27,4 @@ class CallbackModule(CallbackBase):
self._display.display("loaded usercallback from collection, yay")
def v2_runner_on_ok(self, result):
self._display.display("usercallback says ok")
self._display.display(self.get_option("ok_msg"))

View File

@@ -31,6 +31,9 @@ ANSIBLE_CALLBACKS_ENABLED=formerly_core_removed_callback ansible localhost -m de
# ensure non existing callback does not crash ansible
ANSIBLE_CALLBACKS_ENABLED=charlie.gomez.notme ansible localhost -m debug 2>&1 | grep -- "Skipping callback plugin 'charlie.gomez.notme'"
# test configuring collection callback plugins with extra variables
ANSIBLE_CALLBACKS_ENABLED=testns.testcoll.usercallback ansible-playbook noop.yml --extra-vars 'on_ok="configured msg"' | grep 'configured msg'
unset ANSIBLE_LOAD_CALLBACK_PLUGINS
# adhoc normally shouldn't load non-default plugins- let's be sure
output=$(ANSIBLE_CALLBACKS_ENABLED=testns.testcoll.usercallback ansible localhost -m debug)