I am writing a playbook that only should run when a new package version of a software is available.
Both version numbers are custom facts I set with "set_fact"
Ansible let's you compare version numbers, so I tried it like this:
- name: compare versions
debug:
msg: "The version {{ new_version }} is newer than the old version {{ old_version }}"
when: "{{ new_version is version('{{ old_version }}', '>', strict=True }}"
Ansible throws an error that the version number is invalid. When I set "old_version" to a fixed version number it works as expected.
Is it possible to compare two facts with "version"?
I already tried different approaches with double-quotes etc which leads to syntax errors in ansible.
Any ideas?
Thanks
It could be use of Jinja delimiters {{ in a conditional. In a when: condition you don't need these delimiters to interpolate.
Example below works:
vars:
new_version: 14
old_version: 12
tasks:
- debug:
msg: 'The version {{ new_version }} is newer than the old version {{ old_version }}'
when: "new_version is version(old_version, '>')"
Related
Hey I am trying to check the version on installed software on my VMs with Ansible.
Unfortunately I cant get the conditionals right.
Via the ansible_facts.packages I get the version of the software but I am not sure about the comparing.
- hosts:
- os_linux
vars:
softwareVersion: "4.8.0-49"
tasks:
- name: Gather the package facts
ansible.builtin.package_facts:
manager: auto
- name: Check version of SoftwareX
ansible.builtin.debug:
msg: "OLD SoftwareX version: {{ ansible_facts.packages['SoftwareX'][0]['version'] }} found"
when: "ansible_facts.packages['SoftwareX'][0]['version'] <= {{ softwareVersion }}"
I am not sure about the comparing.
when: "ansible_facts.packages['SoftwareX'][0]['version'] <= {{ softwareVersion }}"
Since according When should I use {{ }}?
when:... are always templated and you should avoid adding {{ }}.
you'll need to remove first the curly brackets from softwareVersion.
Then, since you are comparing strings which contains a version number in order, you need to address this in a different way. Means, you can't use plain a mathematical operation but instead a specific filter for.
A minimal test playbook
---
- hosts: localhost
become: false
gather_facts: false
vars:
installedVersion: "4.7.0-48"
softwareVersion: "4.8.0-49"
tasks:
- name: Show hint
debug:
msg: "OLD"
when: installedVersion is version(softwareVersion, '<=')
will result into an output of
TASK [Show hint] ******
ok: [localhost] =>
msg: OLD
Further Documentaion
Comparing versions
Note: In 2.5 version_compare was renamed to version
To compare a version number, such as checking if the ansible_facts['distribution_version'] version is greater than or equal to ‘12.04’, you can use the version test.
Similar Q&A
Compare version numbers using Jinja2
How to compare kernel (or other) version numbers in Ansible?
For a role I'm developing I need to verify that the kernel version is greater than a particular version.
I've found the ansible_kernel fact, but is there an easy way to compare this to other versions? I thought I might manually explode the version string on the .'s and compare the numbers, but I can't even find a friendly filter to explode the version string out, so I'm at a loss.
There is a test for it:
{{ ansible_distribution_version is version('12.04', '>=') }}
{{ sample_version_var is version('1.0', operator='lt', strict=True) }}
To Print the host IP address if the kernel version is less than 3
Ansible Version : 2.0.0.2
---
- hosts: all
vars:
kernel_version: "{{ ansible_kernel }}"
tasks:
- name: 'kernel version from facts'
debug:
msg: '{{ansible_all_ipv4_addresses}} {{ansible_kernel}}'
when: ansible_kernel | version_compare('3','<')
**
In 2.5 version_compare was renamed to version
**
For ansible>=2.9 this won't work, as the test syntax is now strictly separated from filters.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html
The working solution would be:
{{ sample_version_var is version('1.0', operator='lt', strict=True) }}
...
To compare a version number, such as checking if the ansible_facts['distribution_version'] version is greater than or equal to ‘12.04’, you can use the version test.
{{ ansible_facts['distribution_version'] is version('12.04', '>=') }}
When using version in a playbook or role, don’t use {{ }} as described in the FAQ
vars:
my_version: 1.2.3
tasks:
- debug:
msg: "my_version is higher than 1.0.0"
when: my_version is version('1.0.0', '>')
Check Ansible Doc for more info
Have you thought of using shell module instead? for example:
- name: Get Kernel version
shell: uname -r | egrep '^[0-9]*\.[0-9]*' -o
register: kernel_shell_output
- debug: msg="{{ kernel_shell_output.stdout}}"
- name: Add cstate and reboot bios if kernel is 4.8
shell: echo "do what yo need to do"
when: kernel_shell_output.stdout == "4.8"
Is there any command in Ansible to collect the hostnames of hosts with OS Debain?
The file hosts contains no groups!
So a simple command to see the hostnames of hosts containing Debain.
The setup module, which is implicitly called in any playbook via the gather_facts mechanism, contains some output that you could use.
Look for example for the ansible_distribution fact, which should contain Debian on the hosts you are looking for.
If all you want is that list once, you could invoke the module directly, using the ansible command and grep:
ansible all -m setup -a 'filter=ansible_distribution' | grep Debian
If you want to use that information dynamically in a playbook, you could use this pattern:
---
- hosts: all
tasks:
- name: Do something on Debian
debug:
msg: I'm a Debian host
when: ansible_distribution == 'Debian'
I would add that if you want to target distribution and minimum version (often the case), you could do that with a dictionary. I often use this snippet:
---
- hosts: localhost
vars:
minimum_required_version:
CentOS: 7
Debian: 11
Fedora: 31
RHEL7: 7
Ubuntu: 21.10
- name: set boolean fact has_minimum_required_version
set_fact:
has_minimum_required_version: "{{ ansible_distribution_version is version(minimum_required_version[ansible_distribution], '>=') | bool }}"
tasks:
- name: run task when host has minimum version required
debug:
msg: "{{ ansible_distribution }} {{ ansible_distribution_version }} >= {{ minimum_required_version[ansible_distribution] }}"
when: has_minimum_required_version
You could also dynamically include a playbook fragment that targets specific distributions or versions like so:
- name: Include task list in play for specific distros
include_tasks: "{{ ansible_distribution }}.yaml"
Which assumes you'd have Debian.yaml, Ubuntu.yaml, etc. defined for each distro you want to support.
For a role I'm developing I need to verify that the kernel version is greater than a particular version.
I've found the ansible_kernel fact, but is there an easy way to compare this to other versions? I thought I might manually explode the version string on the .'s and compare the numbers, but I can't even find a friendly filter to explode the version string out, so I'm at a loss.
There is a test for it:
{{ ansible_distribution_version is version('12.04', '>=') }}
{{ sample_version_var is version('1.0', operator='lt', strict=True) }}
To Print the host IP address if the kernel version is less than 3
Ansible Version : 2.0.0.2
---
- hosts: all
vars:
kernel_version: "{{ ansible_kernel }}"
tasks:
- name: 'kernel version from facts'
debug:
msg: '{{ansible_all_ipv4_addresses}} {{ansible_kernel}}'
when: ansible_kernel | version_compare('3','<')
**
In 2.5 version_compare was renamed to version
**
For ansible>=2.9 this won't work, as the test syntax is now strictly separated from filters.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html
The working solution would be:
{{ sample_version_var is version('1.0', operator='lt', strict=True) }}
...
To compare a version number, such as checking if the ansible_facts['distribution_version'] version is greater than or equal to ‘12.04’, you can use the version test.
{{ ansible_facts['distribution_version'] is version('12.04', '>=') }}
When using version in a playbook or role, don’t use {{ }} as described in the FAQ
vars:
my_version: 1.2.3
tasks:
- debug:
msg: "my_version is higher than 1.0.0"
when: my_version is version('1.0.0', '>')
Check Ansible Doc for more info
Have you thought of using shell module instead? for example:
- name: Get Kernel version
shell: uname -r | egrep '^[0-9]*\.[0-9]*' -o
register: kernel_shell_output
- debug: msg="{{ kernel_shell_output.stdout}}"
- name: Add cstate and reboot bios if kernel is 4.8
shell: echo "do what yo need to do"
when: kernel_shell_output.stdout == "4.8"
I'm trying to overwrite a previously defined variable my_var (when it's set to LATEST) by loading a value from a file (containing, say, NEWVALUE).
- name: Load from file
vars:
my_var: "{{ lookup('file', '~/file.txt') }}"
my_var2: "{{ lookup('file', '~/file.txt') }}"
debug: msg="my_var is {{ my_var }} my_var2 is {{ my_var2 }}"
when: "{{ my_var=='LATEST' }}"
This prints
ok: [host] ==> {
"msg": "my_var is LATEST my_var2 is NEWVALUE"
}
So I feel that I've verified that I'm loading the value correctly.. but for some reason I can't set the result of lookup in a previously set variable. Disabling the when clause doesn't seem to make any difference.
Should I be able to do this? As an alternative I'm going to use a third variable and just set it to either the preexisting value or the value from the file - but this seems like an unnecessary step to me.
Ansible version 2.1.0.0 b.t.w.
The vars you defined in your example only are available for the single debug task.
As you mentioned in the comment you figured this out and used set_fact instead. And yes, this won't work if you have passed the same variable as extra-var, as it has the highest precedence. There is no way to override a variable you passed as extra-var.