feat: SSH card UX, agent version sync, persistent ssh_admin_ok (0.11.5)
Silent SSH probe on host card open; manual test feedback auto-hides. Persist ssh_admin_ok in DB (migration 019). After agent update read version from host and refresh UI.
This commit is contained in:
@@ -9,7 +9,13 @@ from dataclasses import dataclass
|
||||
from app.models import Host
|
||||
|
||||
SSH_MONITOR_UPDATE_SCRIPT = "/opt/scripts/update_ssh_monitor.sh"
|
||||
SSH_MONITOR_BINARY = "/usr/local/bin/ssh-monitor"
|
||||
SSH_MONITOR_VERSION_CMD = (
|
||||
f"grep -m1 '^SSH_MONITOR_VERSION=' {SSH_MONITOR_BINARY} 2>/dev/null "
|
||||
"| sed -E 's/^SSH_MONITOR_VERSION=[\"'\\'']*([^\"'\\'']+)[\"'\\'']*$/\\1/'"
|
||||
)
|
||||
SSH_OUTPUT_MAX_LEN = 12_000
|
||||
_AGENT_VERSION_RE = re.compile(r"(\d+\.\d+\.\d+(?:-SAC)?)", re.IGNORECASE)
|
||||
_IPV4_RE = re.compile(r"^\d{1,3}(?:\.\d{1,3}){3}$")
|
||||
|
||||
|
||||
@@ -33,6 +39,7 @@ class SshCommandResult:
|
||||
stdout: str = ""
|
||||
stderr: str = ""
|
||||
exit_code: int | None = None
|
||||
agent_version: str | None = None
|
||||
|
||||
|
||||
def is_linux_host(host: Host) -> bool:
|
||||
@@ -233,6 +240,37 @@ def test_ssh_connection(
|
||||
return result
|
||||
|
||||
|
||||
def parse_ssh_monitor_version_text(text: str) -> str | None:
|
||||
if not text:
|
||||
return None
|
||||
match = _AGENT_VERSION_RE.search(text)
|
||||
if not match:
|
||||
return None
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def probe_ssh_monitor_version(
|
||||
*,
|
||||
target: str,
|
||||
user: str,
|
||||
password: str,
|
||||
) -> str | None:
|
||||
result = run_ssh_command(
|
||||
target=target,
|
||||
user=user,
|
||||
password=password,
|
||||
remote_cmd=SSH_MONITOR_VERSION_CMD,
|
||||
command_timeout_sec=30,
|
||||
)
|
||||
if result.ok and result.stdout.strip():
|
||||
version = parse_ssh_monitor_version_text(result.stdout)
|
||||
if version:
|
||||
return version
|
||||
if result.stdout or result.stderr:
|
||||
return parse_ssh_monitor_version_text(f"{result.stdout}\n{result.stderr}")
|
||||
return None
|
||||
|
||||
|
||||
def run_ssh_monitor_update(
|
||||
*,
|
||||
target: str,
|
||||
@@ -258,7 +296,7 @@ def run_ssh_monitor_update(
|
||||
exit_code=probe.exit_code,
|
||||
)
|
||||
|
||||
return run_ssh_command(
|
||||
updated = run_ssh_command(
|
||||
target=target,
|
||||
user=user,
|
||||
password=password,
|
||||
@@ -266,3 +304,21 @@ def run_ssh_monitor_update(
|
||||
command_timeout_sec=900,
|
||||
need_root=True,
|
||||
)
|
||||
if not updated.ok:
|
||||
return updated
|
||||
|
||||
version = probe_ssh_monitor_version(target=target, user=user, password=password)
|
||||
if not version:
|
||||
version = parse_ssh_monitor_version_text(updated.stdout)
|
||||
if version:
|
||||
message = f"{updated.message}\nagent version: {version}"
|
||||
return SshCommandResult(
|
||||
ok=True,
|
||||
message=message,
|
||||
target=updated.target,
|
||||
stdout=updated.stdout,
|
||||
stderr=updated.stderr,
|
||||
exit_code=updated.exit_code,
|
||||
agent_version=version,
|
||||
)
|
||||
return updated
|
||||
|
||||
Reference in New Issue
Block a user