mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Add info about loop based on jinja2 loop var (#42134)
* Add info about loop based on jinja2 loop var * ansible_loop * Update test count * Add extended loop_control that defines whether ansible_loop should be added * Extended needs to be defaulted * Revert "Update test count" This reverts commit f1e93ee469825f4cdcd90fb28667d29aa088275c. * Add docs about loop_control.extended * Add revindex and revindex0 * Document ansible_loop in special vars * Add changelog fragment * Add tests, change items to allitems so that dot notation works, fix logic error with previtem
This commit is contained in:
parent
597c258e0e
commit
9007dbec2f
6 changed files with 117 additions and 0 deletions
2
changelogs/fragments/loop-info.yaml
Normal file
2
changelogs/fragments/loop-info.yaml
Normal file
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- loop_control - Add new ``extended`` option to return extended loop information (https://github.com/ansible/ansible/pull/42134)
|
|
@ -25,6 +25,9 @@ ansible_inventory_sources
|
|||
ansible_limit
|
||||
Contents of the ``--limit`` CLI option for the current execution of Ansible
|
||||
|
||||
ansible_loop
|
||||
A dictionary/map containing extended loop information when enabled via ``loop_control.extended``
|
||||
|
||||
ansible_play_batch
|
||||
List of active hosts in the current play run limited by the serial, aka 'batch'. Failed/Unreachable hosts are not considered 'active'.
|
||||
|
||||
|
|
|
@ -330,6 +330,30 @@ If you need to keep track of where you are in a loop, you can use the ``index_va
|
|||
loop_control:
|
||||
index_var: my_idx
|
||||
|
||||
.. versionadded:: 2.8
|
||||
|
||||
As of Ansible 2.8 you can get extended loop information using the ``extended`` option to loop control. This option will expose the following information.
|
||||
|
||||
========================== ===========
|
||||
Variable Description
|
||||
-------------------------- -----------
|
||||
``ansible_loop.allitems`` The list of all items in the loop
|
||||
``ansible_loop.index`` The current iteration of the loop. (1 indexed)
|
||||
``ansible_loop.index0`` The current iteration of the loop. (0 indexed)
|
||||
``ansible_loop.revindex`` The number of iterations from the end of the loop (1 indexed)
|
||||
``ansible_loop.revindex0`` The number of iterations from the end of the loop (0 indexed)
|
||||
``ansible_loop.first`` ``True`` if first iteration
|
||||
``ansible_loop.last`` ``True`` if last iteration
|
||||
``ansible_loop.length`` The number of items in the loop
|
||||
``ansible_loop.previtem`` The item from the previous iteration of the loop. Undefined during the first iteration.
|
||||
``ansible_loop.nextitem`` The item from the following iteration of the loop. Undefined during the last iteration.
|
||||
========================== ===========
|
||||
|
||||
::
|
||||
|
||||
loop_control:
|
||||
extended: yes
|
||||
|
||||
Migrating from with_X to loop
|
||||
`````````````````````````````
|
||||
|
||||
|
|
|
@ -287,6 +287,7 @@ class TaskExecutor:
|
|||
index_var = None
|
||||
label = None
|
||||
loop_pause = 0
|
||||
extended = False
|
||||
templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars)
|
||||
|
||||
# FIXME: move this to the object itself to allow post_validate to take care of templating (loop_control.post_validate)
|
||||
|
@ -294,6 +295,7 @@ class TaskExecutor:
|
|||
loop_var = templar.template(self._task.loop_control.loop_var)
|
||||
index_var = templar.template(self._task.loop_control.index_var)
|
||||
loop_pause = templar.template(self._task.loop_control.pause)
|
||||
extended = templar.template(self._task.loop_control.extended)
|
||||
|
||||
# This may be 'None',so it is tempalted below after we ensure a value and an item is assigned
|
||||
label = self._task.loop_control.label
|
||||
|
@ -313,11 +315,30 @@ class TaskExecutor:
|
|||
items = self._squash_items(items, loop_var, task_vars)
|
||||
|
||||
no_log = False
|
||||
items_len = len(items)
|
||||
for item_index, item in enumerate(items):
|
||||
task_vars[loop_var] = item
|
||||
if index_var:
|
||||
task_vars[index_var] = item_index
|
||||
|
||||
if extended:
|
||||
task_vars['ansible_loop'] = {
|
||||
'allitems': items,
|
||||
'index': item_index + 1,
|
||||
'index0': item_index,
|
||||
'first': item_index == 0,
|
||||
'last': item_index + 1 == items_len,
|
||||
'length': items_len,
|
||||
'revindex': items_len - item_index,
|
||||
'revindex0': items_len - item_index - 1,
|
||||
}
|
||||
try:
|
||||
task_vars['ansible_loop']['nextitem'] = items[item_index + 1]
|
||||
except IndexError:
|
||||
pass
|
||||
if item_index - 1 >= 0:
|
||||
task_vars['ansible_loop']['previtem'] = items[item_index - 1]
|
||||
|
||||
# Update template vars to reflect current loop iteration
|
||||
templar.set_available_variables(task_vars)
|
||||
|
||||
|
@ -355,6 +376,9 @@ class TaskExecutor:
|
|||
res[loop_var] = item
|
||||
if index_var:
|
||||
res[index_var] = item_index
|
||||
if extended:
|
||||
res['ansible_loop'] = task_vars['ansible_loop']
|
||||
|
||||
res['_ansible_item_result'] = True
|
||||
res['_ansible_ignore_errors'] = task_fields.get('ignore_errors')
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ class LoopControl(FieldAttributeBase):
|
|||
_index_var = FieldAttribute(isa='str')
|
||||
_label = FieldAttribute(isa='str')
|
||||
_pause = FieldAttribute(isa='int', default=0)
|
||||
_extended = FieldAttribute(isa='bool')
|
||||
|
||||
def __init__(self):
|
||||
super(LoopControl, self).__init__()
|
||||
|
|
|
@ -268,3 +268,66 @@
|
|||
things:
|
||||
- !unsafe foo
|
||||
- !unsafe bar
|
||||
|
||||
- name: extended loop info
|
||||
assert:
|
||||
that:
|
||||
- ansible_loop.nextitem == 'orange'
|
||||
- ansible_loop.index == 1
|
||||
- ansible_loop.index0 == 0
|
||||
- ansible_loop.first
|
||||
- not ansible_loop.last
|
||||
- ansible_loop.previtem is undefined
|
||||
- ansible_loop.allitems == ['apple', 'orange', 'banana']
|
||||
- ansible_loop.revindex == 3
|
||||
- ansible_loop.revindex0 == 2
|
||||
- ansible_loop.length == 3
|
||||
loop:
|
||||
- apple
|
||||
- orange
|
||||
- banana
|
||||
loop_control:
|
||||
extended: true
|
||||
when: item == 'apple'
|
||||
|
||||
- name: extended loop info 2
|
||||
assert:
|
||||
that:
|
||||
- ansible_loop.nextitem == 'banana'
|
||||
- ansible_loop.index == 2
|
||||
- ansible_loop.index0 == 1
|
||||
- not ansible_loop.first
|
||||
- not ansible_loop.last
|
||||
- ansible_loop.previtem == 'apple'
|
||||
- ansible_loop.allitems == ['apple', 'orange', 'banana']
|
||||
- ansible_loop.revindex == 2
|
||||
- ansible_loop.revindex0 == 1
|
||||
- ansible_loop.length == 3
|
||||
loop:
|
||||
- apple
|
||||
- orange
|
||||
- banana
|
||||
loop_control:
|
||||
extended: true
|
||||
when: item == 'orange'
|
||||
|
||||
- name: extended loop info 3
|
||||
assert:
|
||||
that:
|
||||
- ansible_loop.nextitem is undefined
|
||||
- ansible_loop.index == 3
|
||||
- ansible_loop.index0 == 2
|
||||
- not ansible_loop.first
|
||||
- ansible_loop.last
|
||||
- ansible_loop.previtem == 'orange'
|
||||
- ansible_loop.allitems == ['apple', 'orange', 'banana']
|
||||
- ansible_loop.revindex == 1
|
||||
- ansible_loop.revindex0 == 0
|
||||
- ansible_loop.length == 3
|
||||
loop:
|
||||
- apple
|
||||
- orange
|
||||
- banana
|
||||
loop_control:
|
||||
extended: true
|
||||
when: item == 'banana'
|
||||
|
|
Loading…
Reference in a new issue