sameeralam3127.linux_vitals · Ansible Galaxy collection

Your Linux fleet has a pulse. Now you can see it.

LinuxVitals is an agentless Ansible collection that scans, opt-in self-heals, and reports on your Linux servers — severity-ranked findings, per-distro reboot and kernel detection, a baseline → postcheck comparison for real maintenance windows, and one self-contained HTML dashboard at the end of it.

$ ansible-galaxy collection install sameeralam3127.linux_vitals
2.2.0 latest release
6 distros tested every push
MIT open source
4 roles scan · heal · certs · report
Verified on every push against real systemd containers
✓ Ubuntu 24.04 ✓ Debian 12 ✓ Rocky Linux 9 ✓ Fedora 42 ✓ Amazon Linux 2023 ✓ openSUSE Leap 15
What it does

Deep OS posture, not just uptime pings

Nothing is installed on managed hosts, and every check is read-only unless you explicitly opt in.

Read-only scan

Kernel & bootloader validation, reboot-required per distro, /boot space, SELinux/AppArmor, failed logins, journal errors, memory pressure, core services — plus every enabled unit systemd reports as failed.

vitals_scan

Every mount, space and inodes

Used space and used inodes on every real filesystem, not just /boot — plus a mount that unexpectedly went read-only, which is usually the kernel reacting to an I/O error.

filesystem_space_low

Saturation, not just free RAM

5-minute load per CPU, PSI stall percentages for CPU, memory and I/O, and the swap paging rate — so a host thrashing with free RAM stops reading as healthy.

pressure_stall_high

Severity-based triage

Every finding is info, warning or critical. Raise linux_vitals_fail_on_severity and only what matters fails a host — everything is still reported.

fail_on_severity

Never a false "all clear"

A check that could not run — journal unreadable, tool missing — raises an unknown finding with the reason, and that host never counts as healthy.

status: unknown

Opt-in self-healing

One restart attempt per enabled, failed systemd unit — and the report says whether it worked. Off by default; it never enables, installs, or masks a unit.

vitals_heal

TLS certificate checks

Opt-in expiry, weak-signature, and obsolete-protocol checks — on disk and over the wire, including a served cert that no longer matches the file.

vitals_certs

Baseline → postcheck diff

Snapshot before a maintenance window, snapshot after, correlated by a maintenance id: improved and regressed hosts, RAM deltas, kernel changes, new and resolved findings.

vitals_report

Self-contained dashboard

One HTML file plus a versioned JSON report. No CDN, no server — search, sort, filter, and expand any host, offline, forever.

dashboard.html.j2

Notifications

Slack Block Kit, email, and a generic webhook — each independent, with credentials kept in .env or vault, never on the command line.

vitals_report

A gate for your pipeline

linux_vitals_fail_on_status fails the run on failing or regressed hosts — after reports and notifications are written, so the evidence always exists.

fail_on_status
Not a mockup

This is the actual dashboard

Rendered by the real vitals_report role from the collection's own golden scan fixtures: a baseline run, a patch window, and a postcheck with the same maintenance id. Search a hostname, sort a column, expand a host.

reports / linux_vitals_report.html Open full screen ↗
Health-score ring & KPI row Improved / Regressed filters Unknown checks, with reasons Light & dark themes
Interactive

Triage playground

The same fleet as the dashboard above, re-scored live in your browser with the collection's own rules. Change the threshold, retune a finding, set a pipeline gate — and watch which hosts fail, what the health score does, and whether the run would exit non-zero.

Fail a host at linux_vitals_fail_on_severity

The default, info, fails a host on any finding.

Fleet gate · linux_vitals_fail_on_status

The run fails when more hosts than the threshold fail (any_fail) or went from Pass to Fail since the baseline (regression).

Per-finding overrides · linux_vitals_finding_severity_overrides

Only findings this sample fleet raises are listed. The number is how many hosts raise it.

0%
0passing
0failing
0regressed

group_vars/all.yml

        
Distro-aware by design

Every family answers "do I need a reboot?" differently

So LinuxVitals asks each one in its own language, reports which source produced the answer, and never reads a broken check as "all clear". Pick a family to watch the probe run.

vitals_scan

        

The bootloader gets the same care: grubby, grubenv, GRUB_DEFAULT, BLS entries and systemd-boot are all resolved, so a host with the newest kernel installed but an older one set to boot is flagged before it reboots into a surprise. Read the detection docs ↗

The workflow

Built around real maintenance windows

Three playbooks, one shared maintenance id. Click a step to replay it.

01 / Before

Capture a baseline

Run …linux_vitals.baseline with a linux_vitals_maintenance_id before your window opens. Full posture, snapshotted per host.

02 / During

Do your maintenance

Patch, reboot, reconfigure — however you normally do it. LinuxVitals stays out of the way.

03 / After

Run postcheck, get the diff

Run …linux_vitals.postcheck with the same id. The dashboard shows exactly what changed — per host, per finding.

control node

    

Too many hosts for one run? Shard the fleet: every shard keeps the window's maintenance id, and from the next release each one sets its own linux_vitals_snapshot_shard, so a shard id reused for a different set of hosts is refused instead of silently merged into the comparison. Sharding a large fleet ↗

Get started

Point it at an inventory, get a dashboard

No agents, no daemons, no database — just SSH and Ansible. Python 3.10+ and ansible-core 2.16+ on the control node.

terminal
# pulls community.general too, which the notification tasks need
ansible-galaxy collection install sameeralam3127.linux_vitals

# on an ansible-core 2.16 control node, pin community.general below 12
ansible-galaxy collection install sameeralam3127.linux_vitals 'community.general:<12'
requirements.yml
collections:
  - name: sameeralam3127.linux_vitals
    version: ">=2.2.0"
terminal
# one-shot health check across the fleet
ansible-playbook -i inventory.ini sameeralam3127.linux_vitals.healthcheck

# before a maintenance window
ansible-playbook -i inventory.ini sameeralam3127.linux_vitals.baseline \
  -e linux_vitals_maintenance_id=CHG-2026-1012

# after it, for the before/after diff
ansible-playbook -i inventory.ini sameeralam3127.linux_vitals.postcheck \
  -e linux_vitals_maintenance_id=CHG-2026-1012
terminal · needs Docker and ansible-core
# Ubuntu, Rocky and Fedora containers: healthy, broken on purpose, healed
git clone https://github.com/sameeralam3127/linux-vitals
cd linux-vitals/demo && ./run.sh

# remove every trace of it
./run.sh clean
Command builder

Build the exact command, from the real variables

Every option below is generated from the collection's own meta/argument_specs.yml, with the real defaults. Change what you need; only what differs from a default ends up in the output — and Share gives you a link that reopens this exact configuration.

Report paths and the .env lookup resolve from this file's directory, not from the playbook's.

Ansible's default is 5. Raising this is the cheapest fleet-scale win; match it to control-node cores and to what your bastion tolerates.

Needed to read /var/log/btmp, the journal, and grub.cfg. Without it those checks come back unknown. Set it in the inventory rather than with --become, which would also try to escalate on the control node during reporting.

Leave all off to run everything. Include reporting with any focused tag, or the run produces no output file.

output

          

Release history

What shipped, and what's moving

Pulled live from GitHub releases and the commit log, with a built-in copy for when the API is out of reach.

What's next

Roadmap

Release milestones, with live progress from the issues in each. Nothing here is a commitment — the reasoning lives in docs/roadmap.md, and you can weigh in on any issue.

See what's actually going on across your fleet

Install it, point it at an inventory, and open one HTML file.