fix(l4d2-web): server delete job now removes the DB row

The delete job ran l4d2ctl delete (host-side cleanup) but never removed the
Server row, so deleted servers kept appearing on /servers. Hard-delete the
row in the worker's success path and skip the post-op status refresh, since
the systemd unit is gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
mwiegand 2026-05-08 18:09:45 +02:00
parent fb3c6be052
commit c8a2d563ce
No known key found for this signature in database
2 changed files with 47 additions and 0 deletions

View file

@ -311,6 +311,15 @@ def run_job(job_id: int) -> None:
on_stderr=on_stderr,
should_cancel=should_cancel,
)
# Host-side cleanup succeeded; remove the DB row so the server
# disappears from /servers. Status refresh is skipped — the
# systemd unit is gone and querying it would just log noise.
with session_scope() as db:
server = db.scalar(select(Server).where(Server.id == server_id))
if server is not None:
db.delete(server)
finish_job(job_id, "succeeded", 0)
return
else:
raise ValueError(f"unknown job operation: {operation}")

View file

@ -260,6 +260,44 @@ def test_unexpected_exception_fails_job_with_exit_code_one(seeded_worker, monkey
job = load_job(job_id)
assert job.state == "failed"
assert job.exit_code == 1
# Failed delete must keep the Server row.
with session_scope() as session:
assert session.scalar(select(Server).where(Server.id == ids.server_one)) is not None
def test_successful_delete_removes_server_row(seeded_worker, monkeypatch) -> None:
app, ids = seeded_worker
job_id = add_job(ids.user, "delete", server_id=ids.server_one)
calls = []
def fake_delete(server_id, *, on_stdout=None, on_stderr=None, should_cancel=None):
del should_cancel
calls.append(server_id)
on_stdout("removing systemd unit")
def fake_status(name): # pragma: no cover — would mean delete didn't skip refresh
pytest.fail(f"server_status must not be called after a successful delete (got {name!r})")
monkeypatch.setattr(l4d2_facade, "delete_server", fake_delete)
monkeypatch.setattr(l4d2_facade, "server_status", fake_status)
with app.app_context():
assert run_worker_once() is True
assert calls == [ids.server_one]
job = load_job(job_id)
assert job.state == "succeeded"
assert job.exit_code == 0
with session_scope() as session:
assert session.scalar(select(Server).where(Server.id == ids.server_one)) is None
# Sibling server is untouched.
assert session.scalar(select(Server).where(Server.id == ids.server_two)) is not None
# The delete job itself stays in the job log; outerjoin in views shows
# "-" for its (now-orphaned) server_id pointer.
finished_job = session.scalar(select(Job).where(Job.id == job_id))
assert finished_job is not None
assert finished_job.server_id == ids.server_one
def test_same_server_jobs_do_not_overlap(seeded_worker, monkeypatch) -> None: