1

The task is to get a list of the latest updates. Approximately as the command issues dnf check-update Ansible code:

  tasks:
  - name: List Available Patches (Non-Kernel)
    dnf:
      list: updates
      update_cache: true
    register: packages

  - debug:
      msg: >-
        {%- set output=[] -%}
        {%- for p in packages.results -%}
        {{ output.append((p.name ~ '-' ~ p.version ~ '-' ~ p.release)) }}
        {%- endfor -%}
        {{ output }}

But in this case I can get the same package but with different versions, how can I get only the latest version?

    "vlc-3.0.18-1.el7.3",
    "vlc-3.0.18-2.el7.3",
    "vlc-core-3.0.18-1.el7.3",
    "vlc-core-3.0.18-2.el7.3",
    "xdg-desktop-portal-1.8.0-3.el7",
    "xorg-x11-server-Xorg-1.20.14-4.el7.3",
    "xorg-x11-server-Xorg-1.20.14-5.el7.3",
    "xorg-x11-server-Xorg-1.20.14-6.el7.3",
rk3dnp
  • 21
  • 3

1 Answers1

1

groupby the list packages.results by name and create the dictionary my_packages

  my_packages: "{{ dict(packages.results|groupby('name')) }}"

Then, the below template

    - debug:
        msg: |
          {% for name,versions in my_packages.items() %}
          {% set max_ver=versions|map(attribute='version')|max %}
          {% set p=versions|selectattr('version', '==', max_ver) %}
          {{ name }}-{{ p.0.version }}-{{ p.0.release }} 
          {% endfor %}

gives what you want

  msg: |-
    adcli-0.8.2-12.el8
    alsa-sof-firmware-1.8-1.el8
    ansible-7.2.0-1.el8
    authselect-1.2.2-3.el8
    authselect-libs-1.2.2-3.el8
    bash-4.4.20-2.el8
    bind-export-libs-9.11.26-6.el8
    binutils-2.30-108.el8
    bpftool-4.18.0-348.2.1.el8_5
    ca-certificates-2021.2.50-80.0.el8_4
    centos-gpg-keys-8-3.el8
    centos-linux-release-8.5-1.2111.el8
    centos-linux-repos-8-3.el8
    centos-logos-85.8-2.el8
    ...

Example of a complete playbook for testing

- hosts: foo

  vars:

    my_packages: "{{ dict(packages.results|groupby('name')) }}"

  tasks:

    - dnf:
        list: updates
      register: packages

    - debug:
        msg: |
          {% for name,versions in my_packages.items() %}
          {% set max_ver=versions|map(attribute='version')|max %}
          {% set p=versions|selectattr('version', '==', max_ver) %}
          {{ name }}-{{ p.0.version }}-{{ p.0.release }} 
          {% endfor %}

Q: "The error was: generator object has no element 0"

A: The problem might be an older version of Ansible. Try explicit conversion to list

          {% set p=versions|selectattr('version', '==', max_ver)|list %}
Vladimir Botka
  • 5,138
  • 8
  • 20
  • I get an error: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: generator object has no element 0\n\nThe error appears to be in '/root/.ansible/41.yml': line 8, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n register: packages\n - debug:\n ^ here\n"} – rk3dnp Jul 28 '23 at 12:55
  • Try explicit conversion to list. See the example. [Upgrade](https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html) to a supported version ASAP. – Vladimir Botka Jul 29 '23 at 14:46
  • 1
    My ansible version is 2.9.27. Converting to a list helped. You can suggest, if necessary, in a column. My output is now: \nzchunk-libs-1.1.5-3.el7 \nzenity-3.32.0-3.el7 Where \n should be newline? I have everything in one line. – rk3dnp Jul 31 '23 at 06:48