fix: remote job stuck after SSH update completes (v0.5.4)
Treat agent_update_state as source of truth for active job; poll log thread no longer overwrites finished status.
This commit is contained in:
@@ -126,7 +126,10 @@ def _poll_ssh_update_log_loop(
|
|||||||
session = SessionLocal()
|
session = SessionLocal()
|
||||||
try:
|
try:
|
||||||
row = session.get(Host, host_id)
|
row = session.get(Host, host_id)
|
||||||
if row is None or row.agent_update_state != "running":
|
if row is None or (row.agent_update_state or "").strip().lower() != "running":
|
||||||
|
continue
|
||||||
|
payload = dict(row.remote_action or {})
|
||||||
|
if (payload.get("status") or "").strip().lower() != "running":
|
||||||
continue
|
continue
|
||||||
cfg = get_effective_linux_admin_config(session)
|
cfg = get_effective_linux_admin_config(session)
|
||||||
if not cfg.configured:
|
if not cfg.configured:
|
||||||
@@ -148,7 +151,12 @@ def _poll_ssh_update_log_loop(
|
|||||||
continue
|
continue
|
||||||
if tail:
|
if tail:
|
||||||
break
|
break
|
||||||
|
session.refresh(row)
|
||||||
|
if (row.agent_update_state or "").strip().lower() != "running":
|
||||||
|
continue
|
||||||
payload = dict(row.remote_action or {})
|
payload = dict(row.remote_action or {})
|
||||||
|
if (payload.get("status") or "").strip().lower() != "running":
|
||||||
|
continue
|
||||||
if tail:
|
if tail:
|
||||||
payload["output"] = tail
|
payload["output"] = tail
|
||||||
payload["message"] = "Выполняется обновление… (лог с хоста)"
|
payload["message"] = "Выполняется обновление… (лог с хоста)"
|
||||||
@@ -339,8 +347,16 @@ def get_remote_action_status(host: Host) -> dict[str, Any]:
|
|||||||
payload = dict(host.remote_action or {})
|
payload = dict(host.remote_action or {})
|
||||||
if not payload:
|
if not payload:
|
||||||
return {"active": False, "host_id": host.id}
|
return {"active": False, "host_id": host.id}
|
||||||
|
agent_state = (host.agent_update_state or "").strip().lower()
|
||||||
|
if agent_state == "running":
|
||||||
|
active = True
|
||||||
|
status = payload.get("status") or "running"
|
||||||
|
elif agent_state in ("success", "failed"):
|
||||||
|
active = False
|
||||||
|
status = payload.get("status") or agent_state
|
||||||
|
else:
|
||||||
status = payload.get("status") or host.agent_update_state or "unknown"
|
status = payload.get("status") or host.agent_update_state or "unknown"
|
||||||
active = status == "running" or host.agent_update_state == "running"
|
active = status == "running"
|
||||||
return {
|
return {
|
||||||
"active": active,
|
"active": active,
|
||||||
"host_id": host.id,
|
"host_id": host.id,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
||||||
|
|
||||||
APP_NAME = "Security Alert Center"
|
APP_NAME = "Security Alert Center"
|
||||||
APP_VERSION = "0.5.3"
|
APP_VERSION = "0.5.4"
|
||||||
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
||||||
|
|||||||
@@ -247,6 +247,30 @@ def test_clear_stale_running_remote_actions(db_session):
|
|||||||
assert host.remote_action["ok"] is False
|
assert host.remote_action["ok"] is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_remote_action_status_ignores_stale_running_payload(db_session):
|
||||||
|
from app.services.host_remote_actions import get_remote_action_status
|
||||||
|
|
||||||
|
host = Host(
|
||||||
|
hostname="done-linux",
|
||||||
|
os_family="linux",
|
||||||
|
product="ssh-monitor",
|
||||||
|
agent_update_state="success",
|
||||||
|
remote_action={
|
||||||
|
"status": "running",
|
||||||
|
"message": "Выполняется обновление… (лог с хоста)",
|
||||||
|
"output": "=== Script update completed successfully ===",
|
||||||
|
"ok": True,
|
||||||
|
"finished_at": "2026-07-08T02:21:11+00:00",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
db_session.add(host)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
status = get_remote_action_status(host)
|
||||||
|
assert status["active"] is False
|
||||||
|
assert status["agent_update_state"] == "success"
|
||||||
|
|
||||||
|
|
||||||
def test_cancel_host_remote_job_api(jwt_headers, client, db_session):
|
def test_cancel_host_remote_job_api(jwt_headers, client, db_session):
|
||||||
host = Host(
|
host = Host(
|
||||||
hostname="cancel-me",
|
hostname="cancel-me",
|
||||||
|
|||||||
Reference in New Issue
Block a user