ExposedGays: map, shop, auth, Supabase schema, Coolify Dockerfile
This commit is contained in:
237
deploy/setup-infra.py
Normal file
237
deploy/setup-infra.py
Normal file
@@ -0,0 +1,237 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Push ExposedGays to Gitea, create Coolify app, apply Supabase schema."""
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
try:
|
||||
import paramiko
|
||||
except ImportError:
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "paramiko", "-q"])
|
||||
import paramiko
|
||||
|
||||
HOST = "10.10.0.10"
|
||||
SUPA_HOST = "10.10.0.11"
|
||||
USER = "localadministrator"
|
||||
PASS = os.environ.get("COOLIFY_SSH_PASS", "Bbt9115xty9176!")
|
||||
GITEA_TOKEN = os.environ.get("GITEA_TOKEN", "dbf033cee4b0e3be5699f374a15f3fa240e2896a")
|
||||
COOLIFY_TOKEN = os.environ.get("COOLIFY_TOKEN", "1|zALRdpUD3VkejNVlEV5UuRzTeoYVhshZtke5VkCNa6e9262d")
|
||||
REPO_NAME = "exposedgays"
|
||||
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
GIT_AUTH = f"https://{USER}:{GITEA_TOKEN}@gitea.onsethost.com/localadministrator/{REPO_NAME}.git"
|
||||
|
||||
|
||||
def ssh_run(host, cmd, timeout=120):
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect(host, username=USER, password=PASS, timeout=20, allow_agent=False, look_for_keys=False)
|
||||
print(f"[{host}] $ {cmd[:120]}")
|
||||
_, o, e = c.exec_command(cmd, timeout=timeout)
|
||||
code = o.channel.recv_exit_status()
|
||||
out = (o.read() + e.read()).decode(errors="replace")
|
||||
if out.strip():
|
||||
print(out[-8000:])
|
||||
print(f"exit={code}")
|
||||
c.close()
|
||||
return code, out
|
||||
|
||||
|
||||
def gitea_api(method, path, data=None):
|
||||
url = f"https://gitea.onsethost.com/api/v1{path}"
|
||||
body = json.dumps(data).encode() if data else None
|
||||
req = urllib.request.Request(url, data=body, method=method)
|
||||
req.add_header("Authorization", f"token {GITEA_TOKEN}")
|
||||
req.add_header("Content-Type", "application/json")
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
return resp.status, json.loads(resp.read().decode())
|
||||
except urllib.error.HTTPError as ex:
|
||||
body = ex.read().decode()
|
||||
try:
|
||||
return ex.code, json.loads(body)
|
||||
except Exception:
|
||||
return ex.code, {"message": body}
|
||||
|
||||
|
||||
def coolify_api(method, path, data=None):
|
||||
url = f"https://coolify.onsethost.com/api/v1{path}"
|
||||
body = json.dumps(data).encode() if data else None
|
||||
req = urllib.request.Request(url, data=body, method=method)
|
||||
req.add_header("Authorization", f"Bearer {COOLIFY_TOKEN}")
|
||||
req.add_header("Content-Type", "application/json")
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=60) as resp:
|
||||
raw = resp.read().decode()
|
||||
return resp.status, json.loads(raw) if raw else {}
|
||||
except urllib.error.HTTPError as ex:
|
||||
body = ex.read().decode()
|
||||
try:
|
||||
return ex.code, json.loads(body)
|
||||
except Exception:
|
||||
return ex.code, {"message": body}
|
||||
|
||||
|
||||
def push_gitea():
|
||||
print("\n=== 1. Create Gitea repo (if missing) ===")
|
||||
code, resp = gitea_api("POST", "/user/repos", {
|
||||
"name": REPO_NAME,
|
||||
"private": True,
|
||||
"auto_init": False,
|
||||
"description": "ExposedGays — free gay cruising + shop",
|
||||
})
|
||||
if code in (201, 409):
|
||||
print(f"Repo ready (HTTP {code})")
|
||||
else:
|
||||
print(f"Repo create: {code} {resp}")
|
||||
|
||||
print("\n=== 2. Git commit + push from COOLIFY_01 ===")
|
||||
schema_sql = open(os.path.join(PROJECT_ROOT, "supabase", "schema.sql"), encoding="utf-8").read()
|
||||
functions_sql = open(os.path.join(PROJECT_ROOT, "supabase", "functions.sql"), encoding="utf-8").read()
|
||||
|
||||
# Tar project and upload via SSH
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect(HOST, username=USER, password=PASS, timeout=20, allow_agent=False, look_for_keys=False)
|
||||
sftp = c.open_sftp()
|
||||
|
||||
import tarfile
|
||||
import io
|
||||
buf = io.BytesIO()
|
||||
with tarfile.open(fileobj=buf, mode="w:gz") as tar:
|
||||
for root, dirs, files in os.walk(PROJECT_ROOT):
|
||||
dirs[:] = [d for d in dirs if d not in (".next", "node_modules", ".git")]
|
||||
for f in files:
|
||||
if f in (".env.local",):
|
||||
continue
|
||||
full = os.path.join(root, f)
|
||||
arc = os.path.relpath(full, PROJECT_ROOT)
|
||||
tar.add(full, arcname=arc)
|
||||
buf.seek(0)
|
||||
sftp.putfo(buf, "/tmp/exposedgays.tar.gz")
|
||||
sftp.close()
|
||||
|
||||
cmds = [
|
||||
"rm -rf /tmp/exposedgays && mkdir -p /tmp/exposedgays && tar -xzf /tmp/exposedgays.tar.gz -C /tmp/exposedgays",
|
||||
f"cd /tmp/exposedgays && git init -b main && git config user.email 'ryan.salazar@justtworoommates.com' && git config user.name 'Ryan Salazar'",
|
||||
"cd /tmp/exposedgays && git add -A && git commit -m 'ExposedGays: map, shop, auth, Supabase schema' || true",
|
||||
f"cd /tmp/exposedgays && git remote remove origin 2>/dev/null; git remote add origin {GIT_AUTH}",
|
||||
f"cd /tmp/exposedgays && git push -u origin main --force",
|
||||
]
|
||||
for cmd in cmds:
|
||||
_, o, e = c.exec_command(cmd, timeout=180)
|
||||
code = o.channel.recv_exit_status()
|
||||
out = (o.read() + e.read()).decode(errors="replace")
|
||||
print(out[-3000:])
|
||||
print(f"exit={code}")
|
||||
c.close()
|
||||
return GIT_AUTH.replace(GITEA_TOKEN, "***")
|
||||
|
||||
|
||||
def apply_supabase_schema():
|
||||
print("\n=== 3. Apply Supabase schema on SUPABASE_01 ===")
|
||||
schema_path = os.path.join(PROJECT_ROOT, "supabase", "schema.sql")
|
||||
func_path = os.path.join(PROJECT_ROOT, "supabase", "functions.sql")
|
||||
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect(SUPA_HOST, username=USER, password=PASS, timeout=20, allow_agent=False, look_for_keys=False)
|
||||
sftp = c.open_sftp()
|
||||
sftp.put(schema_path, "/tmp/eg_schema.sql")
|
||||
sftp.put(func_path, "/tmp/eg_functions.sql")
|
||||
sftp.close()
|
||||
|
||||
cmd = (
|
||||
"docker exec -i supabase-db psql -U postgres -d postgres "
|
||||
"-f /dev/stdin < /tmp/eg_schema.sql 2>&1; "
|
||||
"docker exec -i supabase-db psql -U postgres -d postgres "
|
||||
"-f /dev/stdin < /tmp/eg_functions.sql 2>&1"
|
||||
)
|
||||
# Copy into container first
|
||||
for f in ("eg_schema.sql", "eg_functions.sql"):
|
||||
c.exec_command(f"docker cp /tmp/{f} supabase-db:/tmp/{f}")
|
||||
import time
|
||||
time.sleep(2)
|
||||
_, o, e = c.exec_command(
|
||||
"docker exec supabase-db psql -U postgres -d postgres -f /tmp/eg_schema.sql 2>&1; "
|
||||
"docker exec supabase-db psql -U postgres -d postgres -f /tmp/eg_functions.sql 2>&1",
|
||||
timeout=120,
|
||||
)
|
||||
out = (o.read() + e.read()).decode(errors="replace")
|
||||
print(out[-5000:])
|
||||
c.close()
|
||||
|
||||
|
||||
def create_coolify_app(git_url_auth):
|
||||
print("\n=== 4. Create Coolify application ===")
|
||||
# List projects
|
||||
code, projects = coolify_api("GET", "/projects")
|
||||
print(f"Projects: {code}")
|
||||
project_uuid = None
|
||||
if code == 200 and projects:
|
||||
items = projects if isinstance(projects, list) else projects.get("data", projects)
|
||||
if items:
|
||||
project_uuid = items[0].get("uuid") or items[0].get("id")
|
||||
print(f"Using project: {project_uuid}")
|
||||
|
||||
payload = {
|
||||
"project_uuid": project_uuid,
|
||||
"server_uuid": None,
|
||||
"environment_name": "production",
|
||||
"git_repository": f"https://gitea.onsethost.com/localadministrator/{REPO_NAME}.git",
|
||||
"git_branch": "main",
|
||||
"build_pack": "dockerfile",
|
||||
"dockerfile_location": "/Dockerfile",
|
||||
"ports_exposes": "3000",
|
||||
"name": "exposedgays",
|
||||
"description": "ExposedGays — free cruising + shop",
|
||||
"domains": "https://exposedgays.com,https://www.exposedgays.com",
|
||||
"instant_deploy": True,
|
||||
}
|
||||
|
||||
code, resp = coolify_api("POST", "/applications/public", payload)
|
||||
print(f"Create app: HTTP {code}")
|
||||
print(json.dumps(resp, indent=2)[:3000])
|
||||
|
||||
app_uuid = resp.get("uuid") if isinstance(resp, dict) else None
|
||||
if not app_uuid and isinstance(resp, dict):
|
||||
app_uuid = resp.get("id")
|
||||
|
||||
if app_uuid:
|
||||
print(f"\n=== 5. Set env vars on {app_uuid} ===")
|
||||
envs = [
|
||||
("NEXT_PUBLIC_SUPABASE_URL", "https://supabase.onsethost.com"),
|
||||
("NEXT_PUBLIC_SUPABASE_ANON_KEY", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzc2NzEzOTczLCJleHAiOjIwOTIwNzM5NzN9.oRPm6uJt4Gj-ASOixznas7-IC1pCtlZtEFew-SmY9wo"),
|
||||
("NEXT_PUBLIC_APP_URL", "https://exposedgays.com"),
|
||||
("NEXT_PUBLIC_DEFAULT_CITY", "Fort Lauderdale"),
|
||||
("NEXT_PUBLIC_DEFAULT_LAT", "26.1224"),
|
||||
("NEXT_PUBLIC_DEFAULT_LNG", "-80.1373"),
|
||||
]
|
||||
for key, value in envs:
|
||||
c, r = coolify_api("POST", f"/applications/{app_uuid}/envs", {"key": key, "value": value})
|
||||
print(f" {key}: HTTP {c}")
|
||||
|
||||
print("\n=== 6. Trigger deploy ===")
|
||||
code, dep = coolify_api("POST", f"/deploy?uuid={app_uuid}&force_rebuild=true")
|
||||
print(f"Deploy: HTTP {code} {dep}")
|
||||
|
||||
return app_uuid
|
||||
|
||||
|
||||
def main():
|
||||
git_url = push_gitea()
|
||||
try:
|
||||
apply_supabase_schema()
|
||||
except Exception as ex:
|
||||
print(f"Supabase schema warning: {ex}")
|
||||
app_uuid = create_coolify_app(git_url)
|
||||
print("\n=== DONE ===")
|
||||
print(f"Gitea: https://gitea.onsethost.com/localadministrator/{REPO_NAME}")
|
||||
print(f"Coolify app: {app_uuid or 'check Coolify UI'}")
|
||||
print("Next: add exposedgays.com to Cloudflare tunnel → Coolify container")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user