How can I check if a software package is installed on a Linux system using Ansible?. You can use Ansible automation tool to query installation status of a package on Linux a system. From the results a condition can then be used, e.g skip a task if package is installed, or install if check status is failed.

We’ll have two test scenarios.

  1. Check if package is installed and output status in the results message
  2. Execute another task based on the check results.

We will be checking if vim package is installed on either Debian based or Red Hat based Linux distribution.

Using Ansible command module

Create a new playbook file called check_package.yml

$ vim check_package.yml

Here are the contents of the file.

---
- hosts: servers
  vars:
    package_names:
      - vim
  tasks:
    - name: "Check if vim package is installed or not on Debian Linux family"
      command: dpkg-query -l "{{ item }}"
      loop: "{{ package_names }}"
      register: package_check
      when: ansible_facts['os_family'] == "Debian"

    - name: "Check if vim package is installed or not on Red Hat Linux family"
      command: rpm -q "{{ item }}"
      loop: "{{ package_names }}"
      register: package_check
      when: ansible_facts['os_family'] == "RedHat"

- name: Check Satellite URL
  shell: subscription-manager config  | grep baseurl | grep https://{{ sat_fqdn }}/pulp/repos
  register: baseurl_result
  changed_when: false
  ignore_errors: True

- debug:
    msg: "Current Content base URL is: {{ baseurl_result.stdout_lines }}"

Create a hosts inventory file:

$ vim hosts
[all:vars]
ansible_user='root' #change accordingly
ansible_become=yes
ansible_become_method=sudo

[servers]
10.10.10.11
10.10.10.11

Run the playbook:

$ ansible-playbook -i hosts check_package.yml

PLAY [servers] ***************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************
ok: [server1]
ok: [server2]

TASK [Check if vim package is installed or not on Debian Linux family] *******************************************************************************************
changed: [server1] => (item=vim)
changed: [server2] => (item=vim)

TASK [Check if vim package is installed or not on Red Hat Linux family] ******************************************************************************************
skipping: [server1] => (item=vim)
skipping: [server2] => (item=vim)

TASK [Print executaion results] **********************************************************************************************************************************
ok: [server1] => {
    "msg": "Package is installed"
}
ok: [server2] => {
    "msg": "Package is installed"
}

PLAY RECAP *******************************************************************************************************************************************************
server1                    : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
server2                    : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Using Ansible package module

The same results can be achieved using package module. Below is the modified playbook using package module.

---
- hosts: servers
  vars:
    package_names:
      - vim 
      - telnet
  tasks:
    - name: "Check if vim package is installed or not on Debian Linux family"
      package:
        name: "{{ item }}"
        state: present
      check_mode: true
      loop: "{{ package_names }}"
      register: package_check

    - name: "Print execution results"
      debug:
        msg: "Package is installed"
      when: package_check is succeeded

Execution:

$ ansible-playbook -i hosts check_package1.yml

PLAY [servers] ***************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************
ok: [server1]
ok: [server2]

TASK [Check if vim package is installed or not on Debian Linux family] *******************************************************************************************
ok: [server1] => (item=vim)
ok: [server1] => (item=telnet)
changed: [server2] => (item=vim)
changed: [server2] => (item=telnet)

TASK [Print execution results] ***********************************************************************************************************************************
ok: [server1] => {
    "msg": "Package is installed"
}
ok: [server2] => {
    "msg": "Package is installed"
}

PLAY RECAP *******************************************************************************************************************************************************
server1                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
server2                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Run a task based on results outcome

Let’s modify the playbook to check if packages are present locally in the system, if not install them.

---
- hosts: servers
  remote_user: root
  vars:
    package_names:
      - nano
      - vim
  tasks:
    - name: "Check if vim package is installed or not on Debian Linux family"
      command: dpkg-query -l "{{ item }}"
      loop: "{{ package_names }}"
      register: debian_package_check
      when: ansible_facts['os_family'] == "Debian"

    - name: "Check if vim package is installed or not on Red Hat Linux family"
      command: rpm -q "{{ item }}"
      loop: "{{ package_names }}"
      register: redhat_package_check
      changed_when: false
      ignore_errors: true
      when: ansible_facts['os_family'] == "RedHat"

    - name: Install package if not present Debian
      package:
        name: "{{ item }}"
        state: present
      loop: "{{ package_names }}"
      when: debian_package_check is failed and ansible_facts['os_family'] == "Debian"
    
    - name: Install package if not present RedHat
      package:
        name: "{{ item }}"
        state: present
      loop: "{{ package_names }}"
      when: redhat_package_check is failed and ansible_facts['os_family'] == "RedHat"

Sample execution:

$ ansible-playbook -i hosts check_package.yml
PLAY [servers] ***************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************
ok: [server1]
ok: [server2]

TASK [Check if vim package is installed or not on Debian Linux family] *******************************************************************************************
skipping: [server2] => (item=nano)
changed: [server1] => (item=nano)

TASK [Check if vim package is installed or not on Red Hat Linux family] ******************************************************************************************
skipping: [server1] => (item=nano)
failed: [server2] (item=nano) => {"ansible_loop_var": "item", "changed": false, "cmd": ["rpm", "-q", "nano"], "delta": "0:00:00.014446", "end": "2021-03-25 23:06:14.220052", "item": "nano", "msg": "non-zero return code", "rc": 1, "start": "2021-03-25 23:06:14.205606", "stderr": "", "stderr_lines": [], "stdout": "package nano is not installed", "stdout_lines": ["package nano is not installed"]}
...ignoring

TASK [Install package if not present Debian] *********************************************************************************************************************
skipping: [server1] => (item=nano)
skipping: [server2] => (item=nano)

TASK [Install package if not present RedHat] *********************************************************************************************************************
skipping: [server1] => (item=nano)
changed: [server2] => (item=nano)

PLAY RECAP *******************************************************************************************************************************************************
server1                    : ok=2    changed=1    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0
server2                    : ok=3    changed=1    unreachable=0    failed=0    skipped=2    rescued=0    ignored=1

The Playbook could need improvement to work on all Linux distributions. We just demonstrated how package checking if installed on Red Hat and Debian based system can be done.

More guides on Ansible:

List of Ansible OS Family & OS Distribution Facts

How To Manage Docker Containers With Ansible

Upgrade CentOS|RHEL|Ubuntu|Debian Systems Using Ansible