A simple task, or so I thought: in a Jinja template keep track of the number of items in a loop. And then use that count afterwards.
Disclaimer: the number of items is not equal the number of times the loop runs, so I can’t use the loop variables.
Turns out that Jinja has other opinions, and variables inside a loop are all local. When a variable is changed inside the loop, the scope of the variable stays local, and once the loop ends the original value of the variable is restored. That’s even true for variables which are created outside the loop.
To demonstrate the problem, here is a simple Playbook, just a small template:
The Playbook is executed:
The template is setting a variable, running through a loop and increasing the variable:
One would expect that the variable starts with
1, the loop runs
5 times (the end value of
6 for the range is never reached), and will increase the counter to
6. Instead this happens:
Counter before loop: 1 Counter in loop (1): 2 Counter in loop (2): 2 Counter in loop (3): 2 Counter in loop (4): 2 Counter in loop (5): 2 Counter after loop: 1
Every run of the loop gets a “fresh” copy of the variable value, and the total is never increased beyond
Now one can argue that not too much work should be done in templates, but at some point the work has to be done. A counter is rarely pre-calculated. To solve this kind of problems, Jinja introduced Namespaces in version
2.10. By using a namespace, the variable in the loop is never localized, but instead the variable in the namespace is used. The same simple loop from above with a namespace:
Results in the following output:
Counter before loop: 1 Counter in loop (1): 2 Counter in loop (2): 3 Counter in loop (3): 4 Counter in loop (4): 5 Counter in loop (5): 6 Counter after loop: 6
Exactly what I’m looking for!