feat: bootstrap ssh-monitor updater when missing on host (0.20.2)

SAC now clones the ssh-monitor repo and installs update_ssh_monitor.sh before running the update when the remote updater script is absent.
This commit is contained in:
PTah
2026-06-20 17:01:06 +10:00
parent 07b97bd111
commit c21043d845
5 changed files with 146 additions and 26 deletions
+63 -12
View File
@@ -9,6 +9,9 @@ from dataclasses import dataclass
from app.models import Host
SSH_MONITOR_UPDATE_SCRIPT = "/opt/scripts/update_ssh_monitor.sh"
SSH_MONITOR_UPDATE_DIR = "/opt/scripts/update"
SSH_MONITOR_REPO_NAME = "ssh-monitor"
SSH_MONITOR_UPDATE_REPO_URL = "https://git.kalinamall.ru/PapaTramp/ssh-monitor.git"
SSH_MONITOR_BINARY = "/usr/local/bin/ssh-monitor"
SSH_MONITOR_VERSION_CMD = (
f"grep -m1 '^SSH_MONITOR_VERSION=' {SSH_MONITOR_BINARY} 2>/dev/null "
@@ -271,13 +274,30 @@ def probe_ssh_monitor_version(
return None
def _ssh_monitor_bootstrap_command(repo_url: str) -> str:
"""Clone ssh-monitor repo and install updater when /opt/scripts/update_ssh_monitor.sh is absent."""
safe_repo = repo_url.replace("\\", "\\\\").replace('"', '\\"')
return (
f'UPDATE_DIR="{SSH_MONITOR_UPDATE_DIR}";'
f'REPO_URL="{safe_repo}";'
f'SCRIPT_NAME="{SSH_MONITOR_REPO_NAME}";'
f'INSTALL="{SSH_MONITOR_UPDATE_SCRIPT}";'
f'mkdir -p "$UPDATE_DIR" && cd "$UPDATE_DIR" && '
f'([ -d "$SCRIPT_NAME" ] || git clone "$REPO_URL" "$SCRIPT_NAME") && '
f'cp "$UPDATE_DIR/$SCRIPT_NAME/update_ssh_monitor.sh" "$INSTALL" && '
f'chmod 750 "$INSTALL" && "$INSTALL"'
)
def run_ssh_monitor_update(
*,
target: str,
user: str,
password: str,
repo_url: str | None = None,
) -> SshCommandResult:
script = SSH_MONITOR_UPDATE_SCRIPT
effective_repo = (repo_url or SSH_MONITOR_UPDATE_REPO_URL).strip()
check_cmd = f"test -x {script} && echo ready || echo missing"
probe = run_ssh_command(
target=target,
@@ -286,32 +306,54 @@ def run_ssh_monitor_update(
remote_cmd=check_cmd,
command_timeout_sec=30,
)
if not probe.ok or "missing" in probe.stdout:
if not probe.ok:
return SshCommandResult(
ok=False,
message=f"Update script not found or not executable: {script} on {target}",
message=f"SSH probe failed on {target}: {probe.message}",
target=target,
stdout=probe.stdout,
stderr=probe.stderr,
exit_code=probe.exit_code,
)
updated = run_ssh_command(
target=target,
user=user,
password=password,
remote_cmd=script,
command_timeout_sec=900,
need_root=True,
)
bootstrapped = False
if "missing" in probe.stdout:
bootstrap_cmd = _ssh_monitor_bootstrap_command(effective_repo)
updated = run_ssh_command(
target=target,
user=user,
password=password,
remote_cmd=bootstrap_cmd,
command_timeout_sec=900,
need_root=True,
)
bootstrapped = True
else:
updated = run_ssh_command(
target=target,
user=user,
password=password,
remote_cmd=script,
command_timeout_sec=900,
need_root=True,
)
if not updated.ok:
return updated
prefix = "Updater bootstrap failed" if bootstrapped else "SSH update failed"
return SshCommandResult(
ok=False,
message=f"{prefix} ({target}): {updated.message}",
target=updated.target,
stdout=updated.stdout,
stderr=updated.stderr,
exit_code=updated.exit_code,
)
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}"
prefix = "Bootstrap + update OK" if bootstrapped else updated.message
message = f"{prefix}\nagent version: {version}"
return SshCommandResult(
ok=True,
message=message,
@@ -321,4 +363,13 @@ def run_ssh_monitor_update(
exit_code=updated.exit_code,
agent_version=version,
)
if bootstrapped:
return SshCommandResult(
ok=True,
message=f"Bootstrap + update OK ({target}), exit 0",
target=updated.target,
stdout=updated.stdout,
stderr=updated.stderr,
exit_code=updated.exit_code,
)
return updated