Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

modern_output — Ansible Callback Plugin

A custom stdout callback plugin that replaces Ansible's default playbook output with a clean, minimalistic, emoji-decorated display featuring animated per-host spinners, real-time grouped loop progress, verbosity support, failure summaries, and a color-coded recap table.

Demo

Demo

Demo with verbosity

Demo with verbosity

Features

  • Single-line results — each host outcome is one line: ✅ ok, 🔄 changed, ⏭️ skipped, ❌ FAILED!, 💀 UNREACHABLE!, ⚠️ ignored
  • Multi-line failure detail — failed and unreachable hosts show the error message on indented follow-up lines
  • Debug module outputdebug tasks always display their msg or var output, regardless of verbosity
  • Real-time grouped loops — loop tasks are marked with 🔁; items appear in real-time under their host (each host shown exactly once) with [index/total] item_value progress
  • Animated per-host spinner — while a task runs, every active host gets its own spinning Braille indicator (⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏); queued hosts for future batches display a static
  • Verbosity levels-v shows all module result fields + a failure summary table with error messages; -vv also shows module name and arguments
  • Recap table — a Unicode box-drawing table with color-coded stats (green OK, yellow changed, red failed/unreachable, cyan skipped)
  • Failure summary — at -v or higher, a second table lists each failed host with the task that failed and the error message
  • No external dependencies — only Python stdlib + ansible.plugins.callback.CallbackBase

Example Output

▶ PLAY [Deploy App] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📋 TASK [Install packages] 🔁 ━━━━━━━━━━━━━━━━━━━━━━━━━
  🔁 web-01                       ← items appear in real-time
      ✅ [1/3] httpd
      🔄 [2/3] php
      ✅ [3/3] mariadb
  🔁 web-02
      🔄 [1/3] httpd
      🔄 [2/3] php
      🔄 [3/3] mariadb
  ❌ db-01 · FAILED!              ← final status after all items
      ✅ [1/3] httpd
      ❌ [2/3] php
         msg: package not found
      ⏭️ [3/3] mariadb
  ⏭️  db-02 · skipped

📋 TASK [Show config] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  ✅ web-01 · ok
     Current config is valid.
  ✅ web-02 · ok
     Current config is valid.

📊 PLAY RECAP ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌──────────┬────┬─────────┬─────────────┬────────┬─────────┬─────────┬─────────┐
│ Host     │ OK │ Changed │ Unreachable │ Failed │ Skipped │ Rescued │ Ignored │
├──────────┼────┼─────────┼─────────────┼────────┼─────────┼─────────┼─────────┤
│ db-01    │  3 │       0 │           0 │      1 │       1 │       0 │       0 │
│ db-02    │  5 │       0 │           0 │      0 │       0 │       0 │       0 │
│ web-01   │  5 │       0 │           0 │      0 │       0 │       0 │       0 │
│ web-02   │  4 │       3 │           0 │      0 │       0 │       0 │       0 │
└──────────┴────┴─────────┴─────────────┴────────┴─────────┴─────────┴─────────┘

  ❌ FAILURE SUMMARY                       ← only at -v or higher
┌──────────┬──────────────────┬─────────────────────┐
│ Host     │ Task             │ Error               │
├──────────┼──────────────────┼─────────────────────┤
│ db-01    │ Install packages │ package not found   │
└──────────┴──────────────────┴─────────────────────┘

Installation

  1. Place modern_output.py inside a callback_plugins/ directory next to your playbook (or anywhere Ansible can find it):
project/
├── ansible.cfg
├── inventory
├── playbook.yml
└── callback_plugins/
    └── modern_output.py
  1. Configure ansible.cfg:
[defaults]
stdout_callback = modern_output
callback_plugins = ./callback_plugins

That's it — run ansible-playbook as usual.

Verbosity

Flag What it adds
(none) Status line per host. Debug msg/var always shown. Failures show msg/stderr.
-v All result fields from every module. Failure summary table (Host, Task, Error) at play recap.
-vv Module name and task arguments for every host result.

Example at -vv (non-loop task):

  🔄 web-01 · changed
     module: ansible.builtin.dnf  args: name=httpd, state=present
     msg: Installed: httpd
     rc: 0

Example at -vv (loop item):

  🔁 web-01
      ✅ [1/3] httpd
         module: ansible.builtin.dnf  args: name=httpd, state=present
         msg: Nothing to do
         rc: 0

How It Works

v2_playbook_on_play_start       →  ▶ PLAY [name] ━━━
v2_playbook_on_task_start       →  📋 TASK [name] ━━━  (+ 🔁 if loop)
                                   show all hosts as ⏳ (spinner)
v2_runner_on_start              →  promote host ⏳ → animated ⠋
v2_runner_item_on_*             →  buffer item, redraw live block grouped by host
v2_runner_on_ok / failed / …    →  print result ✅/❌/… (or finalize loop host)
v2_playbook_on_stats            →  📊 PLAY RECAP table + failure summary

Spinner: runs in a background thread, redraws a multi-line block in-place using ANSI cursor-up sequences. Result output and the spinner share a lock so they never tear each other's lines.

Loop block: when the first loop item arrives, the spinner stops and a redrawable "live block" takes over. Each item is buffered per host and the entire block is erased + redrawn on every event, so each host appears exactly once with items accumulating underneath in real-time. When the aggregate result fires, the host header updates from 🔁 to its final status emoji. At the next task start, the block is finalized as permanent output.

Requirements

  • Ansible 2.8+ (uses v2_runner_on_start)
  • A terminal with ANSI escape code and Unicode support

Status Legend

Emoji Meaning
Task succeeded (ok)
🔄 Task succeeded with changes
⏭️ Task skipped
Task failed
💀 Host unreachable
⚠️ Task failed but ignore_errors: true
Host actively executing (animated)
Host queued for a future batch
🔔 Handler running
🔁 Loop task / host with items in progress

About

Modern Ansible custom callback plugin

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages