Use Ansible to report free disk space and installed package versions across several BinaryLane Linux servers. The playbook does not install packages, change configuration, or restart services.

To export your server list instead of entering hosts by hand, start with Build an Ansible inventory from your BinaryLane fleet. Then use the Linux-only group instructions below to choose which servers to check.

TABLE OF CONTENTS

Before you begin

You need:

  • A Linux or macOS control machine with a currently supported ansible-core release. This guide is checked against ansible-core 2.21, which needs Python 3.12 to 3.14 on the control machine. Other supported releases need different Python versions, so check ansible --version against the ansible-core support matrix for the release you run. Windows users can run Ansible from a Linux distribution in WSL. See the Ansible installation guide.
  • Linux target servers reachable over SSH, with a login account able to read filesystem and package information. ansible-core 2.21 supports Python 3.9 to 3.14 on the target. Check the installed Python version rather than assuming it from the server image.
  • Working SSH key access from the control machine to each target. Connect with ssh your_user@your_server first and verify any new host key before accepting it.
  • Package-manager Python bindings available to the target interpreter: python3-apt on Debian and Ubuntu, or the RPM Python bindings (commonly python3-rpm) on RPM-based systems. Ansible's package-fact collection needs these and does not install them, and some distributions do not include them by default.

The playbook uses only modules included with ansible-core, so you do not need to install any extra collections. Ansible may transfer temporary module files during execution; the checks below do not alter your server's package or service configuration.


Applies to

  • ansible-core 2.21, and other supported ansible-core releases that meet their own Python requirements
  • BinaryLane Linux servers meeting the SSH, Python and package-binding prerequisites above

Set up a starting inventory

Create inventory.ini with the hosts and SSH usernames you already use. Replace these example values with your servers:

[fleet]
web1.example.com ansible_user=your_user
web2.example.com ansible_user=your_user
203.0.113.10 ansible_user=your_user

fleet is a group name defined in this inventory.

If you exported fleet.json using the linked guide, reuse that file instead of typing hosts by hand. Do not point this playbook at its whole binarylane group, or at bl_status_active: those groups hold every server on the account regardless of operating system, and that guide itself warns against running Linux tasks against them unless every server in the group is suitable.

To use that inventory with this guide:

  1. Define your own group, such as linux_fleet, in linux_fleet.ini alongside fleet.json. List only the running Linux servers you want to check, using their bl-<id> aliases.
  2. Use both inventory files in the commands below: -i fleet.json -i linux_fleet.ini instead of -i inventory.ini.
  3. Replace every fleet group name and web1.example.com-style host below with your chosen group and its bl-<id> aliases.

Apply these substitutions throughout: the connectivity check, the playbook's hosts: fleet line, the ansible-playbook run, and the --list-hosts and mount-facts commands under Troubleshooting.

Confirm Ansible can reach every host in the group before doing anything else:

ansible fleet -i inventory.ini -m ping

Each server should report "ping": "pong". Resolve SSH or Python errors before running the playbook.

The playbook

Create check-fleet.yml:

---
- name: Check disk space and installed packages
  hosts: fleet
  gather_facts: true
  become: false
  vars:
    package_name: openssh-server

  tasks:
    - name: Collect installed package facts
      ansible.builtin.package_facts:
        manager: auto

    - name: Report free disk space per mounted filesystem
      ansible.builtin.debug:
        msg: >-
          {{ item.mount }}:
          {%- if item.size_total is defined %}
          {{ (item.size_available / 1024 / 1024) | round | int }} MiB free of
          {{ (item.size_total / 1024 / 1024) | round | int }} MiB
          {%- else %}
          size not reported by this host
          {%- endif %}
      loop: "{{ ansible_facts.mounts | default([]) }}"
      loop_control:
        label: "{{ item.mount }}"

    - name: Report when no filesystem facts were collected
      ansible.builtin.debug:
        msg: >-
          No filesystem facts were collected for this host. See
          Troubleshooting below.
      when: ansible_facts.mounts is not defined

    - name: Report the installed version of a specific package
      ansible.builtin.debug:
        msg: >-
          {{ package_name }} is not installed on this host
      when: package_name not in ansible_facts.packages

    - name: Report the installed version when present
      ansible.builtin.debug:
        msg: >-
          {{ package_name }} version:
          {{ item.version }}{{ '-' ~ item.release if item.release is defined else '' }}
          ({{ item.arch | default('architecture not reported') }})
      loop: "{{ ansible_facts.packages.get(package_name, []) }}"
      when: package_name in ansible_facts.packages

Change package_name to the package you want to check. Package names can vary between distributions. Each installed entry is reported, including its release and architecture when provided by the package manager.

Run it

ansible-playbook -i inventory.ini check-fleet.yml

Read the results

Check the final play recap for failed=0 and unreachable=0 on every expected host. Each host should also show its mounted filesystems and the selected package's installed entries, or a not-installed message.

Disk sizes are in MiB (1 MiB = 1,048,576 bytes). Low available space is a reason to investigate that filesystem, with two exceptions to read past first:

  • Read-only image mounts are always full. Snap packages, for example, are mounted as read-only squashfs images and report 0 MiB free at their full size. That is how they are meant to look.
  • A filesystem reported as size not reported by this host was listed by the server but its size could not be read, which can happen with an unresponsive network mount. The filesystem still exists; only its size is missing.

A package-version difference is a lead to investigate, not proof of a missing security update: distribution releases and backported fixes matter.

Troubleshooting

ansible.builtin.package_facts returns an error about a missing package manager binding

Check the interpreter named in the error and whether it can load the package-manager bindings. Debian and Ubuntu need python3-apt; RPM-based systems need the RPM Python bindings. A binding installed for the system Python may not be available to a different interpreter selected by Ansible. Resolve the dependency before rerunning the playbook.

ping succeeds but package_facts or debug results look empty

Read the first failed task for that host in the play output. Confirm gather_facts: true is set and package-fact collection succeeded. ping checks SSH and Python execution, not package-manager dependencies.

A host reports that no filesystem facts were collected

Confirm the missing facts, then leave that host's disk check out of this report. Ansible builds its filesystem facts by parsing the host's mount table, and it drops the whole set for that host if any single entry cannot be parsed. It does this without a warning, including at high verbosity, so the play output alone does not explain it.

To confirm which is the case for one host:

ansible web1.example.com -i inventory.ini -m setup -a "filter=ansible_mounts"

An empty ansible_facts result confirms the filesystem facts were dropped for that host, rather than the host having no filesystems to report. The package checks in this playbook are unaffected, and df -h on the server itself still reports disk space.

A host is missing from the report entirely

Run ansible fleet -i inventory.ini --list-hosts and confirm the host is listed. If it is, check the play recap for failed or unreachable hosts and retry the connection check for that host.


Documentation checked: 10 September 2026