From 7d1eb88ecf05909a79eee2b019f4f5e55f2da029 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Thu, 8 Feb 2018 17:28:07 -0600 Subject: [PATCH] Address memory ballooning caused by task caching changes (#35921) * Exclude parent when copying included task to avoid memory issues. Fixes #35796 * Simplify implicit block squashing to pre-group, instead of post re-parenting --- lib/ansible/playbook/helpers.py | 49 ++++++++++++++---------- lib/ansible/plugins/strategy/__init__.py | 3 +- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/lib/ansible/playbook/helpers.py b/lib/ansible/playbook/helpers.py index ac4df23d6e..248a840bb0 100644 --- a/lib/ansible/playbook/helpers.py +++ b/lib/ansible/playbook/helpers.py @@ -48,29 +48,38 @@ def load_list_of_blocks(ds, play, parent_block=None, role=None, task_include=Non block_list = [] if ds: - for block_ds in ds: - b = Block.load( - block_ds, - play=play, - parent_block=parent_block, - role=role, - task_include=task_include, - use_handlers=use_handlers, - variable_manager=variable_manager, - loader=loader, - ) + count = iter(range(len(ds))) + for i in count: + block_ds = ds[i] # Implicit blocks are created by bare tasks listed in a play without # an explicit block statement. If we have two implicit blocks in a row, # squash them down to a single block to save processing time later. - if b._implicit and len(block_list) > 0 and block_list[-1]._implicit: - for t in b.block: - if isinstance(t._parent, (TaskInclude, IncludeRole)): - t._parent._parent = block_list[-1] - else: - t._parent = block_list[-1] - block_list[-1].block.extend(b.block) - else: - block_list.append(b) + implicit_blocks = [] + while block_ds is not None and not Block.is_block(block_ds): + implicit_blocks.append(block_ds) + i += 1 + # Advance the iterator, so we don't repeat + next(count, None) + try: + block_ds = ds[i] + except IndexError: + block_ds = None + + # Loop both implicit blocks and block_ds as block_ds is the next in the list + for b in (implicit_blocks, block_ds): + if b: + block_list.append( + Block.load( + b, + play=play, + parent_block=parent_block, + role=role, + task_include=task_include, + use_handlers=use_handlers, + variable_manager=variable_manager, + loader=loader, + ) + ) return block_list diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index d57bdcad69..4c081d1c41 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -763,7 +763,8 @@ class StrategyBase: elif not isinstance(data, list): raise AnsibleError("included task files must contain a list of tasks") - ti_copy = included_file._task.copy() + ti_copy = included_file._task.copy(exclude_parent=True) + ti_copy._parent = included_file._task._parent temp_vars = ti_copy.vars.copy() temp_vars.update(included_file._args) # pop tags out of the include args, if they were specified there, and assign