3

I have following working tasks:

- name: Get Package infos
  ansible.builtin.package_facts:
    manager: auto

- name: Test redis-server version
  ansible.builtin.assert:
    that:
      - ansible_facts.packages['redis-server'][0].version is version('4.0', '>=')

I have wondered if I am able to combine those tasks into a single one:

- name: Get Package infos
  tags: redis
  ansible.builtin.package_facts:
    manager: auto
  failed_when: ansible_facts.packages['redis-server'][0].version is version('4.0', '<')

But if I do so I got quite long error message which ends with:

The error was: error while evaluating conditional 
(ansible_facts.packages['redis-server'][0].version is version('4.0', '<')): 
'dict object' has no attribute 'packages'. 'dict object' has no attribute 'packages'"}

It seems that the field packages does not exists at that moment. What may fix this approach?

2
  • 2
    It's a bad idea to combine these tasks. You will miss potential package_facts failures. Feb 29 at 12:59
  • In addition to this, it's an overkill to run package_facts to get status of one package only. Feb 29 at 14:35

2 Answers 2

3

A minimalistic option would be

    - command: redis-cli --version
      register: out
      failed_when: out.stdout|split|last is version(7.0, '<')

Optionally, test also rc

    - command: redis-cli --version
      register: out
      failed_when:
        out.rc != 0 or
        out.stdout|split|last is version(7.0, '<')

This task doesn't change anything. Suppress the reporting of the changed status

    - command: redis-cli --version
      register: out
      failed_when:
        out.rc != 0 or
        out.stdout|split|last is version(7.0, '<')
      changed_when: false

Notes

  1. It's possible to use the ansible_facts.packages from the registered variable. But, the module package_facts is not practical in checking the version of redis because it is OS dependent and slow. For example,
    - package_facts:
      register: out
    - debug:
        msg: |
          {{ out.ansible_facts.packages['redis-server'] |
             map(attribute='version') }}"
          {{ out.failed }}

gives on Ubuntu

  msg: |-
    ['5:7.0.12-1']
    False

The equivalent to the above command task would be

    - package_facts:
      register: out
      failed_when:
        out.failed or
        ver is version(7.0, '<')
      vars:
        ver: "{{ out.ansible_facts.packages['redis-server'] |
                 map(attribute='version') |
                 first |
                 split(':') |
                 last }}"
      changed_when: false

  1. An elegant option is custom facts. On the remote hosts where you want to check the version of redis create the below script
shell> cat /etc/ansible/facts.d/redis.fact 
#!/usr/bin/sh
ver=`(redis-cli --version | cut -d ' ' -f 2)`
echo {\"redis_version\": \"$ver\"}

Test it

shell> /etc/ansible/facts.d/redis.fact 
{"redis_version": "7.0.12"}

Then, the below play

- hosts: localhost

  tasks:

    - setup:
        gather_subset: facter
    - debug:
        var: ansible_local

gives (abridged)

  ansible_local:
    redis:
      redis_version: 7.0.12
3

Correct, ansible_facts is not updated between when a task completes and when that same task evaluates its failed_when.

Use your first attempt as is, package_facts followed by assert. Perfectly understandable what it is doing.

package_facts checks the system package manager, which is a good choice for centralizing how software gets installed. (If your OS distro is supported by this module.) You could install some other way, but that requires other methods to maintain and patch it.

Collecting facts about all packages in a standard format, abstracted across a half dozen package managers, is worth the small performance cost of a package manager query. Similar to doing an rpm -qa when -all is not strictly necessary. Although in rpm's case it is using Python bindings rather than the program.

assert is an action plugin, and so does not need to remote anywhere or run external commands. As a result not much run time would be saved combining the tasks.

Tasks that only collect data, and so increase the tasks count in a play summary but never change things, are acceptable style to me. Doing many non-trivial things in Ansible calls for set up, and those tasks don't always change anything.

Minor suggestion, consider making the version string a variable. Major version requirements of applications might not change often. However when testing your role would be nice to see what the failure condition looks like.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .