feat: sichere Ansible-Tuning-Aktionen #15

Merged
sascha merged 2 commits from feat/safe-ansible-tuning-actions into main 2026-08-08 22:43:24 +02:00
Showing only changes of commit 964774ca6b - Show all commits

25
app.py
View file

@ -11,7 +11,7 @@ from fastapi.responses import JSONResponse, RedirectResponse
from contextlib import asynccontextmanager
log = logging.getLogger("butler")
VERSION = "2.3.3"
VERSION = "2.3.4"
API_DIR = os.environ.get("API_KEY_DIR", "/data/api")
VAULT_CACHE_DIR = os.environ.get("VAULT_CACHE_DIR", "/data/vault-cache")
@ -1567,10 +1567,29 @@ print("updated" if updated else "added")'''
async def ansible_run(request: Request, _=Depends(_verify)):
body = await request.json()
hostname = body.get("limit", body.get("hostname", ""))
template_id = body.get("template_id", 10)
if not hostname:
return JSONResponse({"error": "limit/hostname required"}, status_code=400)
rc, out, err = _ssh(AUTOMATION1, f"cd /app-config/ansible && bash pfannkuchen.sh setup {hostname}", timeout=600)
action = body.get("action", "setup")
if action not in {"setup", "tune", "pvetune"}:
return JSONResponse({"error": "action must be setup, tune or pvetune"}, status_code=400)
if not re.fullmatch(r"[a-zA-Z0-9_.:-]+", hostname):
return JSONResponse({"error": "invalid hostname/limit"}, status_code=400)
command = (
"cd /app-config/ansible && "
"git pull --ff-only origin master && "
f"bash pfannkuchen.sh {action} {hostname}"
)
rc, out, err = _ssh(AUTOMATION1, command, timeout=600)
_audit("/ansible/run", "POST", 200 if rc == 0 else 502, f"{action} {hostname}")
if action != "setup":
return {
"status": "ok" if rc == 0 else "error",
"action": action,
"hostname": hostname,
"rc": rc,
"output": out[-4000:],
"error": err[-1000:] if rc != 0 else "",
}
# After successful ansible run: sync Hawser token to Dockhand
if rc == 0: