From c0ab3871fbea6e2cd3f2320757785833609474f4 Mon Sep 17 00:00:00 2001 From: Estelle Poulin Date: Thu, 5 Nov 2020 19:28:07 -0500 Subject: [PATCH] I FOUND THE BUG The reason that the "obvious" fix of taking away some of the elements of the hash doesn't work is because deep in the Ansible the `_allow_duplicates` flag has the wrong default and this logic only gets triggered sometimes. I was able to get it to trigger by mixing playbook roles and includes roles: - example - exmaple tasks: - include_role: name=example runs three times because of this bug. --- lib/ansible/playbook/role/__init__.py | 30 ++++++++++++++++++++------- lib/ansible/playbook/role_include.py | 2 +- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/ansible/playbook/role/__init__.py b/lib/ansible/playbook/role/__init__.py index d8ba12a5e50d3f..2f5059e61c880d 100644 --- a/lib/ansible/playbook/role/__init__.py +++ b/lib/ansible/playbook/role/__init__.py @@ -142,17 +142,31 @@ def load(role_include, play, parent_role=None, from_files=None, from_include=Fal # specified for a role as the key and the Role() object itself. # We use frozenset to make the dictionary hashable. - params = role_include.get_role_params() - if role_include.when is not None: - params['when'] = role_include.when - if role_include.tags is not None: - params['tags'] = role_include.tags - if from_files is not None: - params['from_files'] = from_files + # This grabs the vars from the dep_chain which if you're paranoid might + # warrant re-running the role but I wouldn't notice. + #params = role_include.get_role_params() + params = {} + #if role_include.when is not None: + # params['when'] = role_include.when + #if role_include.tags is not None: + # params['tags'] = role_include.tags + #if from_files is not None: + # params['from_files'] = from_files + # This is the one that people actually use. + # roles: + # - example + # - role: example + # vars: + # role_var: "blah" + # should be ran twice which enables patterns like + # roles: + # - {role: file_monitor, vars: {path: '/var/log/messages'}} + # - {role: file_monitor, vars: {path: '/var/log/secure'}} + # if role_include.vars: params['vars'] = role_include.vars - params['from_include'] = from_include + #params['from_include'] = from_include hashed_params = hash_params(params) if role_include.role in play.ROLE_CACHE: diff --git a/lib/ansible/playbook/role_include.py b/lib/ansible/playbook/role_include.py index 870dea80d6b32a..89c2ceecf4e477 100644 --- a/lib/ansible/playbook/role_include.py +++ b/lib/ansible/playbook/role_include.py @@ -49,7 +49,7 @@ class IncludeRole(TaskInclude): # ATTRIBUTES # private as this is a 'module options' vs a task property - _allow_duplicates = FieldAttribute(isa='bool', default=True, private=True) + _allow_duplicates = FieldAttribute(isa='bool', default=False, private=True) _public = FieldAttribute(isa='bool', default=False, private=True) def __init__(self, block=None, role=None, task_include=None):