185 lines
5.5 KiB
Bash
185 lines
5.5 KiB
Bash
#!/bin/bash
|
|
# Docker entrypoint script for PPR API
|
|
# Handles database migrations and data seeding automatically
|
|
|
|
# Note: We don't use 'set -e' here because we need to handle specific exit codes from Python scripts
|
|
|
|
echo "========================================="
|
|
echo "PPR API Container Starting"
|
|
echo "========================================="
|
|
|
|
# Wait for database to be ready
|
|
echo "Waiting for database to be ready..."
|
|
python3 << EOF
|
|
import sys
|
|
import time
|
|
from sqlalchemy import create_engine, text
|
|
from app.core.config import settings
|
|
|
|
max_retries = 30
|
|
retry_interval = 2
|
|
|
|
for i in range(max_retries):
|
|
try:
|
|
engine = create_engine(settings.database_url)
|
|
with engine.connect() as conn:
|
|
conn.execute(text("SELECT 1"))
|
|
print("✓ Database is ready")
|
|
sys.exit(0)
|
|
except Exception as e:
|
|
if i < max_retries - 1:
|
|
print(f"Database not ready yet (attempt {i+1}/{max_retries}), waiting...")
|
|
time.sleep(retry_interval)
|
|
else:
|
|
print(f"✗ Database connection failed after {max_retries} attempts: {e}")
|
|
sys.exit(1)
|
|
EOF
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed to connect to database. Exiting."
|
|
exit 1
|
|
fi
|
|
|
|
# Check if this is a fresh database or needs migration
|
|
echo ""
|
|
echo "Checking database state..."
|
|
|
|
python3 << EOF
|
|
import sys
|
|
from sqlalchemy import create_engine, text, inspect
|
|
from app.core.config import settings
|
|
|
|
try:
|
|
engine = create_engine(settings.database_url)
|
|
inspector = inspect(engine)
|
|
|
|
# Check if any tables exist
|
|
tables = inspector.get_table_names()
|
|
|
|
if not tables:
|
|
print("✓ Fresh database detected - will initialize")
|
|
sys.exit(2) # Signal fresh database
|
|
elif 'alembic_version' not in tables:
|
|
print("✓ Existing database without migration tracking - will stamp")
|
|
sys.exit(3) # Signal existing database needs stamping
|
|
else:
|
|
print("✓ Database has migration tracking - will check for updates")
|
|
sys.exit(0) # Normal migration check
|
|
|
|
except Exception as e:
|
|
print(f"✗ Error checking database: {e}")
|
|
sys.exit(1)
|
|
EOF
|
|
|
|
DB_STATE=$?
|
|
|
|
if [ $DB_STATE -eq 2 ]; then
|
|
# Fresh database - run initial migration
|
|
echo ""
|
|
echo "Initializing fresh database..."
|
|
cd /app
|
|
alembic upgrade head
|
|
echo "✓ Database schema created"
|
|
|
|
# Seed reference data
|
|
echo ""
|
|
echo "Loading reference data..."
|
|
python3 /app/seed_data.py
|
|
echo "✓ Reference data loaded"
|
|
|
|
elif [ $DB_STATE -eq 3 ]; then
|
|
# Existing database without Alembic - stamp it
|
|
echo ""
|
|
echo "Stamping existing database with migration version..."
|
|
cd /app
|
|
alembic stamp head
|
|
echo "✓ Database stamped"
|
|
|
|
# Check if reference data exists
|
|
python3 << EOF
|
|
from sqlalchemy import create_engine, text
|
|
from app.core.config import settings
|
|
|
|
engine = create_engine(settings.database_url)
|
|
with engine.connect() as conn:
|
|
airport_count = conn.execute(text("SELECT COUNT(*) FROM airports")).fetchone()[0]
|
|
aircraft_count = conn.execute(text("SELECT COUNT(*) FROM aircraft")).fetchone()[0]
|
|
|
|
if airport_count == 0 or aircraft_count == 0:
|
|
print("Reference data missing - will load")
|
|
exit(10)
|
|
else:
|
|
print(f"Reference data exists (airports: {airport_count}, aircraft: {aircraft_count})")
|
|
exit(0)
|
|
EOF
|
|
|
|
if [ $? -eq 10 ]; then
|
|
echo "Loading reference data..."
|
|
python3 /app/seed_data.py
|
|
echo "✓ Reference data loaded"
|
|
fi
|
|
|
|
elif [ $DB_STATE -eq 0 ]; then
|
|
# Database with Alembic tracking - check for pending migrations
|
|
echo ""
|
|
echo "Checking for pending migrations..."
|
|
cd /app
|
|
|
|
# Get current and head revisions
|
|
CURRENT=$(alembic current 2>/dev/null | grep -o '[a-f0-9]\{12\}' | head -1 || echo "none")
|
|
HEAD=$(alembic heads 2>/dev/null | grep -o '[a-f0-9]\{12\}' | head -1 || echo "none")
|
|
|
|
if [ "$CURRENT" != "$HEAD" ] && [ "$HEAD" != "none" ]; then
|
|
echo "✓ Pending migrations detected"
|
|
echo " Current: $CURRENT"
|
|
echo " Target: $HEAD"
|
|
echo "Applying migrations..."
|
|
alembic upgrade head
|
|
echo "✓ Migrations applied"
|
|
else
|
|
echo "✓ Database is up to date"
|
|
fi
|
|
|
|
# Check if reference data needs to be loaded
|
|
python3 << EOF
|
|
from sqlalchemy import create_engine, text
|
|
from app.core.config import settings
|
|
|
|
engine = create_engine(settings.database_url)
|
|
with engine.connect() as conn:
|
|
airport_count = conn.execute(text("SELECT COUNT(*) FROM airports")).fetchone()[0]
|
|
aircraft_count = conn.execute(text("SELECT COUNT(*) FROM aircraft")).fetchone()[0]
|
|
|
|
if airport_count == 0 or aircraft_count == 0:
|
|
print("Reference data missing - will load")
|
|
exit(10)
|
|
else:
|
|
print(f"Reference data exists (airports: {airport_count}, aircraft: {aircraft_count})")
|
|
exit(0)
|
|
EOF
|
|
|
|
if [ $? -eq 10 ]; then
|
|
echo "Loading reference data..."
|
|
python3 /app/seed_data.py
|
|
echo "✓ Reference data loaded"
|
|
fi
|
|
else
|
|
echo "✗ Database check failed"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo "========================================="
|
|
echo "Starting Application Server"
|
|
echo "========================================="
|
|
echo ""
|
|
|
|
# Start the application with appropriate settings
|
|
if [ "${ENVIRONMENT}" = "production" ]; then
|
|
echo "Starting in PRODUCTION mode with multiple workers..."
|
|
exec uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers ${WORKERS:-4}
|
|
else
|
|
echo "Starting in DEVELOPMENT mode with auto-reload..."
|
|
exec uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
|
|
fi
|