summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cammarata <jimi@sngx.net>2016-08-11 12:23:20 -0500
committerJames Cammarata <jimi@sngx.net>2016-08-11 12:23:20 -0500
commit9d5d815b269a56e25cc069aa0ebff56777c37d12 (patch)
treea3144285bd1691a62cc864a3dd3441b0f5b7affd
parent947877dcce32ed544f1004a167196eb654b5d745 (diff)
downloadansible-fixing_includes.tar.gz
Several fixes for includesfixing_includes
* when including statically, make sure that all parents were also included statically (issue #16990) * properly resolve nested static include paths * print a message when a file is statically included Fixes #16990
-rw-r--r--lib/ansible/playbook/block.py16
-rw-r--r--lib/ansible/playbook/helpers.py68
-rw-r--r--lib/ansible/playbook/task.py5
-rw-r--r--lib/ansible/playbook/task_include.py9
-rw-r--r--lib/ansible/plugins/strategy/__init__.py2
5 files changed, 69 insertions, 31 deletions
diff --git a/lib/ansible/playbook/block.py b/lib/ansible/playbook/block.py
index ec6298a2c1..14519d8162 100644
--- a/lib/ansible/playbook/block.py
+++ b/lib/ansible/playbook/block.py
@@ -374,3 +374,19 @@ class Block(Base, Become, Conditional, Taggable):
return self._parent.get_include_params()
else:
return dict()
+
+ def all_parents_static(self):
+ '''
+ Determine if all of the parents of this block were statically loaded
+ or not. Since Task/TaskInclude objects may be in the chain, they simply
+ call their parents all_parents_static() method. Only Block objects in
+ the chain check the statically_loaded value of the parent.
+ '''
+ from ansible.playbook.task_include import TaskInclude
+ if self._parent:
+ if isinstance(self._parent, TaskInclude) and not self._parent.statically_loaded:
+ return False
+ return self._parent.all_parents_static()
+
+ return True
+
diff --git a/lib/ansible/playbook/helpers.py b/lib/ansible/playbook/helpers.py
index c19db72894..06043b92d2 100644
--- a/lib/ansible/playbook/helpers.py
+++ b/lib/ansible/playbook/helpers.py
@@ -129,41 +129,44 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
else:
is_static = C.DEFAULT_TASK_INCLUDES_STATIC or \
(use_handlers and C.DEFAULT_HANDLER_INCLUDES_STATIC) or \
- (not templar._contains_vars(t.args['_raw_params']) and not t.loop)
+ (not templar._contains_vars(t.args['_raw_params']) and t.all_parents_static() and not t.loop)
if is_static:
if t.loop is not None:
raise AnsibleParserError("You cannot use 'static' on an include with a loop", obj=task_ds)
- # FIXME: all of this code is very similar (if not identical) to that in
- # plugins/strategy/__init__.py, and should be unified to avoid
- # patches only being applied to one or the other location
- if task_include:
- # handle relative includes by walking up the list of parent include
- # tasks and checking the relative result to see if it exists
- parent_include = task_include
- cumulative_path = None
- while parent_include is not None:
- if not isinstance(parent_include, TaskInclude):
- parent_include = parent_include._parent
- continue
- parent_include_dir = templar.template(os.path.dirname(parent_include.args.get('_raw_params')))
- if cumulative_path is None:
- cumulative_path = parent_include_dir
- elif not os.path.isabs(cumulative_path):
- cumulative_path = os.path.join(parent_include_dir, cumulative_path)
- include_target = templar.template(t.args['_raw_params'])
- if t._role:
- new_basedir = os.path.join(t._role._role_path, 'tasks', cumulative_path)
- include_file = loader.path_dwim_relative(new_basedir, 'tasks', include_target)
- else:
- include_file = loader.path_dwim_relative(loader.get_basedir(), cumulative_path, include_target)
+ # we set a flag to indicate this include was static
+ t.statically_loaded = True
+
+ # handle relative includes by walking up the list of parent include
+ # tasks and checking the relative result to see if it exists
+ parent_include = block
+ cumulative_path = None
+
+ found = False
+ while parent_include is not None:
+ if not isinstance(parent_include, TaskInclude):
+ parent_include = parent_include._parent
+ continue
+ parent_include_dir = templar.template(os.path.dirname(parent_include.args.get('_raw_params')))
+ if cumulative_path is None:
+ cumulative_path = parent_include_dir
+ elif not os.path.isabs(cumulative_path):
+ cumulative_path = os.path.join(parent_include_dir, cumulative_path)
+ include_target = templar.template(t.args['_raw_params'])
+ if t._role:
+ new_basedir = os.path.join(t._role._role_path, 'tasks', cumulative_path)
+ include_file = loader.path_dwim_relative(new_basedir, 'tasks', include_target)
+ else:
+ include_file = loader.path_dwim_relative(loader.get_basedir(), cumulative_path, include_target)
- if os.path.exists(include_file):
- break
- else:
- parent_include = parent_include._parent
- else:
+ if os.path.exists(include_file):
+ found = True
+ break
+ else:
+ parent_include = parent_include._parent
+
+ if not found:
try:
include_target = templar.template(t.args['_raw_params'])
except AnsibleUndefinedVariable as e:
@@ -189,6 +192,12 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
return []
elif not isinstance(data, list):
raise AnsibleError("included task files must contain a list of tasks", obj=data)
+
+ # since we can't send callbacks here, we display a message directly in
+ # the same fashion used by the on_include callback. We also do it here,
+ # because the recursive nature of helper methods means we may be loading
+ # nested includes, and we want the include order printed correctly
+ display.display("statically included: %s" % include_file, color=C.COLOR_SKIP)
except AnsibleFileNotFound as e:
if t.static or \
C.DEFAULT_TASK_INCLUDES_STATIC or \
@@ -240,7 +249,6 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
b.tags = list(set(b.tags).union(tags))
# END FIXME
- # FIXME: send callback here somehow...
# FIXME: handlers shouldn't need this special handling, but do
# right now because they don't iterate blocks correctly
if use_handlers:
diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py
index 571bd223a8..807f296502 100644
--- a/lib/ansible/playbook/task.py
+++ b/lib/ansible/playbook/task.py
@@ -463,3 +463,8 @@ class Task(Base, Conditional, Taggable, Become):
return path_stack
+ def all_parents_static(self):
+ if self._parent:
+ return self._parent.all_parents_static()
+ return True
+
diff --git a/lib/ansible/playbook/task_include.py b/lib/ansible/playbook/task_include.py
index 0c6016c559..bfb7e89a85 100644
--- a/lib/ansible/playbook/task_include.py
+++ b/lib/ansible/playbook/task_include.py
@@ -43,11 +43,20 @@ class TaskInclude(Task):
_static = FieldAttribute(isa='bool', default=None)
+ def __init__(self, block=None, role=None, task_include=None):
+ super(TaskInclude, self).__init__(block=block, role=role, task_include=task_include)
+ self.statically_loaded = False
+
@staticmethod
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)
return t.load_data(data, variable_manager=variable_manager, loader=loader)
+ def copy(self, exclude_parent=False, exclude_tasks=False):
+ new_me = super(TaskInclude, self).copy(exclude_parent=exclude_parent, exclude_tasks=exclude_tasks)
+ new_me.statically_loaded = self.statically_loaded
+ return new_me
+
def get_vars(self):
'''
We override the parent Task() classes get_vars here because
diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py
index 49088633bb..6b3c0ad26c 100644
--- a/lib/ansible/plugins/strategy/__init__.py
+++ b/lib/ansible/plugins/strategy/__init__.py
@@ -578,7 +578,7 @@ class StrategyBase:
data,
play=iterator._play,
parent_block=None,
- task_include=None,
+ task_include=included_file._task,
role=included_file._task._role,
use_handlers=is_handler,
loader=self._loader,