From 666188892ed0833e87803a3e80c58923e4cd6bca Mon Sep 17 00:00:00 2001 From: Sloane Hertel <19572925+s-hertel@users.noreply.github.com> Date: Thu, 30 Mar 2023 18:20:10 -0400 Subject: [PATCH] fix using templated values for include/import role FA (#80320) * fix using templated values for include/import role options 'public', 'allow_duplicates', and 'rolespec_validate' * pass templated values without changing the instance * Fix templating by setting always_post_validate to True and calling IncludeRole.post_validate() instead ci_complete * add changelog --- .../fix-templating-private-role-FA.yml | 2 ++ lib/ansible/playbook/helpers.py | 1 + lib/ansible/playbook/included_file.py | 1 + lib/ansible/playbook/role_include.py | 6 ++-- .../role_with_argspec/meta/argument_specs.yml | 7 +++++ .../roles/role_with_argspec/tasks/main.yml | 1 + .../targets/include_import/runme.sh | 5 ++++ .../tasks/test_templating_IncludeRole_FA.yml | 28 +++++++++++++++++++ 8 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 changelogs/fragments/fix-templating-private-role-FA.yml create mode 100644 test/integration/targets/include_import/roles/role_with_argspec/meta/argument_specs.yml create mode 100644 test/integration/targets/include_import/roles/role_with_argspec/tasks/main.yml create mode 100644 test/integration/targets/include_import/tasks/test_templating_IncludeRole_FA.yml diff --git a/changelogs/fragments/fix-templating-private-role-FA.yml b/changelogs/fragments/fix-templating-private-role-FA.yml new file mode 100644 index 00000000000..bef23f7873b --- /dev/null +++ b/changelogs/fragments/fix-templating-private-role-FA.yml @@ -0,0 +1,2 @@ +bugfixes: + - roles - Fix templating ``public``, ``allow_duplicates`` and ``rolespec_validate`` (https://github.com/ansible/ansible/issues/80304). diff --git a/lib/ansible/playbook/helpers.py b/lib/ansible/playbook/helpers.py index 489100e22ab..46fe46a1111 100644 --- a/lib/ansible/playbook/helpers.py +++ b/lib/ansible/playbook/helpers.py @@ -307,6 +307,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h # template the role name now, if needed all_vars = variable_manager.get_vars(play=play, task=ir) templar = Templar(loader=loader, variables=all_vars) + ir.post_validate(templar=templar) ir._role_name = templar.template(ir._role_name) # uses compiled list from object diff --git a/lib/ansible/playbook/included_file.py b/lib/ansible/playbook/included_file.py index 409eaec795a..b833077c951 100644 --- a/lib/ansible/playbook/included_file.py +++ b/lib/ansible/playbook/included_file.py @@ -187,6 +187,7 @@ class IncludedFile: role_name = templar.template(role_name) new_task = original_task.copy() + new_task.post_validate(templar=templar) new_task._role_name = role_name for from_arg in new_task.FROM_ARGS: if from_arg in include_args: diff --git a/lib/ansible/playbook/role_include.py b/lib/ansible/playbook/role_include.py index 4c56a4dc76a..155c123c7e0 100644 --- a/lib/ansible/playbook/role_include.py +++ b/lib/ansible/playbook/role_include.py @@ -51,9 +51,9 @@ class IncludeRole(TaskInclude): # ATTRIBUTES # private as this is a 'module options' vs a task property - allow_duplicates = NonInheritableFieldAttribute(isa='bool', default=True, private=True) - public = NonInheritableFieldAttribute(isa='bool', default=False, private=True) - rolespec_validate = NonInheritableFieldAttribute(isa='bool', default=True) + allow_duplicates = NonInheritableFieldAttribute(isa='bool', default=True, private=True, always_post_validate=True) + public = NonInheritableFieldAttribute(isa='bool', default=False, private=True, always_post_validate=True) + rolespec_validate = NonInheritableFieldAttribute(isa='bool', default=True, private=True, always_post_validate=True) def __init__(self, block=None, role=None, task_include=None): diff --git a/test/integration/targets/include_import/roles/role_with_argspec/meta/argument_specs.yml b/test/integration/targets/include_import/roles/role_with_argspec/meta/argument_specs.yml new file mode 100644 index 00000000000..e6d200c1655 --- /dev/null +++ b/test/integration/targets/include_import/roles/role_with_argspec/meta/argument_specs.yml @@ -0,0 +1,7 @@ +argument_specs: + main: + short_description: The main entry point for dup_allowed_role + options: + optional_int: + type: int + description: An integer value diff --git a/test/integration/targets/include_import/roles/role_with_argspec/tasks/main.yml b/test/integration/targets/include_import/roles/role_with_argspec/tasks/main.yml new file mode 100644 index 00000000000..23f52ef574d --- /dev/null +++ b/test/integration/targets/include_import/roles/role_with_argspec/tasks/main.yml @@ -0,0 +1 @@ +- debug: msg='Running role_with_argspec' diff --git a/test/integration/targets/include_import/runme.sh b/test/integration/targets/include_import/runme.sh index d384a12e14b..078f080b0db 100755 --- a/test/integration/targets/include_import/runme.sh +++ b/test/integration/targets/include_import/runme.sh @@ -121,6 +121,11 @@ ansible-playbook valid_include_keywords/playbook.yml "$@" ansible-playbook tasks/test_allow_single_role_dup.yml 2>&1 | tee test_allow_single_role_dup.out test "$(grep -c 'ok=3' test_allow_single_role_dup.out)" = 1 +# test templating public, allow_duplicates, and rolespec_validate +ansible-playbook tasks/test_templating_IncludeRole_FA.yml 2>&1 | tee IncludeRole_FA_template.out +test "$(grep -c 'ok=4' IncludeRole_FA_template.out)" = 1 +test "$(grep -c 'failed=0' IncludeRole_FA_template.out)" = 1 + # https://github.com/ansible/ansible/issues/66764 ANSIBLE_HOST_PATTERN_MISMATCH=error ansible-playbook empty_group_warning/playbook.yml diff --git a/test/integration/targets/include_import/tasks/test_templating_IncludeRole_FA.yml b/test/integration/targets/include_import/tasks/test_templating_IncludeRole_FA.yml new file mode 100644 index 00000000000..cb67a9bb150 --- /dev/null +++ b/test/integration/targets/include_import/tasks/test_templating_IncludeRole_FA.yml @@ -0,0 +1,28 @@ +--- +- name: test templating allow_duplicates, public, and rolespec_validate + hosts: localhost + gather_facts: false + tasks: + - name: prevent duplicate roles with a templated value + block: + - import_role: + name: dup_allowed_role + allow_duplicates: "{{ False | bool }}" + - import_role: + name: dup_allowed_role + allow_duplicates: "{{ False | bool }}" + + - name: prevent leaky vars with a templated value + include_role: + name: role1 + public: "{{ False | bool }}" + - assert: + that: + - where_am_i_defined is undefined + + - name: skip role argspec validation with a templated value + include_role: + name: role_with_argspec + rolespec_validate: "{{ False | bool }}" + vars: + optional_int: wrong_type