Version numbers in Ansible code
There are two useful Jinja filters that could help dealing with version numbers in Ansible code. One is
version_compare, which allows to compare version numbers. The other is
regex_replace, which can be used to get a major.minor version number from a longer version number.
It is possible to compare a simple version to an integer or decimal, to decide, whether to, for example, run a task in Ansible. That, however, becomes a bit harder, when using version numbers, that are more complex and are not really numbers, e.g.
3.2.1. One can use the
split function - split the version by dots and compare the results, but it's not that clean:
when: "version.stdout.split('.') >= '2' and version.stdout.split('.') > '7'"
Fortunately, there is a
version_compare jinja filter, that can be used in Ansible to compare even more complex versions:
- hosts: "localhost" gather_facts: false vars: version: "2.7.11" tasks: - name: check if version is within acceptable range assert: that: - version | version_compare('2.7', '>=', strict=True) - version | version_compare('4.0', '<', strict=True)
The second parameter of
version_compare (relational operator) can be noted as above, or using letter references (
gt...) as well.
The documentation on the
strict parameter is very brief, but the testing seems to show that it indeed uses stricter version notation rules on both sides of comparison: it requires at least one dot in the version number, and does not allow more than 2 dots. Setting
version variable in the code above to
188.8.131.52 would not work, while
3.0.1 would be fine with the
strict parameter present.
We'll use Python as an example, which has a version numbering scheme, that always has 2 dots, e.g.
3.5.1. In some cases, we must use Python executables, that are suffixed by a shortened version number, e.g.
python2.7. This means that we somehow need to reliably turn
Another jinja filter,
regex_replace, seemed the most efficient and reliable way to do just that. This regexp seemed to do the trick:
version | regex_replace('^([0-9])\\.([0-9]*).*', '\\1.\\2')
There is a caveat when using Ansible < 2.x:
Prior to ansible 2.0, if “regex_replace” filter was used with variables inside YAML arguments (as opposed to simpler ‘key=value’ arguments), then you needed to escape backreferences (e.g. \1) with 4 backslashes (
\\\\) instead of 2 (
So, for Ansible versions < 2.x, the code would look like this:
version_var | regex_replace('^([0-9])\\.([0-9]*).*', '\\\\1.\\\\2')