Guidance about Jinja variable typing?

The system roles team has had two issues reported related to variables having different types in Jinja templates:

https://github.com/linux-system-roles/timesync/pull/154
https://github.com/willshersystems/ansible-sshd/issues/188

Both issues appear to be related to some interaction between Jinja 3.0 and ansible-core 2.1x

My question is: what should we do about this in the system roles? Do we really have to go through all of our Jinja template code and ensure variables are “cast” to their correct type? Do we have to add requirements.txt, bindep, etc. to ensure that only the correct combinations of ansible-core and Jinja are used?
Both of these solutions seem wrong to me, unless we have been using variables incorrectly in Jinja for years now, and we really should have been “casting” the types all along.

Hi,

there have been some changes when macros are used in templates. I filed
an issue for this some time ago:
https://github.com/ansible/ansible/issues/78141 Some of the changes
were not intentional and fixed in
https://github.com/ansible/ansible/commit/2aa3cc9e40f46aa9071060052a68c2e82605a9e4
(should be in the next 2.13.x release), while others are intentional
(due to changes how Jinja2 handles native types); the comments in the
issue explain some of the things that happen. Maybe this helps a bit.

Cheers,
Felix

Thanks. Yes, this explains the sshd issue.

But the timesync role issue does not involve macros: https://github.com/linux-system-roles/timesync/pull/154/files

<table>
<tr>
<td>

- {% if timesync_step_threshold != 0.0 %}

</td>
</tr>
<tr>
</tr>
</table>+ {% if timesync_step_threshold|float != 0.0 %}

That is - for some reason the variable timesync_step_threshold stops being a float inside the Jinja2 code block - and this only happens with certain combinations of ansible-core + jinja2

I think I’d need more evidence and context about how the role is being run, and if/how the user is specifying that value.

Regardless, the change is safe, and sane. It probably makes sense to cast them, especially if a caller was to specify that value as an int, since it’s just a default users can override. Or if they were to supply -e timesync_step_threshold=1.0 from the CLI it would become a string.

There are many ways in which a user tries to specify a value and it results in a string, such as {{ previsouly_a_float }} will become a string if done as a module argument to something like set_fact. Unless jinja2_native is enabled.

I think I’d need more evidence and context about how the role is being run, and if/how the user is specifying that value.

Regardless, the change is safe, and sane. It probably makes sense to cast them, especially if a caller was to specify that value as an int, since it’s just a default users can override. Or if they were to supply -e timesync_step_threshold=1.0 from the CLI it would become a string.

There are many ways in which a user tries to specify a value and it results in a string, such as {{ previsouly_a_float }} will become a string if done as a module argument to something like set_fact. Unless jinja2_native is enabled.

Which to me implies that, in template code (macros or otherwise), we should always cast anything which is a float or an int, because we can never be sure how the value was input.

Looks like another item for the recommended practices list - https://github.com/redhat-cop/automation-good-practices/blob/main/coding_style/README.adoc#yaml-and-jinja2-syntax

And I’m going to investigate if there is a way to scan the system roles template code for VAR OP float_or_int_value so I can cast all of it . . .

New addition to recommended practices: https://github.com/redhat-cop/automation-good-practices/pull/77
Script to check for usage of public api variables in roles in numeric operations in Jinja templates: https://github.com/linux-system-roles/auto-maintenance/pull/181