summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToshio Kuratomi <toshio@fedoraproject.org>2016-01-27 20:17:52 -0800
committerToshio Kuratomi <toshio@fedoraproject.org>2016-01-27 21:55:00 -0800
commit0e410bbc8a6156d696edbebc5f07a23f454dd49c (patch)
treead87f6b5e7119662150f54a3f5492978baa5b712
parentfad6eb18448736ad1308f622be8e138fcf259288 (diff)
downloadansible-safer-squashing.tar.gz
Squashing was occuring even though pkgs didn't have a template that would be affected by squashsafer-squashing
This broke other uses of looping (looping for delegate_to in the reported bug) Fixes #13980
-rw-r--r--lib/ansible/executor/task_executor.py33
-rw-r--r--test/units/executor/test_task_executor.py27
2 files changed, 49 insertions, 11 deletions
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
index 1417bc9d2c..6350cc2b0e 100644
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -269,28 +269,39 @@ class TaskExecutor:
if all(isinstance(o, string_types) for o in items):
final_items = []
name = self._task.args.pop('name', None) or self._task.args.pop('pkg', None)
- # The user is doing an upgrade or some other operation
- # that doesn't take name or pkg.
- if name:
+
+ # This gets the information to check whether the name field
+ # contains a template that we can squash for
+ template_no_item = template_with_item = None
+ if templar._contains_vars(name):
+ variables['item'] = '\0$'
+ template_no_item = templar.template(name, variables, cache=False)
+ variables['item'] = '\0@'
+ template_with_item = templar.template(name, variables, cache=False)
+ del variables['item']
+
+ # Check if the user is doing some operation that doesn't take
+ # name/pkg or the name/pkg field doesn't have any variables
+ # and thus the items can't be squashed
+ if name and (template_no_item != template_with_item):
for item in items:
variables['item'] = item
if self._task.evaluate_conditional(templar, variables):
- if templar._contains_vars(name):
- new_item = templar.template(name, cache=False)
- final_items.append(new_item)
- else:
- final_items.append(item)
+ new_item = templar.template(name, cache=False)
+ final_items.append(new_item)
self._task.args['name'] = final_items
+ # Wrap this in a list so that the calling function loop
+ # executes exactly once
return [final_items]
+ else:
+ # Restore the name parameter
+ self._task.args['name'] = name
#elif:
# Right now we only optimize single entries. In the future we
# could optimize more types:
# * lists can be squashed together
# * dicts could squash entries that match in all cases except the
# name or pkg field.
- # Note: we really should be checking that the name or pkg field
- # contains a template that expands with our with_items values.
- # If it doesn't then we may break things
return items
def _execute(self, variables=None):
diff --git a/test/units/executor/test_task_executor.py b/test/units/executor/test_task_executor.py
index 0c868fef4b..7135a39ae2 100644
--- a/test/units/executor/test_task_executor.py
+++ b/test/units/executor/test_task_executor.py
@@ -198,21 +198,47 @@ class TestTaskExecutor(unittest.TestCase):
shared_loader_obj = mock_shared_loader,
)
+ #
+ # No replacement
+ #
+ mock_task.action = 'yum'
+ new_items = te._squash_items(items=items, variables=job_vars)
+ self.assertEqual(new_items, ['a', 'b', 'c'])
+
mock_task.action = 'foo'
+ mock_task.args={'name': '{{item}}'}
+ new_items = te._squash_items(items=items, variables=job_vars)
+ self.assertEqual(new_items, ['a', 'b', 'c'])
+
+ mock_task.action = 'yum'
+ mock_task.args={'name': 'static'}
+ new_items = te._squash_items(items=items, variables=job_vars)
+ self.assertEqual(new_items, ['a', 'b', 'c'])
+
+ mock_task.action = 'yum'
+ mock_task.args={'name': '{{pkg_mgr}}'}
new_items = te._squash_items(items=items, variables=job_vars)
self.assertEqual(new_items, ['a', 'b', 'c'])
+ #
+ # Replaces
+ #
mock_task.action = 'yum'
+ mock_task.args={'name': '{{item}}'}
new_items = te._squash_items(items=items, variables=job_vars)
self.assertEqual(new_items, [['a','c']])
mock_task.action = '{{pkg_mgr}}'
+ mock_task.args={'name': '{{item}}'}
new_items = te._squash_items(items=items, variables=job_vars)
self.assertEqual(new_items, [['a', 'c']])
+ #
# Smoketests -- these won't optimize but make sure that they don't
# traceback either
+ #
mock_task.action = '{{unknown}}'
+ mock_task.args={'name': '{{item}}'}
new_items = te._squash_items(items=items, variables=job_vars)
self.assertEqual(new_items, ['a', 'b', 'c'])
@@ -220,6 +246,7 @@ class TestTaskExecutor(unittest.TestCase):
dict(name='b', state='present'),
dict(name='c', state='present')]
mock_task.action = 'yum'
+ mock_task.args={'name': '{{item}}'}
new_items = te._squash_items(items=items, variables=job_vars)
self.assertEqual(new_items, items)