diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index f7795af059..4533bf4efd 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -46,6 +46,24 @@ except ImportError: __all__ = ['TaskExecutor'] +def remove_omit(task_args, omit_token): + ''' + Remove args with a value equal to the ``omit_token`` recursively + to align with now having suboptions in the argument_spec + ''' + new_args = {} + + for i in iteritems(task_args): + if i[1] == omit_token: + continue + elif isinstance(i[1], dict): + new_args[i[0]] = remove_omit(i[1], omit_token) + else: + new_args[i[0]] = i[1] + + return new_args + + class TaskExecutor: ''' @@ -498,7 +516,7 @@ class TaskExecutor: # And filter out any fields which were set to default(omit), and got the omit token value omit_token = variables.get('omit') if omit_token is not None: - self._task.args = dict((i[0], i[1]) for i in iteritems(self._task.args) if i[1] != omit_token) + self._task.args = remove_omit(self._task.args, omit_token) # Read some values from the task, so that we can modify them if need be if self._task.until: diff --git a/test/units/executor/test_task_executor.py b/test/units/executor/test_task_executor.py index 3b75636b82..7d1f33e9a4 100644 --- a/test/units/executor/test_task_executor.py +++ b/test/units/executor/test_task_executor.py @@ -22,7 +22,7 @@ __metaclass__ = type from ansible.compat.tests import unittest from ansible.compat.tests.mock import patch, MagicMock from ansible.errors import AnsibleError, AnsibleParserError -from ansible.executor.task_executor import TaskExecutor +from ansible.executor.task_executor import TaskExecutor, remove_omit from ansible.playbook.play_context import PlayContext from ansible.plugins.loader import action_loader, lookup_loader from ansible.parsing.yaml.objects import AnsibleUnicode @@ -484,3 +484,38 @@ class TestTaskExecutor(unittest.TestCase): mock_templar = MagicMock() res = te._poll_async_result(result=dict(ansible_job_id=1), templar=mock_templar) self.assertEqual(res, dict(finished=1)) + + def test_recursive_remove_omit(self): + omit_token = 'POPCORN' + + data = { + 'foo': 'bar', + 'baz': 1, + 'qux': ['one', 'two', 'three'], + 'subdict': { + 'remove': 'POPCORN', + 'keep': 'not_popcorn', + 'subsubdict': { + 'remove': 'POPCORN', + 'keep': 'not_popcorn', + }, + 'a_list': ['POPCORN'], + }, + 'a_list': ['POPCORN'], + } + + expected = { + 'foo': 'bar', + 'baz': 1, + 'qux': ['one', 'two', 'three'], + 'subdict': { + 'keep': 'not_popcorn', + 'subsubdict': { + 'keep': 'not_popcorn', + }, + 'a_list': ['POPCORN'], + }, + 'a_list': ['POPCORN'], + } + + self.assertEqual(remove_omit(data, omit_token), expected)