#!/usr/bin/env bash set -e # ============================================================================== # Plane Installation & Deployment Script for cisystem # Target Directory: /home/ubuntu/plane # Port: 127.0.0.1:8090 (Routed by Nginx to jira.tradhox.com) # ============================================================================== INSTALL_DIR="/home/ubuntu/plane" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" echo "==> [1/6] Initializing Plane directory structure at ${INSTALL_DIR}..." mkdir -p "${INSTALL_DIR}/patches" mkdir -p "${INSTALL_DIR}/logs" "${INSTALL_DIR}/logs/api" "${INSTALL_DIR}/logs/worker" "${INSTALL_DIR}/logs/beat-worker" "${INSTALL_DIR}/logs/migrator" "${INSTALL_DIR}/logs/web" "${INSTALL_DIR}/logs/proxy" chmod -R 777 "${INSTALL_DIR}/logs" 2>/dev/null || true "${INSTALL_DIR}/logs" # Verify .env exists and sync database credentials if [ -f "${INSTALL_DIR}/.env" ]; then echo "==> Updating database settings in existing ${INSTALL_DIR}/.env..." python3 -c ' import re, os env_file = "'"${INSTALL_DIR}/.env"'" updates = { "PGHOST": "host.docker.internal", "POSTGRES_HOST": "host.docker.internal", "POSTGRES_USER": "vignesh", "POSTGRES_PASSWORD": "vignesh_secret_pass_2026", "DATABASE_URL": "postgresql://vignesh:vignesh_secret_pass_2026@host.docker.internal:5432/plane" } if os.path.exists(env_file): with open(env_file, "r") as f: content = f.read() for k, v in updates.items(): pattern = re.compile(rf"^{k}=.*$", re.MULTILINE) if pattern.search(content): content = pattern.sub(f"{k}={v}", content) else: content += f"\n{k}={v}\n" with open(env_file, "w") as f: f.write(content) ' elif [ -f "${SCRIPT_DIR}/.env.example" ]; then echo "Notice: Creating initial .env from .env.example..." cp "${SCRIPT_DIR}/.env.example" "${INSTALL_DIR}/.env" fi echo "==> [2/6] Syncing docker-compose, scripts and runtime patches..." if [ "${SCRIPT_DIR}" != "${INSTALL_DIR}" ]; then cp "${SCRIPT_DIR}/docker-compose.yml" "${INSTALL_DIR}/docker-compose.yml" if [ -f "${SCRIPT_DIR}/logs.sh" ]; then cp "${SCRIPT_DIR}/logs.sh" "${INSTALL_DIR}/logs.sh" fi if [ -d "${SCRIPT_DIR}/patches" ]; then cp -r "${SCRIPT_DIR}/patches/"* "${INSTALL_DIR}/patches/" fi else echo "Already inside target directory ${INSTALL_DIR}." fi chmod +x "${INSTALL_DIR}/logs.sh" 2>/dev/null || true cd "${INSTALL_DIR}" echo "==> [3/6] Loading or Pulling Docker images..." if [ -f "source.tar.gz" ]; then echo "==> Extracting source code..." mkdir -p source-build tar -xzf source.tar.gz -C source-build rm source.tar.gz echo "==> Building custom Docker images from source on EC2..." cd source-build docker build -t makeplane/plane-frontend:stable -f apps/web/Dockerfile.web . docker build -t makeplane/plane-backend:stable -f apps/api/Dockerfile.api apps/api/ cd .. rm -rf source-build echo "==> Pulling remaining images (stable)..." docker compose pull space admin live plane-redis plane-mq proxy else echo "==> Pulling all Docker images..." docker compose pull web space admin live api worker beat-worker migrator plane-redis plane-mq proxy fi echo "==> [4/6] Executing database migrations..." docker compose run --rm migrator echo "==> Generating frontend Enterprise patches..." if [ -f "${INSTALL_DIR}/patches/patch_frontend.py" ]; then python3 "${INSTALL_DIR}/patches/patch_frontend.py" "${INSTALL_DIR}/patches" || true fi echo "==> [5/6] Starting Plane containers without touching other host services..." docker compose up -d --remove-orphans echo "==> [6/6] Verifying service health..." HEALTHY=false for i in $(seq 1 45); do STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8090/ || true) if [ "$STATUS" = "200" ] || [ "$STATUS" = "302" ]; then echo "✓ Plane is healthy! HTTP Status: $STATUS (http://127.0.0.1:8090/)" HEALTHY=true break fi echo "Waiting for Plane to be ready (attempt $i/45, status: $STATUS)..." sleep 2 done if [ "$HEALTHY" != "true" ]; then echo "ERROR: Plane did not respond with 200/302 within 90 seconds. Checking logs:" docker compose logs --tail=50 proxy api web exit 1 fi echo "==> Verifying existing cisystem services are undisturbed..." for s in "3000:Forgejo" "3001:Docmost" "8084:OnlyOffice Portal" "8083:OnlyOffice Engine"; do PORT="${s%%:*}" NAME="${s##*:}" CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:${PORT}/" || true) echo " - ${NAME} (Port ${PORT}): HTTP ${CODE}" done echo "✓ Plane installation / deployment completed successfully!"