Add Fleet control plane and split manage.sh deploy menu.
Strategy nodes gain fleet token APIs; control/ app for local ops; manage.sh offers strategy vs control one-click deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
"""本机/本地服务器一键部署中控(git pull + 构建 + pm2 reload)。
|
||||
|
||||
环境变量(可选):
|
||||
CONTROL_ROOT 默认 /opt/eth_hedge_sim(与策略机同仓)或本机仓库根
|
||||
CONTROL_HOST 若设置则 SSH 远程执行;否则在本机执行
|
||||
CONTROL_USER 默认 root
|
||||
CONTROL_PASS SSH 密码(远程时必填)
|
||||
REPO_URL 默认 https://git.bz121.com/dekun/eth_hedge_sim.git
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
HOST = os.environ.get("CONTROL_HOST", "").strip()
|
||||
USER = os.environ.get("CONTROL_USER", "root")
|
||||
PASSWORD = os.environ.get("CONTROL_PASS", "")
|
||||
ROOT = os.environ.get("CONTROL_ROOT", "").strip()
|
||||
REPO = os.environ.get("REPO_URL", "https://git.bz121.com/dekun/eth_hedge_sim.git")
|
||||
|
||||
|
||||
def _default_root() -> Path:
|
||||
# scripts/deploy_control.py -> repo root
|
||||
return Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def local_update(root: Path) -> int:
|
||||
script = root / "control" / "deploy" / "update.sh"
|
||||
if not script.is_file():
|
||||
print(f"missing {script}", file=sys.stderr)
|
||||
return 2
|
||||
if os.name == "nt":
|
||||
print("Run on Linux local server, or set CONTROL_HOST for SSH.", file=sys.stderr)
|
||||
return 2
|
||||
env = {**os.environ, "DEBIAN_FRONTEND": "noninteractive"}
|
||||
proc = subprocess.run(["bash", str(script)], cwd=str(root), env=env)
|
||||
return int(proc.returncode)
|
||||
|
||||
|
||||
def remote_update(root: str) -> int:
|
||||
try:
|
||||
import paramiko
|
||||
except ImportError:
|
||||
print("pip install paramiko", file=sys.stderr)
|
||||
return 2
|
||||
if not PASSWORD:
|
||||
print("Set CONTROL_PASS for remote deploy.", file=sys.stderr)
|
||||
return 2
|
||||
remote = f"""
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
if [[ ! -d '{root}/.git' ]]; then
|
||||
mkdir -p "$(dirname '{root}')"
|
||||
git clone '{REPO}' '{root}'
|
||||
fi
|
||||
bash '{root}/control/deploy/update.sh'
|
||||
curl -fsS http://127.0.0.1:5160/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 control 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
|
||||
print(text, 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:
|
||||
print(err, file=sys.stderr)
|
||||
client.close()
|
||||
print(f"exit={code}")
|
||||
return int(code)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if HOST:
|
||||
root = ROOT or "/opt/eth_hedge_sim"
|
||||
return remote_update(root)
|
||||
root = Path(ROOT) if ROOT else _default_root()
|
||||
return local_update(root)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user