Templating changes
Note that Ansible 12 and stable-2.19 are coming soon. We’ve decided to pin this post ahead of the actual releases so folks have a heads up. However the versions mentioned below are not actually available just yet.
Ansible 12 is built on the ansible-core
stable-2.19 release, which includes an overhaul of the templating system. As the Porting Guide mentions, the overhaul of the ansible-core
templating system now detects problematic behaviors that were not detected in previous versions.
Another way to think about that statement: In previous releases, you could have broken tests or playbooks that Ansible did not tell you about. As of version 12, Ansible will tell you about those broken tests or playbooks.
Of course when something is broken it needs to be fixed. And the purpose of this post is to help you find answers quickly and resolve issues with your playbooks, modules, collections, and roles.
Note that this document is not intended to be comprehensive. Think of this document as more of a quick start. You should always refer to the Porting Guide as the official source of truth and definitive guide. We do not plan to add more examples or additional detail into this post.
Detection of broken conditionals
Ansible 12 now detects conditional statements that were broken but previously ignored. This change can help identify logic errors that might have been causing silent issues in playbooks. The Porting Guide refers to these changes in the broken conditionals section.
The templating system now requires conditionals to evaluate to actual boolean values rather than relying on Python’s “truthy” evaluation. This means that ansible-core 2.19 and Ansible 12 detects non-boolean conditionals during expression evaluation and reports errors, for example:
# Before (silently broken)
- assert:
that: inventory_hostname # Always truthy
In this example, inventory_hostname
is an Ansible magic variable that contains the name of the current host from the inventory. For example it could be test-server1
which evaluates to a truthy value in a boolean context because it is not an empty string. This means the assertion is likely to always evaluate to True regardless of what the hostname might be.
With the change to evaluate conditionals to boolean values, you could update tests to be more meaningful as in the following examples:
# Test if the hostname is defined and not empty
- assert:
that: inventory_hostname | length > 0
# Test if the hostname matches the expected value
- assert:
that: inventory_hostname == "test-server1"
In this way, Ansible 12 now helps you catch conditionals that don’t actually test what you intended them to test and prevents tests from silently passing when they should fail.
Note that ansible-core will report errors with this message: Conditionals must have a boolean result.
You can temporarily change the error to a deprecation warning with the ALLOW_BROKEN_CONDITIONALS
configuration option.
See the Porting Guide for more information and complete details about broken conditionals.
Replacing embedded templates
One of the changes from the templating system overhaul is to get rid of the potentially dangerous ability to embed templates. The Porting Guide refers to this in the multi-pass templating section.
Let’s look at a real-world example. In a test for the community.mysql collection, the following change was required:
Before
- name: assert that databases does not exist
assert:
that:
- "'{{ db1_name }}' not in mysql_result.stdout"
- "'{{ db2_name }}' not in mysql_result.stdout"
- "'{{ db3_name }}' not in mysql_result.stdout"
After
- name: assert that databases does not exist
assert:
that:
- db1_name not in mysql_result.stdout
- db2_name not in mysql_result.stdout
- db3_name not in mysql_result.stdout
Explanation
The original code used template delimiters {{ }}
within conditional expressions. This is an example of multi-pass templating because Ansible’s templating engine has to process those template delimiters multiple times.
In the first pass, Ansible “sees” this as a string that contains template syntax. Ansible recognizes that {{ db1_name }}
needs to be substituted with an actual value; for example, testdb1
.
When that template substitution happens, the string becomes "'testdb1' not in mysql_result.stdout"
.
In the second pass, Ansible evaluates that string as a conditional expression and checks if the literal string 'testdb1'
is in mysql_result.stdout
.
The updated code removes template delimiters so that it’s a single-pass operation where db1_name
is directly referenced as a variable in the Jinja expression. As the Porting Guide mentions, “dynamic expression construction from playbooks is insecure and unsupported.”
Additional considerations
Ansible 12 includes a number of other changes beyond overhauling the templating engine. For example, module developers must now explicitly convert non-string keys to string before passing dictionaries to ansible-core’s AnsibleModule.exit_json()
method. The Porting Guide refers to this in the No implicit conversion of non-string dict keys section.
Let’s see another real-world example. This time we can look at the community.clickhouse collection, which made the following change:
Before
if result == PRIV_ERR_CODE:
return {PRIV_ERR_CODE: "Not enough privileges"}
After
if result == PRIV_ERR_CODE:
return {str(PRIV_ERR_CODE): "Not enough privileges"}
Explanation
By wrapping PRIV_ERR_CODE
with str()
the module explicitly converts the integer, or numeric, constant to a string before using it as a dictionary key. This change makes data serialization more predictable and, since data handling is more explicit, there is also a security improvement.
Where to go next
Read the Porting Guide as your next step. The Porting Guide outlines all the changes in ansible-core’s templating engine as of stable-2.19 and Ansible 12. The Porting Guide also describes common errors that can occur due to those changes along with lots of examples.
- Porting Guide at Ansible 12 Porting Guide — Ansible Community Documentation
Here are some other resources you might find useful to understand changes in Ansible 12:
- Core-2.19 templating changes - preview and testing
- Making a collection compatible with core 2.19 and templating changes
- Brian Coca’s description of templating changes: Core-2.19 templating changes - preview and testing - #20 by bcoca
- All forum posts about templating: Topics tagged templating
Call to action
As always we’d love to hear from you. If you have questions or notice issues or small additions for this post, please reply directly below.
If you think you see important information that is missing from the Porting Guide, please create an issue here:
If you still have a question or are observing behavior or an error that the Porting Guide does not explain, please create a new forum post and add the “templating” tag.