diff --git a/changelogs/fragments/include-run-once.yaml b/changelogs/fragments/include-run-once.yaml new file mode 100644 index 00000000000..ae29bbdb975 --- /dev/null +++ b/changelogs/fragments/include-run-once.yaml @@ -0,0 +1,2 @@ +bugfixes: +- dynamic includes - Add missed ``run_once`` to valid include attributes (https://github.com/ansible/ansible/pull/48068) diff --git a/lib/ansible/playbook/task_include.py b/lib/ansible/playbook/task_include.py index 4c92a3efce3..40b7861cd71 100644 --- a/lib/ansible/playbook/task_include.py +++ b/lib/ansible/playbook/task_include.py @@ -45,7 +45,8 @@ class TaskInclude(Task): OTHER_ARGS = frozenset(('apply',)) # assigned to matching property VALID_ARGS = BASE.union(OTHER_ARGS) # all valid args VALID_INCLUDE_KEYWORDS = frozenset(('action', 'args', 'debugger', 'ignore_errors', 'loop', 'loop_control', - 'loop_with', 'name', 'no_log', 'register', 'tags', 'vars', 'when')) + 'loop_with', 'name', 'no_log', 'register', 'run_once', 'tags', 'vars', + 'when')) # ================================================================================= # ATTRIBUTES diff --git a/test/integration/targets/include_import/run_once/include_me.yml b/test/integration/targets/include_import/run_once/include_me.yml new file mode 100644 index 00000000000..e92128a951f --- /dev/null +++ b/test/integration/targets/include_import/run_once/include_me.yml @@ -0,0 +1,2 @@ +- set_fact: + lola: wiseman diff --git a/test/integration/targets/include_import/run_once/playbook.yml b/test/integration/targets/include_import/run_once/playbook.yml new file mode 100644 index 00000000000..cc1e265f61b --- /dev/null +++ b/test/integration/targets/include_import/run_once/playbook.yml @@ -0,0 +1,61 @@ +# This playbook exists to document the behavior of how run_once when +# applied to a dynamic include works +# +# As with other uses of keywords on dynamic includes, it only affects the include. +# In this case it causes the include to only be processed for ansible_play_hosts[0] +# which has the side effect of only running the tasks on ansible_play_hosts[0] +# and would only delegate facts of the include itself, not the tasks contained within + +- hosts: localhost + gather_facts: false + tasks: + - add_host: + name: "{{ item }}" + ansible_connection: local + groups: + - all + loop: + - localhost0 + - localhost1 + + - add_host: + name: "{{ item }}" + groups: + - testing + ansible_connection: local + loop: + - localhost2 + - localhost3 + +- hosts: all:!testing + gather_facts: false + vars: + lola: untouched + tasks: + - include_tasks: + file: include_me.yml + apply: + run_once: true + run_once: true + + - assert: + that: + - lola == 'wiseman' + +- hosts: testing + gather_facts: false + vars: + lola: untouched + tasks: + - include_tasks: include_me.yml + run_once: true + + - assert: + that: + - lola == 'wiseman' + when: inventory_hostname == ansible_play_hosts[0] + + - assert: + that: + - lola == 'untouched' + when: inventory_hostname != ansible_play_hosts[0] diff --git a/test/integration/targets/include_import/runme.sh b/test/integration/targets/include_import/runme.sh index 308a8af8094..e3497119ee9 100755 --- a/test/integration/targets/include_import/runme.sh +++ b/test/integration/targets/include_import/runme.sh @@ -83,3 +83,6 @@ test "$(grep -c '"item=foo"' test_include_dupe_loop.out)" = 3 ansible-playbook public_exposure/playbook.yml -i ../../inventory "$@" ansible-playbook public_exposure/no_bleeding.yml -i ../../inventory "$@" ansible-playbook public_exposure/no_overwrite_roles.yml -i ../../inventory "$@" + +# https://github.com/ansible/ansible/pull/48068 +ansible-playbook run_once/playbook.yml "$@"