From 0e28ab45282231c05bedd8674bfc1720b7ecc1da Mon Sep 17 00:00:00 2001 From: Martin Krizek Date: Wed, 20 Mar 2019 14:46:19 +0100 Subject: [PATCH] Template run_once for handlers (#54030) Fixes #27237 --- .../27237-handlers-template-run_once.yaml | 2 ++ lib/ansible/plugins/strategy/__init__.py | 14 +++++++------- test/integration/targets/handlers/runme.sh | 7 +++++++ .../handlers/test_handlers_template_run_once.yml | 12 ++++++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 changelogs/fragments/27237-handlers-template-run_once.yaml create mode 100644 test/integration/targets/handlers/test_handlers_template_run_once.yml diff --git a/changelogs/fragments/27237-handlers-template-run_once.yaml b/changelogs/fragments/27237-handlers-template-run_once.yaml new file mode 100644 index 00000000000..3e15287fdb8 --- /dev/null +++ b/changelogs/fragments/27237-handlers-template-run_once.yaml @@ -0,0 +1,2 @@ +bugfixes: + - Fix handlers to allow for templated values in run_once (https://github.com/ansible/ansible/issues/27237) diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index d182c456bd9..84d43d9ab9e 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -846,9 +846,7 @@ class StrategyBase: # we consider the ability of meta tasks to flush handlers for handler in handler_block.block: if handler.notified_hosts: - handler_vars = self._variable_manager.get_vars(play=iterator._play, task=handler) - handler_name = handler.get_name() - result = self._do_handler_run(handler, handler_name, iterator=iterator, play_context=play_context) + result = self._do_handler_run(handler, handler.get_name(), iterator=iterator, play_context=play_context) if not result: break return result @@ -871,11 +869,11 @@ class StrategyBase: self._tqm.send_callback('v2_playbook_on_handler_task_start', handler) handler.name = saved_name - run_once = False + bypass_host_loop = False try: action = action_loader.get(handler.action, class_only=True) - if handler.run_once or getattr(action, 'BYPASS_HOST_LOOP', False): - run_once = True + if getattr(action, 'BYPASS_HOST_LOOP', False): + bypass_host_loop = True except KeyError: # we don't care here, because the action may simply not have a # corresponding action plugin @@ -887,7 +885,9 @@ class StrategyBase: task_vars = self._variable_manager.get_vars(play=iterator._play, host=host, task=handler) self.add_tqm_variables(task_vars, play=iterator._play) self._queue_task(host, handler, task_vars, play_context) - if run_once: + + templar = Templar(loader=self._loader, variables=task_vars) + if templar.template(handler.run_once) or bypass_host_loop: break # collect the results from the handler run diff --git a/test/integration/targets/handlers/runme.sh b/test/integration/targets/handlers/runme.sh index 711f91ee006..1bddc079c9e 100755 --- a/test/integration/targets/handlers/runme.sh +++ b/test/integration/targets/handlers/runme.sh @@ -75,3 +75,10 @@ set -e # https://github.com/ansible/ansible/issues/47287 [ "$(ansible-playbook test_handlers_including_task.yml -i ../../inventory -v "$@" | egrep -o 'failed=[0-9]+')" = "failed=0" ] + +# https://github.com/ansible/ansible/issues/27237 +set +e +result="$(ansible-playbook test_handlers_template_run_once.yml -i inventory.handlers "$@" 2>&1)" +set -e +grep -q "handler A" <<< "$result" +grep -q "handler B" <<< "$result" diff --git a/test/integration/targets/handlers/test_handlers_template_run_once.yml b/test/integration/targets/handlers/test_handlers_template_run_once.yml new file mode 100644 index 00000000000..6edc32e235c --- /dev/null +++ b/test/integration/targets/handlers/test_handlers_template_run_once.yml @@ -0,0 +1,12 @@ +- hosts: A,B + gather_facts: no + tasks: + - debug: + changed_when: true + notify: + - handler + handlers: + - name: handler + debug: + msg: "handler {{ inventory_hostname }}" + run_once: "{{ testvar | default(False) }}"