Ansible: updating select packages if installed without installing if not

I have a few tens of hosts that are a mix of CentOS 6 and 7. I recently started using Ansible to help manage them, but I'm still very much a newbie.

Like everybody, I have a periodic need to update packages on those machines, especially for security reasons. However, I don't want to update all packages on them, just specific ones -- which may vary from machine to machine, depending on its roles. I have used Ansible's yum command, with state=latest, and a list of specific packages, to update those hosts in the past, but only today did I notice that when running that against a host, if one of the listed packages is not installed on that machine it will then be installed.

What I need is a way to supply Ansible with a list of packages, and then for each host it will act upon: - if the package is present, update it to the latest version; - if the package is not present, do nothing.

Is there a practical way to do that?


Since ansible 2.5 there is an option update_only for yum (and since ansible 2.1 only_upgrade for apt) which installs latest version only if it was already installed on the system. So, instead of collecting a list of packages in another task, you can add the option.

- name: Update subset of packages.
  yum:
    name: "{{ item }}"
    state: latest
    update_only: yes
  with_items:
    - package1
    - package2

I am myself was searching the web and this article was found before I got to the official documentation. So I think it worse to be added here.


If you only want to update a subset of the packages with available updates you might want to try @wurtel s attempt. You will need to register the installed packages like this:

- name: Get installed packages.
  command: rpm -qa --qf "%{NAME}\n"
  register: installed_packages

Then you can define a set theory filter and update all the packages defined in the list of packages which are allowed to update packages_to_update.

- name: Update subset of packages.
  yum:
    name: "{{ item }}"
    state: latest
  with_items:
  - {{ installed_packages | intersect(packages_to_update) }}

This all seems a little complicated for a yum update?

why not just use a local command for this until Ansible gets around to allowing this option?

A simple playbook like this would do it.

---
- hosts: dev-systems
  remote_user: admin
  become: yes
  tasks:
    - name: Update installed packages.
      command: /usr/bin/yum update -y {{item}}
      with_items:
          - package1
          - package2
          - package3
          - package-etc

I just tested this and using two packages. one that needed an update and one that was not installed. End result was an updated package with out the other being installed.