Sweeps README, docs/, example configs, code docstrings, report and notification subject lines, plugin catalog URL default, and stray comments in Dockerfile/entrypoint.sh/.gitignore. Adds a legacy note to docs/core/configuration.md explaining the FABLEDSCRYER_* fallback. docker-compose DB credentials intentionally left as fabledscryer to preserve the existing pgdata volume.
4.2 KiB
Ansible Integration
Roundtable can browse, trigger, and stream output from Ansible playbooks directly from the web UI. Runs execute as asyncio tasks inside the same process — no Celery, no external workers.
Playbook Sources
Sources are configured at /settings/ under Ansible. Two source types are supported:
Local Filesystem
Points to a directory on the host that already contains playbooks.
# In app_settings (configured via UI)
ansible.sources:
- name: "homelab"
type: local
path: "/opt/playbooks"
Git Repository
The app clones or pulls the repo into a local cache directory on a configurable schedule. All execution uses the local cache.
ansible.sources:
- name: "infra-repo"
type: git
url: "https://github.com/example/infra.git"
branch: "main"
pull_interval_seconds: 300
cache_path: "/data/playbook_cache/infra-repo"
Git sources register a ScheduledTask named ansible_git_pull_<name> that runs git pull on the configured interval.
Inventory Discovery
The app discovers inventory files within the root of the playbook source directory (non-recursive). It looks for files named:
hostsinventoryinventory.ymlinventory.ini
A manual relative path can also be entered in the UI (e.g. inventories/production/hosts) for inventories in subdirectories.
Triggering a Run
From the UI at /ansible/, you can:
- Browse available playbooks across all sources
- View playbook contents before running
- Select an inventory file
- Trigger a run (requires
operatororviewerrole — execution is restricted tooperator/admin)
The run flow:
- UI submits
POST /ansible/runswithplaybook_path,source_name, andinventory_path - An
AnsibleRunrow is created withstatus = running - Playbook execution starts as
asyncio.create_task() - The response returns the
run_idand an HTMX partial that wires the SSE subscription - The browser connects to
GET /ansible/runs/<run_id>/streamto receive live output
SSE Streaming
Run output is streamed to the browser via Server-Sent Events (SSE) at:
GET /ansible/runs/<run_id>/stream
Each output line is sent as:
event: output
data: <line of stdout/stderr>
Run completion:
event: done
data: success|failed|interrupted
Output is flushed to the ansible_runs.output DB column every 50 lines or every 5 seconds (whichever comes first) and always on completion. This means partial output survives a process crash.
If a client connects after the run has already completed, the endpoint immediately sends event: done with the final status and closes the stream. To view stored output, use the run history view at GET /ansible/runs/<run_id>.
Run Lifecycle
| Status | Description |
|---|---|
running |
Execution in progress |
success |
Playbook exited 0 |
failed |
Playbook exited non-zero |
interrupted |
App restarted while run was in progress |
On startup, the app marks any runs still in running state as interrupted (see _mark_interrupted_runs() in app.py).
Output stored in the DB is capped at 1 MB. If truncated, [output truncated] is appended to the DB column, but the live SSE stream continues unaffected.
Data Model
ansible_runs table (defined in roundtable/models/ansible.py):
| Column | Type | Description |
|---|---|---|
id |
UUID | Primary key |
playbook_path |
str | Relative path to playbook |
inventory_path |
str | Inventory path used |
source_name |
str | Name of the playbook source |
triggered_by |
FK → users | |
status |
enum | running, success, failed, interrupted |
started_at |
timestamp UTC | |
finished_at |
timestamp UTC | Null if still running |
output |
text | Captured stdout/stderr (capped at 1 MB) |
Runs older than data.retention_days (default 90) are pruned by the data_cleanup scheduled task.
Source Files
| File | Purpose |
|---|---|
roundtable/ansible/sources.py |
Source discovery, git pull logic |
roundtable/ansible/executor.py |
Subprocess execution and output streaming |
roundtable/ansible/routes.py |
HTTP routes (browse, trigger, stream, history) |
roundtable/models/ansible.py |
AnsibleRun model |