133 lines
5.5 KiB
Bash
Executable File
133 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# -------------------------------------------------------------
|
||
# Staging Deploy & Orchestration Helper for NexusReader
|
||
# -------------------------------------------------------------
|
||
set -e
|
||
|
||
NEXUS_ONLY=false
|
||
for arg in "$@"; do
|
||
case $arg in
|
||
--nexus-only|-n)
|
||
NEXUS_ONLY=true
|
||
;;
|
||
esac
|
||
done
|
||
|
||
ENV_FILE=".env.stage"
|
||
TEMPLATE_FILE=".env.stage.template"
|
||
COMPOSE_FILE="docker-compose.stage.yml"
|
||
|
||
echo "🏁 Starting staging environment orchestration..."
|
||
if [ "$NEXUS_ONLY" = true ]; then
|
||
echo "ℹ️ Mode: --nexus-only (only the web/nexus application container will be modified)"
|
||
fi
|
||
|
||
# 1. Create .env.stage if it doesn't exist
|
||
if [ ! -f "$ENV_FILE" ]; then
|
||
if [ -f "$TEMPLATE_FILE" ]; then
|
||
echo "📄 Creating $ENV_FILE from $TEMPLATE_FILE..."
|
||
cp "$TEMPLATE_FILE" "$ENV_FILE"
|
||
else
|
||
echo "❌ Error: Template file $TEMPLATE_FILE not found."
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# 2. Check and generate secure random passwords for placeholders
|
||
if grep -q "CHANGE_ME_TO_STRONG_PASSWORD" "$ENV_FILE"; then
|
||
echo "🔐 Generating secure random passwords in $ENV_FILE..."
|
||
PG_PASS=$(openssl rand -hex 16)
|
||
NEO_PASS=$(openssl rand -hex 16)
|
||
# Use standard sed compatible with Linux
|
||
sed -i "s/POSTGRES_PASSWORD=CHANGE_ME_TO_STRONG_PASSWORD/POSTGRES_PASSWORD=$PG_PASS/g" "$ENV_FILE"
|
||
sed -i "s/NEO4J_PASSWORD=CHANGE_ME_TO_STRONG_PASSWORD/NEO4J_PASSWORD=$NEO_PASS/g" "$ENV_FILE"
|
||
fi
|
||
|
||
if grep -q "CHANGE_ME_TO_SECURE_ADMIN_PASSWORD" "$ENV_FILE"; then
|
||
echo "🔐 Generating secure admin seed password in $ENV_FILE..."
|
||
ADMIN_PASS=$(openssl rand -hex 16)
|
||
sed -i "s/NEXUS_ADMIN_PASSWORD=CHANGE_ME_TO_SECURE_ADMIN_PASSWORD/NEXUS_ADMIN_PASSWORD=$ADMIN_PASS/g" "$ENV_FILE"
|
||
fi
|
||
|
||
if grep -q "^QDRANT_API_KEY=$" "$ENV_FILE" || grep -q "^QDRANT_API_KEY=[[:space:]]*$" "$ENV_FILE"; then
|
||
echo "🔐 Generating secure random Qdrant API key in $ENV_FILE..."
|
||
QD_KEY=$(openssl rand -hex 16)
|
||
sed -i "s/^QDRANT_API_KEY=.*/QDRANT_API_KEY=$QD_KEY/g" "$ENV_FILE"
|
||
fi
|
||
|
||
# Load staging variables for local execution context (needed for ports/migrations)
|
||
# Clean up carriage returns just in case
|
||
POSTGRES_USER=$(grep "^POSTGRES_USER=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '\r')
|
||
POSTGRES_PASSWORD=$(grep "^POSTGRES_PASSWORD=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '\r')
|
||
POSTGRES_DB=$(grep "^POSTGRES_DB=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '\r')
|
||
POSTGRES_PORT=$(grep "^POSTGRES_PORT=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '\r')
|
||
WEB_PORT=$(grep "^WEB_PORT=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '\r')
|
||
QDRANT_HTTP_PORT=$(grep "^QDRANT_HTTP_PORT=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '\r')
|
||
NEO4J_HTTP_PORT=$(grep "^NEO4J_HTTP_PORT=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '\r')
|
||
|
||
# Fallbacks in case env parsing is empty
|
||
POSTGRES_PORT=${POSTGRES_PORT:-5438}
|
||
WEB_PORT=${WEB_PORT:-5080}
|
||
|
||
# 3. Stop any conflicting Docker Compose environments
|
||
if [ "$NEXUS_ONLY" = true ]; then
|
||
echo "🧹 Stopping and removing only the web (nexus) container..."
|
||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" stop web || true
|
||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" rm -f web || true
|
||
else
|
||
echo "🧹 Stopping existing containers..."
|
||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" down --remove-orphans || true
|
||
docker compose down --remove-orphans 2>/dev/null || true
|
||
fi
|
||
|
||
# 4. Build and start containers
|
||
if [ "$NEXUS_ONLY" = true ]; then
|
||
echo "🚀 Building and restarting only the web (nexus) container..."
|
||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --build web
|
||
else
|
||
echo "🚀 Building and starting staging containers..."
|
||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --build
|
||
fi
|
||
|
||
# 5. Wait for Database to be healthy
|
||
echo "⏳ Waiting for database (nexus-db-stage) to become healthy..."
|
||
MAX_ATTEMPTS=30
|
||
attempt=0
|
||
until [ "$(docker inspect --format='{{json .State.Health.Status}}' nexus-db-stage 2>/dev/null)" == "\"healthy\"" ]; do
|
||
sleep 2
|
||
attempt=$((attempt + 1))
|
||
if [ $attempt -ge $MAX_ATTEMPTS ]; then
|
||
echo "❌ Timeout: Database container never became healthy."
|
||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs db
|
||
exit 1
|
||
fi
|
||
done
|
||
echo "✅ Database is healthy!"
|
||
|
||
# 6. Apply Entity Framework migrations
|
||
echo "🔄 Applying EF Core migrations to staging database on port $POSTGRES_PORT..."
|
||
export ConnectionStrings__PostgresConnection="Host=127.0.0.1;Port=$POSTGRES_PORT;Database=$POSTGRES_DB;Username=$POSTGRES_USER;Password=$POSTGRES_PASSWORD"
|
||
dotnet ef database update --project src/NexusReader.Data --startup-project src/NexusReader.Web --no-build
|
||
|
||
# 7. Wait for Web Application to respond
|
||
echo "⏳ Waiting for Web Application to start on http://localhost:$WEB_PORT/health..."
|
||
MAX_WEB_ATTEMPTS=30
|
||
web_attempt=0
|
||
until curl -s -f "http://localhost:$WEB_PORT/health" >/dev/null; do
|
||
sleep 2
|
||
web_attempt=$((web_attempt + 1))
|
||
if [ $web_attempt -ge $MAX_WEB_ATTEMPTS ]; then
|
||
echo "⚠️ Warning: Web app is not responding yet on http://localhost:$WEB_PORT/health, but let's check logs..."
|
||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs web
|
||
break
|
||
fi
|
||
done
|
||
|
||
echo "🎉 Staging environment is ready!"
|
||
echo "--------------------------------------------------------"
|
||
echo "🌐 Web Application: http://localhost:$WEB_PORT"
|
||
echo "🗄️ PostgreSQL Port: $POSTGRES_PORT"
|
||
echo "🔎 Neo4j Console: http://localhost:$NEO4J_HTTP_PORT"
|
||
echo "📊 Qdrant Service: http://localhost:$QDRANT_HTTP_PORT"
|
||
echo "--------------------------------------------------------"
|