fix: Clean Up now deletes entire session directory tmp/{guid}/

- Backend cleanup_staging accepts session_id, deletes whole
  STAGING_ROOT/{guid}/ dir when provided
- CleanupRequest model gets session_id field
- Frontend cleanup proxy passes session_id from body
- api_client passes session_id to backend
- reuseImage JS includes session_id in cleanup payload
This commit is contained in:
Claus Lohmar 2026-07-23 10:54:42 +00:00
parent 90bf8e4842
commit 6db69f434c
6 changed files with 26 additions and 8 deletions

View file

@ -162,7 +162,7 @@ def cleanup_job(job_id: str, req: CleanupRequest) -> CleanupResponse:
except (IndexError, ValueError):
vmid = 0
logger.info("Cleanup: job=%s vmid=%d delete=%s", job_id, vmid, req.delete_staging_files)
result = cleanup_staging(vmid, req.delete_staging_files)
result = cleanup_staging(vmid, req.delete_staging_files, req.session_id)
return CleanupResponse(
job_id=result["job_id"],
action_taken=result["action_taken"],

View file

@ -62,6 +62,7 @@ class JobSubmissionRequest(BaseModel):
class CleanupRequest(BaseModel):
delete_staging_files: bool
session_id: str = ""
# ---------------------------------------------------------------------------

View file

@ -125,9 +125,8 @@ def clone_vm(req: CloneRequest) -> JobStatusResponse:
def cleanup_staging(vmid: int, delete: bool, session_id: str = "") -> dict:
"""Remove staging files for a VM ID."""
out_dir = _staging_out(session_id) / str(vmid)
"""Remove staging files. If delete=True and session_id is set,
removes the entire session directory (both in/ and out/)."""
if not delete:
return {
"job_id": f"job_{vmid}",
@ -135,6 +134,20 @@ def cleanup_staging(vmid: int, delete: bool, session_id: str = "") -> dict:
"message": f"Staging files preserved for VM {vmid}",
}
# Delete the entire session tmp directory if we have a session ID
if session_id:
session_dir = STAGING_ROOT / session_id
if session_dir.exists():
shutil.rmtree(session_dir, ignore_errors=True)
logger.info("Cleaned up session dir: %s", session_dir)
return {
"job_id": f"job_{vmid}",
"action_taken": "purged",
"message": "Session files deleted.",
}
# Fallback: delete just the VM output dir
out_dir = _staging_out(session_id) / str(vmid)
if out_dir.exists():
shutil.rmtree(out_dir, ignore_errors=True)
logger.info("Cleaned up output dir: %s", out_dir)

View file

@ -59,9 +59,12 @@ class ApiClient:
"""GET /api/v1/jobs/{job_id} — poll job status."""
return self._get(f"/api/v1/jobs/{job_id}")
def cleanup_job(self, job_id: str, delete: bool) -> dict:
def cleanup_job(self, job_id: str, delete: bool, session_id: str = "") -> dict:
"""POST /api/v1/jobs/{job_id}/cleanup — remove or keep staging files."""
return self._post(f"/api/v1/jobs/{job_id}/cleanup", {"delete_staging_files": delete})
return self._post(f"/api/v1/jobs/{job_id}/cleanup", {
"delete_staging_files": delete,
"session_id": session_id,
})
def clone_vm(self, source_vmid: int, target_vmid: int, target_name: str) -> dict:
"""POST /api/v1/clone — clone an existing VM."""

View file

@ -519,7 +519,8 @@ async def session_cleanup(job_id: str, request: Request):
try:
body = await request.json()
delete = body.get("delete_staging_files", False)
return api.cleanup_job(job_id, delete)
session_id = body.get("session_id", "")
return api.cleanup_job(job_id, delete, session_id)
except ApiError as exc:
return JSONResponse({"error": exc.detail}, status_code=502)

View file

@ -371,7 +371,7 @@ async function reuseImage(jobId, vmid, sourceFilename, keep) {
try {
await fetch('/session/cleanup/' + jobId, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ delete_staging_files: true }),
body: JSON.stringify({ delete_staging_files: true, session_id: window.VM_BENCH_SID || '' }),
});
window.location.href = '/';
} catch (err) { alert('Cleanup failed: ' + err.message); }