"""Deploy guest-chat to test.pubuli.com (100.31.73.254) on port 7777.""" from __future__ import annotations import os import sys import time import paramiko HOST = os.environ.get("DEPLOY_HOST", "100.31.73.254") USER = os.environ.get("DEPLOY_USER", "wakka") PASSWORD = os.environ["DEPLOY_PASSWORD"] REMOTE_DIR = "/home/wakka/guest-cs-stack" LOCAL_STACK = os.path.dirname(os.path.abspath(__file__)) 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", ] INSTALL_DOCKER = r""" set -e if ! command -v docker >/dev/null 2>&1; then echo "[install] docker..." sudo apt-get update -qq sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker.io docker-compose-v2 sudo usermod -aG docker wakka || true fi docker --version docker compose version """ DEPLOY = rf""" set -euo pipefail cd {REMOTE_DIR} echo "[deploy] stop old processes on 7777/7788..." fuser -k 7777/tcp 2>/dev/null || true fuser -k 7788/tcp 2>/dev/null || true pkill -f "python app.py" 2>/dev/null || true pkill -f "python.*7788" 2>/dev/null || true pkill -f "python.*7777" 2>/dev/null || true sleep 2 echo "[deploy] pull..." sudo docker pull ladioussuapp/guest-chat:latest echo "[deploy] up..." sudo docker compose -f docker-compose.chat.yaml -f docker-compose.chat.test7777.yaml down 2>/dev/null || true sudo docker compose -f docker-compose.chat.yaml -f docker-compose.chat.test7777.yaml up -d --force-recreate sleep 30 sudo docker compose -f docker-compose.chat.yaml -f docker-compose.chat.test7777.yaml ps curl -sI http://127.0.0.1:7777/guest-customer-service | head -8 """ 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 try_connect(host: str, user: str, password: str) -> paramiko.SSHClient | None: try: c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect(host, username=user, password=password, timeout=20, allow_agent=False, look_for_keys=False) return c except Exception as exc: print(f"connect {user}@{host} failed: {exc}") return None def main() -> int: users = [USER, "root", "ubuntu", "admin"] c = None for u in dict.fromkeys(users): c = try_connect(HOST, u, PASSWORD) if c: print(f"connected as {u}@{HOST}") break if not c: return 1 run(c, "hostname; whoami; ss -tlnp | grep -E '7777|7788' || true") run(c, INSTALL_DOCKER, timeout=900) c.close() time.sleep(1) c = try_connect(HOST, USER if c else users[0], PASSWORD) if not c: return 1 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(f"uploaded {name}") sftp.close() code, out, _ = run(c, DEPLOY, timeout=900) # bootstrap if empty db if "Server: gunicorn" not in out: run(c, f"chmod +x {REMOTE_DIR}/bootstrap-chatwoot.sh && bash {REMOTE_DIR}/bootstrap-chatwoot.sh", timeout=300) run(c, DEPLOY, timeout=900) c.close() return code if __name__ == "__main__": raise SystemExit(main())