import os import sys import time import paramiko HOST = "20.191.152.26" USER = "wakka" PASSWORD = os.environ["DEPLOY_PASSWORD"] REMOTE_DIR = "/home/wakka/guest-cs-stack" LOCAL_STACK = os.path.dirname(os.path.abspath(__file__)) # 目标:本地 127.0.0.1:7788 同款 → test.pubuli.com:7777(hostname: wakka-test-server) COMPOSE = "docker-compose.chat.yaml -f docker-compose.chat.test7777.yaml" FILES = [ "docker-compose.chat.yaml", "docker-compose.chat.test7777.yaml", "chatwoot.env", "guest-cs.env", "guest-cs.test.env", "deploy-test7777.sh", "bootstrap-chatwoot-test.sh", ] DEPLOY = rf""" set -euo pipefail cd {REMOTE_DIR} chmod +x deploy-test7777.sh bootstrap-chatwoot-test.sh 2>/dev/null || true echo "[deploy] stop old processes..." fuser -k 7777/tcp 7788/tcp 2>/dev/null || true pkill -f "python app.py" 2>/dev/null || true sleep 2 echo "[deploy] pull..." sudo docker pull ladioussuapp/guest-chat:latest echo "[deploy] up..." sudo docker compose -f {COMPOSE} down 2>/dev/null || true sudo docker compose -f {COMPOSE} up -d --force-recreate sleep 30 sudo docker compose -f {COMPOSE} ps curl -sI http://127.0.0.1:7777/guest-customer-service | head -10 """ def run(client, cmd, timeout=900): print("\n>>>", cmd[:140].replace("\n", " ")) _, o, e = client.exec_command(cmd, timeout=timeout) out = o.read().decode("utf-8", errors="replace") err = e.read().decode("utf-8", errors="replace") code = o.channel.recv_exit_status() if out: print(out) if err: print(err, file=sys.stderr) return code, out, err def main(): c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect(HOST, username=USER, password=PASSWORD, timeout=30) run(c, "hostname; ss -tlnp | grep -E '7777|7788' || true") run(c, f"mkdir -p {REMOTE_DIR}") sftp = c.open_sftp() for name in FILES: sftp.put(os.path.join(LOCAL_STACK, name), f"{REMOTE_DIR}/{name}") print("uploaded", name) sftp.close() code, out, _ = run(c, DEPLOY, timeout=900) if "Server: gunicorn" not in out and "200 OK" in out: pass elif "Server: gunicorn" not in out: run(c, f"cd {REMOTE_DIR} && bash bootstrap-chatwoot-test.sh", timeout=300) code, out, _ = run(c, DEPLOY, timeout=900) # 若 bootstrap 产生新 token,打印供更新 guest-cs.test.env run( c, "sudo docker exec guest-chat-postgres-1 psql -U postgres -d chatwoot_production -t -c " "\"SELECT website_token FROM channel_web_widgets LIMIT 1;\" 2>/dev/null || true", timeout=60, ) run(c, "sudo docker exec guest-chat printenv | grep CHATWOOT_GUEST", timeout=60) c.close() return code if __name__ == "__main__": raise SystemExit(main())