Backport #38827 for 2.5 - Allow inheriting attrs from static parents (#38847)

* Skip self._parent on dynamic, defer to grandparent for attr lookup (#38827)

* Skip self._parent on dynamic, defer to grandparent for attr lookup

* Revert _inheritable

* Add tests for include inheritance from static blocks

Fixes #38037 #36194

(cherry picked from commit 354aa8d602)

* Add changelog for #38827
pull/39089/head
Matt Martz 7 years ago committed by GitHub
parent 017f9a4876
commit 0bbb67383b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,2 @@
bugfixes:
- dynamic includes - Allow inheriting attributes from static parents (https://github.com/ansible/ansible/pull/38827)

@ -171,8 +171,6 @@ class Base(with_metaclass(BaseMeta, object)):
'su', 'su_user', 'su_pass', 'su_exe', 'su_flags', 'su', 'su_user', 'su_pass', 'su_exe', 'su_flags',
] ]
_inheritable = True
def __init__(self): def __init__(self):
# initialize the data loader and variable manager, which will be provided # initialize the data loader and variable manager, which will be provided

@ -299,13 +299,20 @@ class Block(Base, Become, Conditional, Taggable):
prepend = self._valid_attrs[attr].prepend prepend = self._valid_attrs[attr].prepend
try: try:
value = self._attributes[attr] value = self._attributes[attr]
if self._parent and (value is None or extend): # If parent is static, we can grab attrs from the parent
# otherwise, defer to the grandparent
if getattr(self._parent, 'statically_loaded', True):
_parent = self._parent
else:
_parent = self._parent._parent
if _parent and (value is None or extend):
try: try:
if getattr(self._parent, 'statically_loaded', True): if getattr(_parent, 'statically_loaded', True):
if hasattr(self._parent, '_get_parent_attribute'): if hasattr(_parent, '_get_parent_attribute'):
parent_value = self._parent._get_parent_attribute(attr) parent_value = _parent._get_parent_attribute(attr)
else: else:
parent_value = self._parent._attributes.get(attr, None) parent_value = _parent._attributes.get(attr, None)
if extend: if extend:
value = self._extend_value(value, parent_value, prepend) value = self._extend_value(value, parent_value, prepend)
else: else:

@ -48,8 +48,6 @@ class IncludeRole(TaskInclude):
OTHER_ARGS = ('private', 'allow_duplicates') # assigned to matching property OTHER_ARGS = ('private', 'allow_duplicates') # assigned to matching property
VALID_ARGS = tuple(frozenset(BASE + FROM_ARGS + OTHER_ARGS)) # all valid args VALID_ARGS = tuple(frozenset(BASE + FROM_ARGS + OTHER_ARGS)) # all valid args
_inheritable = False
# ================================================================================= # =================================================================================
# ATTRIBUTES # ATTRIBUTES

@ -423,13 +423,20 @@ class Task(Base, Conditional, Taggable, Become):
prepend = self._valid_attrs[attr].prepend prepend = self._valid_attrs[attr].prepend
try: try:
value = self._attributes[attr] value = self._attributes[attr]
if self._parent and (value is None or extend): # If parent is static, we can grab attrs from the parent
if getattr(self._parent, 'statically_loaded', True): # otherwise, defer to the grandparent
if getattr(self._parent, 'statically_loaded', True):
_parent = self._parent
else:
_parent = self._parent._parent
if _parent and (value is None or extend):
if getattr(_parent, 'statically_loaded', True):
# vars are always inheritable, other attributes might not be for the partent but still should be for other ancestors # vars are always inheritable, other attributes might not be for the partent but still should be for other ancestors
if attr != 'vars' and getattr(self._parent, '_inheritable', True) and hasattr(self._parent, '_get_parent_attribute'): if attr != 'vars' and hasattr(_parent, '_get_parent_attribute'):
parent_value = self._parent._get_parent_attribute(attr) parent_value = _parent._get_parent_attribute(attr)
else: else:
parent_value = self._parent._attributes.get(attr, None) parent_value = _parent._attributes.get(attr, None)
if extend: if extend:
value = self._extend_value(value, parent_value, prepend) value = self._extend_value(value, parent_value, prepend)

@ -50,8 +50,6 @@ class TaskInclude(Task):
@staticmethod @staticmethod
def load(data, block=None, role=None, task_include=None, variable_manager=None, loader=None): def load(data, block=None, role=None, task_include=None, variable_manager=None, loader=None):
t = TaskInclude(block=block, role=role, task_include=task_include) t = TaskInclude(block=block, role=role, task_include=task_include)
if t.action == 'include_task':
t._inheritable = False
return t.load_data(data, variable_manager=variable_manager, loader=loader) return t.load_data(data, variable_manager=variable_manager, loader=loader)
def copy(self, exclude_parent=False, exclude_tasks=False): def copy(self, exclude_parent=False, exclude_tasks=False):

@ -0,0 +1,2 @@
- command: "true"
register: block_include_result

@ -0,0 +1,2 @@
- command: "true"
register: import_include_include_result

@ -0,0 +1 @@
- include_tasks: import_include_include_tasks.yml

@ -41,3 +41,7 @@ ANSIBLE_STRATEGY='linear' ansible-playbook test_recursion.yml -i ../../inventory
# https://github.com/ansible/ansible/issues/34782 # https://github.com/ansible/ansible/issues/34782
ANSIBLE_STRATEGY='linear' ansible-playbook nested.yml -i ../../inventory "$@" --skip-tags never ANSIBLE_STRATEGY='linear' ansible-playbook nested.yml -i ../../inventory "$@" --skip-tags never
ANSIBLE_STRATEGY='free' ansible-playbook nested.yml -i ../../inventory "$@" --skip-tags never ANSIBLE_STRATEGY='free' ansible-playbook nested.yml -i ../../inventory "$@" --skip-tags never
# Inlcuded tasks should inherit attrs from non-dynamic blocks in parent chain
# https://github.com/ansible/ansible/pull/38827
ANSIBLE_STRATEGY='linear' ansible-playbook test_grandparent_inheritance.yml -i ../../inventory "$@"

@ -0,0 +1,29 @@
---
- hosts: testhost
gather_facts: false
tasks:
- debug:
var: inventory_hostname
- name: Test included tasks inherit from block
check_mode: true
block:
- include_tasks: grandchild/block_include_tasks.yml
- debug:
var: block_include_result
- assert:
that:
- block_include_result is skipped
- name: Test included tasks inherit deeply from import
import_tasks: grandchild/import.yml
check_mode: true
- debug:
var: import_include_include_result
- assert:
that:
- import_include_include_result is skipped
Loading…
Cancel
Save