Introduction
ARA Records Ansible (ARA) is an open-source tool that records Ansible playbook execution data and makes it available through a web interface, CLI, and REST API. Every time you run a playbook, ARA captures tasks, results, hosts, files, and timing — giving you a searchable history of what ran, when, where, and what changed. This guide covers installation, configuration, and practical usage.
What ARA Records
ansible-playbook site.yml
│
▼
┌──────────────────────┐
│ ARA Callback Plugin │ ← Intercepts all task results
└──────────────────────┘
│
▼
┌──────────────────────┐
│ ARA Database │ ← SQLite (default) or PostgreSQL
│ │
│ • Playbook metadata │
│ • Play/task results │
│ • Host facts │
│ • File contents │
│ • Timing data │
│ • Changed/failed │
└──────────────────────┘
│
▼
┌──────────────────────┐
│ Browse Results │
│ • Web UI │
│ • CLI (ara) │
│ • REST API │
└──────────────────────┘
Installation
Install ARA with pip
# Install ARA with the API server (includes web UI)
pip install "ara[server]"
# Verify installation
ara --version
# Minimal install (recording only, no server)
pip install ara
Install with Ansible
# install-ara.yml
---
- name: Install ARA Records Ansible
hosts: control_node
become: true
tasks:
- name: Install ARA with server components
ansible.builtin.pip:
name: "ara[server]"
state: present
- name: Get ARA callback plugin path
ansible.builtin.command: python3 -m ara.setup.callback_plugins
register: ara_callback_path
changed_when: false
- name: Display callback path
ansible.builtin.debug:
msg: "Add this to ansible.cfg: callback_plugins = {{ ara_callback_path.stdout }}"
Configuration
Method 1: ansible.cfg (Recommended)
# ansible.cfg
[defaults]
# Enable ARA callback plugin
callback_plugins = %(python_path)s/ara/plugins/callback
# Or get the path dynamically:
# python3 -m ara.setup.callback_plugins
[ara]
# API client (default: offline — uses local database)
api_client = offline
# Database location (default: ~/.ara/server/ansible.sqlite)
# api_server = http://ara-server:8000
# api_username = ara
# api_password = password
Method 2: Environment Variables
# Enable ARA callback
export ANSIBLE_CALLBACK_PLUGINS=$(python3 -m ara.setup.callback_plugins)
# Or set all at once using ARA's helper
eval $(python3 -m ara.setup.env)
# Verify it's active
ansible-playbook --list-callbacks | grep ara
Method 3: Ansible Configuration with Environment
# Configure ARA via playbook environment
- name: Run playbook with ARA recording
hosts: all
environment:
ARA_API_CLIENT: "offline"
ARA_DATABASE_NAME: "/var/lib/ara/{{ lookup('pipe', 'date +%Y-%m') }}.sqlite"
tasks:
- name: Example task (will be recorded by ARA)
ansible.builtin.debug:
msg: "This task execution is recorded by ARA"
Using the Web UI
# Start the built-in development server
ara-manage runserver 0.0.0.0:8000
# Access at http://localhost:8000
# For production, use gunicorn
pip install gunicorn
ara-manage migrate
gunicorn --workers 4 --bind 0.0.0.0:8000 ara.server.wsgi
Deploy ARA Server with Ansible
# deploy-ara-server.yml
---
- name: Deploy ARA server
hosts: ara_server
become: true
vars:
ara_db_backend: "django.db.backends.postgresql"
ara_db_name: "ara"
ara_db_user: "ara"
ara_db_password: "{{ vault_ara_db_password }}"
ara_db_host: "localhost"
ara_listen: "0.0.0.0:8000"
ara_workers: 4
tasks:
- name: Install ARA server
ansible.builtin.pip:
name:
- "ara[server]"
- gunicorn
- psycopg2-binary
state: present
- name: Create ARA settings file
ansible.builtin.template:
src: ara-settings.yaml.j2
dest: /etc/ara/settings.yaml
mode: "0640"
notify: Restart ARA
- name: Run database migrations
ansible.builtin.command: ara-manage migrate
environment:
ARA_SETTINGS: /etc/ara/settings.yaml
register: migrate
changed_when: "'Applying' in migrate.stdout"
- name: Create systemd service
ansible.builtin.copy:
content: |
[Unit]
Description=ARA Records Ansible API Server
After=network.target postgresql.service
[Service]
Type=notify
User=ara
Group=ara
Environment=ARA_SETTINGS=/etc/ara/settings.yaml
ExecStart=/usr/local/bin/gunicorn \
--workers {{ ara_workers }} \
--bind {{ ara_listen }} \
ara.server.wsgi
Restart=on-failure
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/ara.service
notify: Restart ARA
- name: Enable and start ARA service
ansible.builtin.systemd:
name: ara
state: started
enabled: true
daemon_reload: true
handlers:
- name: Restart ARA
ansible.builtin.systemd:
name: ara
state: restarted
daemon_reload: true
Using the CLI
# List recent playbooks
ara playbook list
# +----+---------------------+----------+--------+
# | id | started | duration | status |
# +----+---------------------+----------+--------+
# | 1 | 2026-04-15 10:00:00 | 00:02:30 | completed |
# | 2 | 2026-04-15 09:30:00 | 00:05:12 | failed |
# +----+---------------------+----------+--------+
# Show details of a specific playbook run
ara playbook show 1
# List results (tasks) from a playbook
ara result list --playbook 1
# Show failed tasks only
ara result list --status failed
# Show specific task result with full output
ara result show 42
# List hosts and their status
ara host list --playbook 1
# Show facts for a host
ara host show webserver1 --with-facts
# Search across all playbook runs
ara playbook list --label "deploy" --status failed
# Export playbook run as HTML report
ara playbook generate-html 1 --output /tmp/report/
# Delete old records (cleanup)
ara playbook delete 1
ARA with CI/CD
# .github/workflows/ansible.yml (GitHub Actions)
name: Ansible Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Ansible + ARA
run: pip install ansible "ara[server]"
- name: Configure ARA
run: |
mkdir -p ~/.ara
eval $(python3 -m ara.setup.env)
echo "ANSIBLE_CALLBACK_PLUGINS=$(python3 -m ara.setup.callback_plugins)" >> $GITHUB_ENV
- name: Run playbook
run: ansible-playbook -i inventory/production site.yml
- name: Generate ARA report
if: always()
run: |
ara playbook list
ara playbook generate-html --output ara-report/
- name: Upload ARA report
if: always()
uses: actions/upload-artifact@v4
with:
name: ara-report
path: ara-report/
ARA with Centralized Server
# Configure all control nodes to report to central ARA server
# ansible.cfg on each control node
[defaults]
callback_plugins = /path/to/ara/plugins/callback
[ara]
api_client = http
api_server = https://ara.internal.example.com:8000
api_username = ansible-runner
api_password = {{ vault_ara_api_password }}
api_timeout = 30
# On the ARA server — configure authentication
# /etc/ara/settings.yaml
---
default:
READ_LOGIN_REQUIRED: false # Allow anonymous read
WRITE_LOGIN_REQUIRED: true # Require auth to write
EXTERNAL_AUTH: false
DATABASE_ENGINE: django.db.backends.postgresql
DATABASE_NAME: ara
DATABASE_USER: ara
DATABASE_PASSWORD: "{{ ara_db_password }}"
DATABASE_HOST: localhost
DISTRIBUTED_SQLITE: false
PAGE_SIZE: 100
Common Mistakes
# ❌ MISTAKE 1: ARA not recording — callback not loaded
# Check if ARA callback is active:
ansible-playbook --list-callbacks 2>&1 | grep ara
# If missing, verify ANSIBLE_CALLBACK_PLUGINS path
python3 -m ara.setup.callback_plugins
# ❌ MISTAKE 2: Permission error on SQLite database
# Default location: ~/.ara/server/ansible.sqlite
# Fix: Ensure the user running ansible-playbook owns the directory
mkdir -p ~/.ara/server
# Or use a custom location:
export ARA_DATABASE_NAME=/var/lib/ara/ansible.sqlite
# ❌ MISTAKE 3: ARA slowing down playbooks
# ARA adds minimal overhead (~1-2% for offline mode)
# HTTP mode adds network latency per task
# Fix for HTTP mode: use async recording
# [ara]
# api_timeout = 15
# Or batch results (ARA 1.7+)
# ❌ MISTAKE 4: Database growing too large
# Fix: Rotate or prune old records
ara playbook prune --days 90 --confirm
# Or use separate databases per month:
export ARA_DATABASE_NAME=~/.ara/$(date +%Y-%m).sqlite
ARA vs Other Tools
Feature | ARA | AWX/Tower | Ansible Log
─────────────────|───────────────|────────────────|───────────────
Setup complexity | Low (pip) | High (k8s/vm) | None
Web UI | ✅ Yes | ✅ Yes | ❌ No
REST API | ✅ Yes | ✅ Yes | ❌ No
CLI | ✅ Yes | ❌ No | ✅ grep
Auth/RBAC | Basic | Full RBAC | None
Job scheduling | ❌ No | ✅ Yes | ❌ No
Cost | Free | Subscription | Free
Overhead | Minimal | Significant | None
Best for | Recording + | Enterprise | Quick
| browsing | automation | debugging
Related Articles
- Ansible Callback Plugins
- Ansible Troubleshooting
- Ansible CI/CD Pipelines
- Ansible AAP Enterprise
- Ansible Playbook Best Practices
Conclusion
ARA Records Ansible turns ephemeral playbook output into searchable, browsable history. Install it with pip install "ara[server]", enable the callback plugin, and every playbook run is automatically recorded. Use the web UI for browsing, the CLI for scripting, and the REST API for integration. For teams, deploy a central ARA server so all engineers' playbook runs are visible in one place. It's the easiest way to answer "what changed, when, and why" across your Ansible automation.