Ansible check if software package is installed on Linux

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
  #connection: local # When running locally
  vars:
    package_names:
      - vim
  tasks:
    - name: "Check if listed 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 listed 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: "Print execution results"
      debug:
        msg: "Package is installed"
      when: package_check is succeeded

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.12

Validate Playbook syntax:

$ ansible-playbook --syntax-check check_package.yml -i hosts
playbook: check_package.yml

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.

$ vim check_package1.yml
---
- hosts: servers
  #connection: local # When running locally
  vars:
    package_names:
      - vim 
      - telnet
  tasks:
    - name: "Check if listed package is installed or not on Debian Linux family"
      ansible.builtin.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.

$ vim check_package.yml
---
- hosts: servers
  #connection: local # When running locally
  remote_user: root
  vars:
    package_names:
      - nano
      - vim
  tasks:
    - name: "Check if listed 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 listed 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
      ansible.builtin.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
      ansible.builtin.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:

Join our Linux and open source community. Subscribe to our newsletter for tips, tricks, and collaboration opportunities!

Recent Post

Unlock the Right Solutions with Confidence

At CloudSpinx, we don’t just offer services - we deliver clarity, direction, and results. Whether you're navigating cloud adoption, scaling infrastructure, or solving DevOps challenges, our seasoned experts help you make smart, strategic decisions with total confidence. Let us turn complexity into opportunity and bring your vision to life.

Leave a Comment

Your email address will not be published. Required fields are marked *

Related Post

Rook is a robust and open source solution used to orchestrate distributed storage systems, particularly in cloud native environments. The […]

s5cmd is a CLI utility used to access S3 bucket and manage files – upload, or delete objects in an S3 […]

Ceph is an enterprise-grade, and open-source software-defined storage solution backed by Red Hat. It is designed for reliability, scalability, and […]

Let's Connect

Unleash the full potential of your business with CloudSpinx. Our expert solutions specialists are standing by to answer your questions and tailor a plan that perfectly aligns with your unique needs.
You will get a response from our solutions specialist within 12 hours
We understand emergencies can be stressful. For immediate assistance, chat with us now

Contact CloudSpinx today!

Download CloudSpinx Profile

Discover the full spectrum of our expertise and services by downloading our detailed Company Profile. Simply enter your first name, last name, and email address.