306 lines
9.0 KiB
Bash
306 lines
9.0 KiB
Bash
#!/bin/bash
|
||
|
||
# ================================================================================================
|
||
# ENHANCED TECH STACK SELECTOR - DOCKER STARTUP SCRIPT
|
||
# Optimized for Docker environment with proper service discovery
|
||
# ================================================================================================
|
||
|
||
set -e
|
||
|
||
# Parse command line arguments
|
||
FORCE_MIGRATION=false
|
||
if [ "$1" = "--force-migration" ] || [ "$1" = "-f" ]; then
|
||
FORCE_MIGRATION=true
|
||
echo "🔄 Force migration mode enabled"
|
||
elif [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
|
||
echo "Usage: $0 [OPTIONS]"
|
||
echo ""
|
||
echo "Options:"
|
||
echo " --force-migration, -f Force re-run all migrations"
|
||
echo " --help, -h Show this help message"
|
||
echo ""
|
||
echo "Examples:"
|
||
echo " $0 # Normal startup with auto-migration detection"
|
||
echo " $0 --force-migration # Force re-run all migrations"
|
||
exit 0
|
||
fi
|
||
|
||
echo "="*60
|
||
echo "🚀 ENHANCED TECH STACK SELECTOR v15.0 - DOCKER VERSION"
|
||
echo "="*60
|
||
echo "✅ PostgreSQL data migrated to Neo4j"
|
||
echo "✅ Price-based relationships"
|
||
echo "✅ Real data from PostgreSQL"
|
||
echo "✅ Comprehensive pricing analysis"
|
||
echo "✅ Docker-optimized startup"
|
||
echo "="*60
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Function to print colored output
|
||
print_status() {
|
||
echo -e "${GREEN}✅ $1${NC}"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}❌ $1${NC}"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||
}
|
||
|
||
# Get environment variables with defaults
|
||
POSTGRES_HOST=${POSTGRES_HOST:-postgres}
|
||
POSTGRES_PORT=${POSTGRES_PORT:-5432}
|
||
POSTGRES_USER=${POSTGRES_USER:-pipeline_admin}
|
||
POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-secure_pipeline_2024}
|
||
POSTGRES_DB=${POSTGRES_DB:-dev_pipeline}
|
||
NEO4J_URI=${NEO4J_URI:-bolt://neo4j:7687}
|
||
NEO4J_USER=${NEO4J_USER:-neo4j}
|
||
NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||
CLAUDE_API_KEY=${CLAUDE_API_KEY:-}
|
||
|
||
print_status "Environment variables loaded"
|
||
print_info "PostgreSQL: ${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}"
|
||
print_info "Neo4j: ${NEO4J_URI}"
|
||
|
||
# Function to wait for service to be ready
|
||
wait_for_service() {
|
||
local service_name=$1
|
||
local host=$2
|
||
local port=$3
|
||
local max_attempts=30
|
||
local attempt=1
|
||
|
||
print_info "Waiting for ${service_name} to be ready..."
|
||
|
||
while [ $attempt -le $max_attempts ]; do
|
||
if nc -z $host $port 2>/dev/null; then
|
||
print_status "${service_name} is ready!"
|
||
return 0
|
||
fi
|
||
|
||
print_info "Attempt ${attempt}/${max_attempts}: ${service_name} not ready yet, waiting 2 seconds..."
|
||
sleep 2
|
||
attempt=$((attempt + 1))
|
||
done
|
||
|
||
print_error "${service_name} failed to become ready after ${max_attempts} attempts"
|
||
return 1
|
||
}
|
||
|
||
# Wait for PostgreSQL
|
||
if ! wait_for_service "PostgreSQL" $POSTGRES_HOST $POSTGRES_PORT; then
|
||
exit 1
|
||
fi
|
||
|
||
# Wait for Neo4j
|
||
if ! wait_for_service "Neo4j" neo4j 7687; then
|
||
exit 1
|
||
fi
|
||
|
||
# Function to check if database needs migration
|
||
check_database_migration() {
|
||
print_info "Checking if database needs migration..."
|
||
|
||
# Check if price_tiers table exists and has data
|
||
if ! python3 -c "
|
||
import psycopg2
|
||
import os
|
||
try:
|
||
conn = psycopg2.connect(
|
||
host=os.getenv('POSTGRES_HOST', 'postgres'),
|
||
port=int(os.getenv('POSTGRES_PORT', '5432')),
|
||
user=os.getenv('POSTGRES_USER', 'pipeline_admin'),
|
||
password=os.getenv('POSTGRES_PASSWORD', 'secure_pipeline_2024'),
|
||
database=os.getenv('POSTGRES_DB', 'dev_pipeline')
|
||
)
|
||
cursor = conn.cursor()
|
||
|
||
# Check if price_tiers table exists
|
||
cursor.execute(\"\"\"
|
||
SELECT EXISTS (
|
||
SELECT FROM information_schema.tables
|
||
WHERE table_schema = 'public'
|
||
AND table_name = 'price_tiers'
|
||
);
|
||
\"\"\")
|
||
table_exists = cursor.fetchone()[0]
|
||
|
||
if not table_exists:
|
||
print('price_tiers table does not exist - migration needed')
|
||
exit(1)
|
||
|
||
# Check if price_tiers has data
|
||
cursor.execute('SELECT COUNT(*) FROM price_tiers;')
|
||
count = cursor.fetchone()[0]
|
||
|
||
if count == 0:
|
||
print('price_tiers table is empty - migration needed')
|
||
exit(1)
|
||
|
||
# Check if stack_recommendations has sufficient data
|
||
cursor.execute('SELECT COUNT(*) FROM stack_recommendations;')
|
||
rec_count = cursor.fetchone()[0]
|
||
|
||
if rec_count < 20: # Reduced threshold for Docker environment
|
||
print(f'stack_recommendations has only {rec_count} records - migration needed')
|
||
exit(1)
|
||
|
||
print('Database appears to be fully migrated')
|
||
cursor.close()
|
||
conn.close()
|
||
|
||
except Exception as e:
|
||
print(f'Error checking database: {e}')
|
||
exit(1)
|
||
" 2>/dev/null; then
|
||
return 1 # Migration needed
|
||
else
|
||
return 0 # Migration not needed
|
||
fi
|
||
}
|
||
|
||
# Function to run PostgreSQL migrations
|
||
run_postgres_migrations() {
|
||
print_info "Running PostgreSQL migrations..."
|
||
|
||
# Migration files in order
|
||
migration_files=(
|
||
"db/001_schema.sql"
|
||
"db/002_tools_migration.sql"
|
||
"db/003_tools_pricing_migration.sql"
|
||
)
|
||
|
||
# Set PGPASSWORD to avoid password prompts
|
||
export PGPASSWORD="$POSTGRES_PASSWORD"
|
||
|
||
for migration_file in "${migration_files[@]}"; do
|
||
if [ ! -f "$migration_file" ]; then
|
||
print_error "Migration file not found: $migration_file"
|
||
exit 1
|
||
fi
|
||
|
||
print_info "Running migration: $migration_file"
|
||
|
||
# Run migration with error handling
|
||
if psql -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -d $POSTGRES_DB -f "$migration_file" -q 2>/dev/null; then
|
||
print_status "Migration completed: $migration_file"
|
||
else
|
||
print_error "Migration failed: $migration_file"
|
||
print_info "Check the error logs above for details"
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
# Unset password
|
||
unset PGPASSWORD
|
||
|
||
print_status "All PostgreSQL migrations completed successfully"
|
||
}
|
||
|
||
# Check if migration is needed and run if necessary
|
||
if [ "$FORCE_MIGRATION" = true ]; then
|
||
print_warning "Force migration enabled - running migrations..."
|
||
run_postgres_migrations
|
||
|
||
# Verify migration was successful
|
||
print_info "Verifying migration..."
|
||
if check_database_migration; then
|
||
print_status "Migration verification successful"
|
||
else
|
||
print_error "Migration verification failed"
|
||
exit 1
|
||
fi
|
||
elif check_database_migration; then
|
||
print_status "Database is already migrated"
|
||
else
|
||
print_warning "Database needs migration - running migrations..."
|
||
run_postgres_migrations
|
||
|
||
# Verify migration was successful
|
||
print_info "Verifying migration..."
|
||
if check_database_migration; then
|
||
print_status "Migration verification successful"
|
||
else
|
||
print_error "Migration verification failed"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# Check if Neo4j migration has been run
|
||
print_info "Checking if Neo4j migration has been completed..."
|
||
if ! python3 -c "
|
||
from neo4j import GraphDatabase
|
||
import os
|
||
try:
|
||
driver = GraphDatabase.driver(
|
||
os.getenv('NEO4J_URI', 'bolt://neo4j:7687'),
|
||
auth=(os.getenv('NEO4J_USER', 'neo4j'), os.getenv('NEO4J_PASSWORD', 'password'))
|
||
)
|
||
with driver.session() as session:
|
||
result = session.run('MATCH (p:PriceTier) RETURN count(p) as count')
|
||
price_tiers = result.single()['count']
|
||
if price_tiers == 0:
|
||
print('No data found in Neo4j - migration needed')
|
||
exit(1)
|
||
else:
|
||
print(f'Found {price_tiers} price tiers - migration appears complete')
|
||
driver.close()
|
||
except Exception as e:
|
||
print(f'Error checking migration status: {e}')
|
||
exit(1)
|
||
" 2>/dev/null; then
|
||
print_warning "No data found in Neo4j - running migration..."
|
||
|
||
# Run migration
|
||
if python3 migrate_postgres_to_neo4j.py; then
|
||
print_status "Migration completed successfully"
|
||
else
|
||
print_error "Migration failed"
|
||
exit 1
|
||
fi
|
||
else
|
||
print_status "Migration appears to be complete"
|
||
fi
|
||
|
||
# Set environment variables for the application
|
||
export NEO4J_URI="$NEO4J_URI"
|
||
export NEO4J_USER="$NEO4J_USER"
|
||
export NEO4J_PASSWORD="$NEO4J_PASSWORD"
|
||
export POSTGRES_HOST="$POSTGRES_HOST"
|
||
export POSTGRES_PORT="$POSTGRES_PORT"
|
||
export POSTGRES_USER="$POSTGRES_USER"
|
||
export POSTGRES_PASSWORD="$POSTGRES_PASSWORD"
|
||
export POSTGRES_DB="$POSTGRES_DB"
|
||
export CLAUDE_API_KEY="$CLAUDE_API_KEY"
|
||
|
||
print_status "Environment variables set"
|
||
|
||
# Create logs directory if it doesn't exist
|
||
mkdir -p logs
|
||
|
||
# Start the migrated application
|
||
print_info "Starting Enhanced Tech Stack Selector (Docker Version)..."
|
||
print_info "Server will be available at: http://localhost:8002"
|
||
print_info "API documentation: http://localhost:8002/docs"
|
||
print_info "Health check: http://localhost:8002/health"
|
||
print_info "Diagnostics: http://localhost:8002/api/diagnostics"
|
||
print_info ""
|
||
print_info "Press Ctrl+C to stop the server"
|
||
print_info ""
|
||
|
||
# Start the application
|
||
cd src
|
||
python3 main_migrated.py
|