feat: live update log in UI and suppress lifecycle Telegram during SAC update
Poll remote update_script.log while SSH update runs; skip lifecycle notify when host agent_update_state is running (SAC v0.5.1).
This commit is contained in:
@@ -16,7 +16,7 @@ from app.services.agent_update import execute_agent_update_fallback
|
||||
from app.services.agent_update_types import AgentUpdateFallbackResult
|
||||
from app.services.linux_admin_settings import get_effective_linux_admin_config
|
||||
from app.services.agent_update_settings import get_effective_agent_update_config
|
||||
from app.services.ssh_connect import iter_ssh_targets, run_ssh_monitor_update, SshCommandResult
|
||||
from app.services.ssh_connect import iter_ssh_targets, run_ssh_monitor_update, SshCommandResult, tail_ssh_monitor_update_log
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -113,12 +113,61 @@ def _apply_ssh_update_result(db: Session, host: Host, result: SshCommandResult)
|
||||
host.agent_update_last_error = (result.message or "SSH update failed")[:2000]
|
||||
|
||||
|
||||
_REMOTE_LOG_POLL_SEC = 2.0
|
||||
|
||||
|
||||
def _poll_ssh_update_log_loop(
|
||||
host_id: int,
|
||||
*,
|
||||
stop: threading.Event,
|
||||
) -> None:
|
||||
"""Периодически подтягивает tail update_script.log в hosts.remote_action для UI."""
|
||||
while not stop.wait(_REMOTE_LOG_POLL_SEC):
|
||||
session = SessionLocal()
|
||||
try:
|
||||
row = session.get(Host, host_id)
|
||||
if row is None or row.agent_update_state != "running":
|
||||
continue
|
||||
cfg = get_effective_linux_admin_config(session)
|
||||
if not cfg.configured:
|
||||
continue
|
||||
try:
|
||||
targets = iter_ssh_targets(row)
|
||||
except Exception:
|
||||
continue
|
||||
tail = ""
|
||||
for target in targets:
|
||||
try:
|
||||
tail = tail_ssh_monitor_update_log(
|
||||
target=target,
|
||||
user=cfg.user,
|
||||
password=cfg.password,
|
||||
)
|
||||
except Exception:
|
||||
logger.debug("update log tail failed host_id=%s target=%s", host_id, target, exc_info=True)
|
||||
continue
|
||||
if tail:
|
||||
break
|
||||
payload = dict(row.remote_action or {})
|
||||
if tail:
|
||||
payload["output"] = tail
|
||||
payload["message"] = "Выполняется обновление… (лог с хоста)"
|
||||
row.remote_action = payload
|
||||
session.commit()
|
||||
except Exception:
|
||||
logger.debug("remote log poll failed host_id=%s", host_id, exc_info=True)
|
||||
session.rollback()
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
|
||||
def start_host_remote_action(
|
||||
db: Session,
|
||||
host: Host,
|
||||
*,
|
||||
title: str,
|
||||
runner: ActionRunner,
|
||||
poll_remote_log: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
host_id = int(host.id)
|
||||
with _lock:
|
||||
@@ -133,6 +182,17 @@ def start_host_remote_action(
|
||||
|
||||
def _worker() -> None:
|
||||
session = SessionLocal()
|
||||
stop_poll = threading.Event()
|
||||
poll_thread: threading.Thread | None = None
|
||||
if poll_remote_log and runner is run_ssh_monitor_update_action:
|
||||
poll_thread = threading.Thread(
|
||||
target=_poll_ssh_update_log_loop,
|
||||
args=(host_id,),
|
||||
kwargs={"stop": stop_poll},
|
||||
name=f"sac-remote-log-{host_id}",
|
||||
daemon=True,
|
||||
)
|
||||
poll_thread.start()
|
||||
try:
|
||||
row = session.get(Host, host_id)
|
||||
if row is None:
|
||||
@@ -167,6 +227,9 @@ def start_host_remote_action(
|
||||
}
|
||||
session.commit()
|
||||
finally:
|
||||
stop_poll.set()
|
||||
if poll_thread is not None:
|
||||
poll_thread.join(timeout=5.0)
|
||||
session.close()
|
||||
with _lock:
|
||||
_running.discard(host_id)
|
||||
|
||||
Reference in New Issue
Block a user