fix(ansible): git sources work in the image and survive a redeploy; pulls time out; alert vars go in a JSON file (#5157)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 49s
CI / unit (push) Successful in 1m11s
CI / publish (push) Successful in 1m3s

- git ships in the image; checkouts live under /data/ansible/sources
  (STEWARD_ANSIBLE_SOURCE_DIR), on the persistent volume.
- One task, ansible_git_pulls, reads the sources every 30 s and pulls each
  as its interval passes: a source added in Settings is pulled without a
  restart, a removed one is forgotten.
- git_pull: a 120 s timeout ending the process group, GIT_TERMINAL_PROMPT=0,
  pull --ff-only, a failed clone removed; it raises GitPullError with git's
  message, so the Sync button stops saying Synced after a failure (and the
  message is now escaped).
- An alert action's vars and the firing's steward_alert_* vars reach
  ansible-playbook as one JSON extra-vars file, not -e key=value, which
  Ansible split on whitespace (a rule named 'High CPU on web').

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 21:13:14 -04:00
co-authored by Claude Opus 5.5
parent d2ade9c1c7
commit edcfa4d3db
8 changed files with 265 additions and 89 deletions
+13 -18
View File
@@ -434,26 +434,21 @@ def _register_core_tasks(app: Quart) -> None:
),
])
# Register git-pull tasks for each ansible git source
ansible_cfg = app.config.get("ANSIBLE", {})
from .ansible.sources import get_sources
for source in get_sources(ansible_cfg):
if source["type"] != "git":
continue
_source = source
# Pull Ansible git sources as each falls due. One task reads the sources
# as they are on every tick, so one added in Settings is pulled within
# half a minute, no restart (#5157).
async def run_git_pulls():
from .ansible.sources import pull_due_sources
await pull_due_sources(app.config.get("ANSIBLE", {}))
async def run_git_pull(src=_source):
from .ansible.sources import git_pull
await git_pull(src)
app._task_registry.append(
ScheduledTask(
name=f"ansible_git_pull_{_source['name']}",
coro_factory=run_git_pull,
interval_seconds=_source["pull_interval_seconds"],
run_on_startup=True,
)
app._task_registry.append(
ScheduledTask(
name="ansible_git_pulls",
coro_factory=run_git_pulls,
interval_seconds=30,
run_on_startup=True,
)
)
# Fire due Ansible schedules (recurring playbook runs). Checks every minute;
# each schedule's own interval gates whether it actually runs.