delete jen vytvoří job

This commit is contained in:
JiriUhlir
2026-06-22 13:51:48 +02:00
parent bd256d565c
commit 1a88ca57f9
2 changed files with 30 additions and 13 deletions
+5 -1
View File
@@ -1,5 +1,9 @@
DEPLOY_SCRIPT = "/tools/deploy-app.sh" DEPLOY_SCRIPT = "/tools/deploy-app.sh"
DELETE_APP_SCRIPT = "/tools/delete-app.sh" # Mazání aplikace NEPROVÁDÍ portál přímo běží bez práv k workspace, takže rm padá na
# "Permission denied". Portál jen zařadí run_script job a Worker spustí tento skript
# v appfactory-tools s právy serveru. Prefix "scripts/" je povinný, jinak ho worker hledá
# ve špatné složce (stejná konvence jako app/routes/runtime.py).
DELETE_APP_SCRIPT_NAME = "scripts/delete-app.sh"
BACKUP_SCRIPT = "/tools/backup-appfactory.sh" BACKUP_SCRIPT = "/tools/backup-appfactory.sh"
RESTORE_SCRIPT = "/tools/restore-appfactory.sh" RESTORE_SCRIPT = "/tools/restore-appfactory.sh"
GENERATE_COMPOSE_SCRIPT = "/tools/generate-apps-compose.sh" GENERATE_COMPOSE_SCRIPT = "/tools/generate-apps-compose.sh"
+25 -12
View File
@@ -8,7 +8,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse
from ..auth import is_admin, is_developer, require_admin, require_developer, require_user from ..auth import is_admin, is_developer, require_admin, require_developer, require_user
from ..config import ( from ..config import (
DEFAULT_GITEA_ORG, DEFAULT_GITEA_ORG,
DELETE_APP_SCRIPT, DELETE_APP_SCRIPT_NAME,
DEPLOY_SCRIPT, DEPLOY_SCRIPT,
GENERATE_COMPOSE_SCRIPT, GENERATE_COMPOSE_SCRIPT,
get_appfactory_host, get_appfactory_host,
@@ -405,7 +405,7 @@ def apps_page(
) )
delete_icon = ( delete_icon = (
f""" f"""
<form method="post" action="/portal/delete-app" onsubmit="return confirm('Smazat {app_id}? Tím se odstraní kontejner, image, workspace, záznam v katalogu a Gitea repozitář.');"> <form method="post" action="/portal/delete-app" onsubmit="return confirm('Smazat {app_id}? Worker odstraní kontejner, image, workspace, záznam v katalogu a Gitea repozitář. Akce se zařadí jako job.');">
<input type="hidden" name="app_id" value="{app_id}"> <input type="hidden" name="app_id" value="{app_id}">
<button type="submit" class="icon-action icon-action-danger" title="Smazat" aria-label="Smazat"> <button type="submit" class="icon-action icon-action-danger" title="Smazat" aria-label="Smazat">
<i class="fa-solid fa-trash" aria-hidden="true"></i> <i class="fa-solid fa-trash" aria-hidden="true"></i>
@@ -1520,8 +1520,23 @@ def create_app(
@router.post("/delete-app", response_class=HTMLResponse) @router.post("/delete-app", response_class=HTMLResponse)
def delete_app(app_id: str = Form(...), user=Depends(require_admin)): def delete_app(app_id: str = Form(...), user=Depends(require_admin)):
result = run_command([DELETE_APP_SCRIPT, app_id]) # Portál NEMAŽE workspace přímo nemá k němu práva (rm padá na "Permission denied").
status = "OK" if result.returncode == 0 else "FAILED" # Místo toho zařadí run_script job; mazání (container, image, gitea repo, workspace)
# provede Worker přes scripts/delete-app.sh s právy serveru. Veškerá runtime/Docker
# logika patří do Workeru a shell skriptů, ne do portálu.
payload = {
"script_name": DELETE_APP_SCRIPT_NAME,
"args": [app_id],
"arguments": [app_id],
}
job_id = create_job(
job_type="run_script",
target_type="app",
target_id=app_id,
payload=payload,
user=user,
source="portal",
)
log_audit_event( log_audit_event(
user, user,
action="delete_app", action="delete_app",
@@ -1529,17 +1544,15 @@ def delete_app(app_id: str = Form(...), user=Depends(require_admin)):
target_id=app_id, target_id=app_id,
metadata={ metadata={
"app_id": app_id, "app_id": app_id,
"status": status, "status": "QUEUED",
"returncode": result.returncode, "script_name": DELETE_APP_SCRIPT_NAME,
"job_id": job_id,
}, },
) )
return render_result( # Worker zpracuje job asynchronně; pošleme uživatele rovnou na detail jobu, ať vidí
title=f"Smazání služby: {status}", # živé logy mazání a výsledek.
back_url="/portal/apps", return RedirectResponse(url=f"/portal/jobs/{job_id}", status_code=303)
sections=[("Výstup", result.stdout), ("Chyba", result.stderr)],
user=user,
)
@router.post("/update-resources", response_class=HTMLResponse) @router.post("/update-resources", response_class=HTMLResponse)