#!/usr/bin/env python3 """从本机 SSH 触发服务器一键更新(服务器内 git pull,不 scp 代码)。 环境变量(可选): DEPLOY_HOST 默认 47.236.184.99 DEPLOY_USER 默认 root DEPLOY_PASS 服务器密码 DEPLOY_ROOT 默认 /opt/eth_hedge_sim REPO_URL 默认 https://git.bz121.com/dekun/eth_hedge_sim.git DEPLOY_MODE update|bootstrap 默认 update(跑 pull_and_restart) bootstrap 时执行 manage 非交互更新路径 """ from __future__ import annotations import os import sys HOST = os.environ.get("DEPLOY_HOST", "47.236.184.99") USER = os.environ.get("DEPLOY_USER", "root") PASSWORD = os.environ.get("DEPLOY_PASS", "") ROOT = os.environ.get("DEPLOY_ROOT", "/opt/eth_hedge_sim") REPO = os.environ.get("REPO_URL", "https://git.bz121.com/dekun/eth_hedge_sim.git") MODE = os.environ.get("DEPLOY_MODE", "update").strip().lower() def main() -> int: if not PASSWORD: print("Set DEPLOY_PASS env var (do not commit password).", file=sys.stderr) return 2 try: import paramiko except ImportError: print("pip install paramiko", file=sys.stderr) return 2 if MODE == "bootstrap": remote = f""" set -euo pipefail export DEBIAN_FRONTEND=noninteractive if [[ ! -d '{ROOT}/.git' ]]; then mkdir -p /opt git clone '{REPO}' '{ROOT}' fi bash '{ROOT}/deploy/pull_and_restart.sh' curl -fsS http://127.0.0.1:5155/health || true """ else: remote = f""" set -euo pipefail if [[ ! -d '{ROOT}/.git' ]]; then mkdir -p /opt git clone '{REPO}' '{ROOT}' fi bash '{ROOT}/deploy/lib/update.sh' curl -fsS http://127.0.0.1:5155/health || true """ client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) print(f"connecting {USER}@{HOST} ...") client.connect(HOST, username=USER, password=PASSWORD, timeout=30) print("running remote pull/update ...") stdin, stdout, stderr = client.exec_command(remote, get_pty=True) while True: chunk = stdout.read(1024) if not chunk: break text = chunk.decode("utf-8", errors="replace") if isinstance(chunk, bytes) else chunk try: print(text, end="", flush=True) except UnicodeEncodeError: print(text.encode("ascii", errors="replace").decode("ascii"), end="", flush=True) err_raw = stderr.read() err = err_raw.decode("utf-8", errors="replace") if isinstance(err_raw, bytes) else err_raw code = stdout.channel.recv_exit_status() if err: try: print(err, file=sys.stderr) except UnicodeEncodeError: print(err.encode("ascii", errors="replace").decode("ascii"), file=sys.stderr) client.close() print(f"exit={code}") return code if __name__ == "__main__": raise SystemExit(main())