123 lines
3.5 KiB
Python
123 lines
3.5 KiB
Python
"""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())
|