From b5cc5dcb37f7278b7dea78121fa5a44b8e7662f3 Mon Sep 17 00:00:00 2001 From: Dispatcharr Date: Mon, 3 Mar 2025 15:18:11 -0600 Subject: [PATCH] Revert "Merge branch 'main' of https://github.com/Dispatcharr/Dispatcharr" This reverts commit dc4de65cbf16860524d2b2638a7ef057fe158cf3, reversing changes made to 814d6a6cda930a3e17ba295e5d78dbc2405fc7fa. Attempt to fix --- dispatcharr/settings.py | 4 +- docker/Dockerfile | 114 ++++++----------- docker/entrypoint.aio.sh | 105 +++++++++++++++ docker/entrypoint.sh | 267 ++++++++++----------------------------- docker/nginx.conf | 15 --- 5 files changed, 211 insertions(+), 294 deletions(-) create mode 100755 docker/entrypoint.aio.sh delete mode 100644 docker/nginx.conf diff --git a/dispatcharr/settings.py b/dispatcharr/settings.py index bb4a7f4e..ab421fe7 100644 --- a/dispatcharr/settings.py +++ b/dispatcharr/settings.py @@ -118,11 +118,12 @@ USE_I18N = True USE_TZ = True STATIC_URL = '/static/' -STATIC_ROOT = BASE_DIR / 'static' # Directory where static files will be collected +STATIC_ROOT = BASE_DIR / 'staticfiles' # Directory where static files will be collected # Adjust STATICFILES_DIRS to include the paths to the directories that contain your static files. STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'frontend/build/static'), # React build static files + BASE_DIR / 'static', # Django custom static files (if any) ] @@ -140,7 +141,6 @@ SERVER_IP = "127.0.0.1" CORS_ALLOW_ALL_ORIGINS = True CORS_ALLOW_CREDENTIALS = True -CSRF_TRUSTED_ORIGINS = ['*'] APPEND_SLASH = True REST_FRAMEWORK = { diff --git a/docker/Dockerfile b/docker/Dockerfile index 079c1d6f..ef9799e7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,47 +1,3 @@ -FROM python:3.13-slim AS builder - -ENV PATH="/dispatcharrpy/bin:$PATH" \ - VIRTUAL_ENV=/dispatcharrpy \ - DJANGO_SETTINGS_MODULE=dispatcharr.settings \ - PYTHONUNBUFFERED=1 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - curl \ - gcc \ - git \ - wget && \ - echo "=== setting up nodejs ===" && \ - curl -sL https://deb.nodesource.com/setup_23.x -o /tmp/nodesource_setup.sh && \ - bash /tmp/nodesource_setup.sh && \ - apt-get update && \ - apt-get install -y --no-install-recommends \ - nodejs && \ - python -m pip install virtualenv && \ - virtualenv /dispatcharrpy && \ - git clone https://github.com/Dispatcharr/Dispatcharr /app && \ - cd /app && \ - pip install --no-cache-dir -r requirements.txt && \ - pip install --no-cache-dir -r requirements-pytorch.txt && \ - pip install --no-cache-dir -r requirements-sentence-transformers.txt && \ - echo "installing sentence-transformers" && \ - pip install sentence-transformers==3.4.1 && \ - cd /app/frontend && \ - npm install && \ - npm run build && \ - find . -maxdepth 1 ! -name '.' ! -name 'build' -exec rm -rf '{}' \; && \ - python manage.py collectstatic --noinput || true && \ - echo "Aggressively remove build-only packages and caches" && \ - apt-get purge -y \ - curl \ - gcc \ - git \ - nodejs \ - wget && \ - apt-get autoremove -y && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /var/tmp/* /tmp/* - FROM python:3.13-slim ENV PATH="/dispatcharrpy/bin:$PATH" \ @@ -50,47 +6,57 @@ ENV PATH="/dispatcharrpy/bin:$PATH" \ PYTHONUNBUFFERED=1 RUN apt-get update && \ - apt-get install -y --no-install-recommends \ + apt-get install -y \ curl \ ffmpeg \ - gnupg2 \ + gcc \ + git \ gpg \ libpq-dev \ lsb-release \ - nginx \ - procps \ - streamlink \ - wget && \ - echo "=== setting up postgres ====" && \ - echo "deb http://apt.postgresql.org/pub/repos/apt/ bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ - wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \ - echo "=== setting up redis ===" && \ + python3-virtualenv \ + streamlink + +RUN \ + curl -sL https://deb.nodesource.com/setup_23.x -o /tmp/nodesource_setup.sh && \ + bash /tmp/nodesource_setup.sh && \ curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg && \ chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg && \ echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/redis.list && \ apt-get update && \ + apt-get install -y redis + +RUN apt-get update && \ apt-get install -y \ - postgresql-14 \ - postgresql-contrib-14 \ - redis-server && \ + nodejs \ + redis + +RUN \ mkdir /data && \ - apt-get remove -y \ - gnupg2 \ - gpg \ - lsb-release && \ - apt-get clean && \ - apt-get autoremove -y && \ - rm -rf \ - /tmp/* \ - /var/lib/apt/lists/* \ - /var/tmp/* - -COPY docker/nginx.conf /etc/nginx/sites-enabled/default - -# Copy the virtual environment and application from the builder stage -COPY --from=builder /dispatcharrpy /dispatcharrpy -COPY --from=builder /app /app + virtualenv /dispatcharrpy && \ + git clone https://github.com/Dispatcharr/Dispatcharr /app && \ + cd /app && \ + pip install --no-cache-dir -r requirements.txt && \ + cd /app/frontend && \ + npm install && \ + npm run build && \ + find . -maxdepth 1 ! -name '.' ! -name 'build' -exec rm -rf '{}' \; && \ + cd /app && \ + python manage.py collectstatic --noinput || true && \ + apt-get remove -y \ + gcc \ + git \ + gpg \ + libpq-dev \ + lsb-release \ + nodejs && \ + apt-get clean && \ + apt-get autoremove -y && \ + rm -rf \ + /tmp/* \ + /var/lib/apt/lists/* \ + /var/tmp/* WORKDIR /app -CMD ["/app/docker/entrypoint.sh"] +CMD ["/app/docker/entrypoint.aio.sh"] diff --git a/docker/entrypoint.aio.sh b/docker/entrypoint.aio.sh new file mode 100755 index 00000000..244df3ab --- /dev/null +++ b/docker/entrypoint.aio.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +# Run Django migrations and collect static files +python manage.py collectstatic --noinput +python manage.py migrate --noinput + +# Function to clean up only running processes +cleanup() { + echo "🔥 Cleanup triggered! Stopping services..." + for pid in "${pids[@]}"; do + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + echo "⛔ Stopping process (PID: $pid)..." + kill -TERM "$pid" 2>/dev/null + else + echo "✅ Process (PID: $pid) already stopped." + fi + done + wait +} + +# Catch termination signals (CTRL+C, Docker Stop, etc.) +trap cleanup TERM INT + +# Initialize an array to store PIDs +pids=() + +GUNICORN_PORT=9191 + +# If running in development mode, install and start frontend +if [ "$DISPATCHARR_ENV" = "dev" ]; then + echo "🚀 Development Mode - Setting up Frontend..." + GUNICORN_PORT=5656 + + # Install Node.js + apt-get update && apt-get install -y nodejs + + # Install frontend dependencies + cd /app/frontend && npm install + cd /app + + # Start React development server + echo "🚀 Starting React Dev Server..." + cd /app/frontend + PORT=9191 ./node_modules/pm2/bin/pm2 --name test start npm -- start + ./node_modules/pm2/bin/pm2 logs & + react_pid=$! + echo "✅ React started with PID $react_pid" + pids+=("$react_pid") + cd /app +fi + +# If running in `dev` or `aio`, start Redis and Celery +if [ "$DISPATCHARR_ENV" = "dev" ] || [ "$DISPATCHARR_ENV" = "aio" ]; then + echo "🚀 Running Redis and Celery for '$DISPATCHARR_ENV'..." + + # Start Redis + echo "🚀 Starting Redis..." + redis-server --daemonize no & + sleep 1 # Give Redis time to start + redis_pid=$(pgrep -x redis-server) + if [ -n "$redis_pid" ]; then + echo "✅ Redis started with PID $redis_pid" + pids+=("$redis_pid") + else + echo "❌ Redis failed to start!" + fi + + # Start Celery + echo "🚀 Starting Celery..." + celery -A dispatcharr worker -l info & + celery_pid=$! + echo "✅ Celery started with PID $celery_pid" + pids+=("$celery_pid") +fi + +# Always start Gunicorn +echo "🚀 Starting Gunicorn..." +gunicorn --workers=4 --worker-class=gevent --timeout=300 --bind 0.0.0.0:${GUNICORN_PORT} dispatcharr.wsgi:application & +gunicorn_pid=$! +echo "✅ Gunicorn started with PID $gunicorn_pid" +pids+=("$gunicorn_pid") + +# Log PIDs +echo "📝 Process PIDs: ${pids[*]}" + +# Wait for at least one process to exit and log the process that exited first +if [ ${#pids[@]} -gt 0 ]; then + echo "⏳ Waiting for processes to exit..." + ps -aux | grep -E 'redis-server|celery|gunicorn|npm' + wait -n "${pids[@]}" + echo "🚨 One of the processes exited! Checking which one..." + + for pid in "${pids[@]}"; do + if ! kill -0 "$pid" 2>/dev/null; then + process_name=$(ps -p "$pid" -o comm=) + echo "❌ Process $process_name (PID: $pid) has exited!" + fi + done +else + echo "❌ No processes started. Exiting." + exit 1 +fi + +# Cleanup and stop remaining processes +cleanup diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index e3a1f7d5..334eb608 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,62 +1,25 @@ -#!/bin/bash +#!/bin/sh set -e # Exit immediately if a command exits with a non-zero status -# Function to clean up only running processes -cleanup() { - echo "🔥 Cleanup triggered! Stopping services..." - for pid in "${pids[@]}"; do - if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then - echo "⛔ Stopping process (PID: $pid)..." - kill -TERM "$pid" 2>/dev/null - else - echo "✅ Process (PID: $pid) already stopped." - fi - done - wait -} - -# Catch termination signals (CTRL+C, Docker Stop, etc.) -trap cleanup TERM INT - -# Initialize an array to store PIDs -pids=() - # Function to echo with timestamp echo_with_timestamp() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" } -# Global variables -if [[ ! -f /etc/profile.d/dispatcharr.sh ]]; then - echo "export PATH=$PATH" >> /etc/profile.d/dispatcharr.sh - echo "export VIRTUAL_ENV=$VIRTUAL_ENV" >> /etc/profile.d/dispatcharr.sh - echo "export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE" >> /etc/profile.d/dispatcharr.sh - echo "export PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> /etc/profile.d/dispatcharr.sh -fi - -chmod +x /etc/profile.d/dispatcharr.sh - -# Dispatcharr variables -export ADMIN_PORT=5656 - # Set PostgreSQL environment variables export POSTGRES_DB=${POSTGRES_DB:-dispatcharr} export POSTGRES_USER=${POSTGRES_USER:-dispatch} export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-secret} export POSTGRES_HOST=${POSTGRES_HOST:-localhost} export POSTGRES_PORT=${POSTGRES_PORT:-5432} -export PGDATA=${PGDATA:-/app/data/db} -export PG_BINDIR="/usr/lib/postgresql/14/bin" - -# Set up user details export PUID=${PUID:-1000} export PGID=${PGID:-1000} - -# Set up initial django admin export DJANGO_SUPERUSER_USERNAME=${DEFAULT_USERNAME:-admin} export DJANGO_SUPERUSER_PASSWORD=${DEFAULT_PASSWORD:-admin} export DJANGO_SUPERUSER_EMAIL=${DEFAULT_EMAIL:-admin@dispatcharr.local} +export PGDATA=${PGDATA:-/app/data/db} +export PG_BINDIR="/usr/lib/postgresql/14/bin" # Echo environment variables for debugging @@ -80,86 +43,38 @@ else fi fi -# If running in development mode, install and start frontend -if [ "$DISPATCHARR_ENV" = "dev" ]; then - echo "🚀 Development Mode - Setting up Frontend..." +# Initialize PostgreSQL database +if [ -z "$(ls -A "$PGDATA")" ]; then + echo_with_timestamp "Initializing PostgreSQL database..." + mkdir -p "$PGDATA" + chown -R postgres:postgres "$PGDATA" + chmod 700 "$PGDATA" - # Install Node.js - apt-get update && apt-get install -y nodejs - - # Install frontend dependencies - cd /app/frontend && npm install - cd /app - - # Start React development server - echo "🚀 Starting React Dev Server..." - cd /app/frontend - su - $POSTGRES_USER -c "PORT=9191 /app/frontend/node_modules/pm2/bin/pm2 --name dev-server start npm -- start" - ./node_modules/pm2/bin/pm2 logs & - react_pid=$(cat /home/dispatch/.pm2/pids/dev-server*) - echo "✅ React started with PID $react_pid" - pids+=("$react_pid") - cd /app + # Initialize PostgreSQL + su - postgres -c "$PG_BINDIR/initdb -D $PGDATA" + # Configure PostgreSQL + echo "host all all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf" + echo "listen_addresses='*'" >> "$PGDATA/postgresql.conf" fi -# If running in `dev` or `aio`, start Postgres, Redis, and Celery -if [ "$DISPATCHARR_ENV" = "dev" ] || [ "$DISPATCHARR_ENV" = "aio" ]; then - echo "🚀 Running Postgres, Redis, and Celery for '$DISPATCHARR_ENV'..." +# Start PostgreSQL +su - postgres -c "$PG_BINDIR/pg_ctl -D $PGDATA start -w -t 300 -o '-c port=${POSTGRES_PORT}'" - # Initialize PostgreSQL database - if [ -z "$(ls -A "$PGDATA")" ]; then - echo_with_timestamp "Initializing PostgreSQL database..." - mkdir -p "$PGDATA" - chown -R postgres:postgres "$PGDATA" - chmod 700 "$PGDATA" +# Wait for PostgreSQL to be ready +until su - postgres -c "$PG_BINDIR/pg_isready -h ${POSTGRES_HOST} -p ${POSTGRES_PORT}" >/dev/null 2>&1; do + echo_with_timestamp "Waiting for PostgreSQL to be ready..." + sleep 1 +done - # Initialize PostgreSQL - su - postgres -c "$PG_BINDIR/initdb -D $PGDATA" - # Configure PostgreSQL - echo "host all all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf" - echo "listen_addresses='*'" >> "$PGDATA/postgresql.conf" - fi +# Setup database if needed +if ! su - postgres -c "psql -p ${POSTGRES_PORT} -tAc \"SELECT 1 FROM pg_database WHERE datname = '$POSTGRES_DB';\"" | grep -q 1; then + # Create PostgreSQL database + echo_with_timestamp "Creating PostgreSQL database..." + su - postgres -c "createdb -p ${POSTGRES_PORT} ${POSTGRES_DB}" - # Start Redis - echo "🚀 Starting Redis..." - su - $POSTGRES_USER -c "redis-server --daemonize no &" - sleep 1 # Give Redis time to start - redis_pid=$(pgrep -x redis-server) - if [ -n "$redis_pid" ]; then - echo "✅ Redis started with PID $redis_pid" - pids+=("$redis_pid") - else - echo "❌ Redis failed to start!" - fi - - # Start Celery - echo "🚀 Starting Celery..." - su - $POSTGRES_USER -c "cd /app && celery -A dispatcharr worker -l info &" - celery_pid=$(pgrep -x celery) - echo "✅ Celery started with PID $celery_pid" - pids+=("$celery_pid") - - # Start PostgreSQL - echo "Starting Postgres..." - su - postgres -c "$PG_BINDIR/pg_ctl -D $PGDATA start -w -t 300 -o '-c port=${POSTGRES_PORT}'" - # Wait for PostgreSQL to be ready - until su - postgres -c "$PG_BINDIR/pg_isready -h ${POSTGRES_HOST} -p ${POSTGRES_PORT}" >/dev/null 2>&1; do - echo_with_timestamp "Waiting for PostgreSQL to be ready..." - sleep 1 - done - postgres_pid=$(su - postgres -c "$PG_BINDIR/pg_ctl -D $PGDATA status" | sed -n 's/.*PID: \([0-9]\+\).*/\1/p') - echo "✅ Postgres started with PID $postgres_pid" - pids+=("$postgres_pid") - - # Setup database if needed - if ! su - postgres -c "psql -p ${POSTGRES_PORT} -tAc \"SELECT 1 FROM pg_database WHERE datname = '$POSTGRES_DB';\"" | grep -q 1; then - # Create PostgreSQL database - echo_with_timestamp "Creating PostgreSQL database..." - su - postgres -c "createdb -p ${POSTGRES_PORT} ${POSTGRES_DB}" - - # Create user, set ownership, and grant privileges - echo_with_timestamp "Creating PostgreSQL user..." - su - postgres -c "psql -p ${POSTGRES_PORT} -d ${POSTGRES_DB}" </dev/null 2>&1; then - echo_with_timestamp "ERROR: PostgreSQL is running but the database is not accessible. Exiting..." - exit 1 - else - echo_with_timestamp "PostgreSQL database is accessible." - fi + echo_with_timestamp "Setting PostgreSQL user privileges..." + su postgres -c "$PG_BINDIR/psql -p ${POSTGRES_PORT} -c \"ALTER DATABASE ${POSTGRES_DB} OWNER TO $POSTGRES_USER;\"" + su postgres -c "$PG_BINDIR/psql -p ${POSTGRES_PORT} -c \"GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_DB} TO $POSTGRES_USER;\"" + # Finished setting up PosgresSQL database + echo_with_timestamp "PostgreSQL database setup complete." fi +# Test PostgreSQL connection and exit if unavailable +echo_with_timestamp "Testing database connection..." +if ! pg_isready -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -d $POSTGRES_DB; then + echo_with_timestamp "ERROR: PostgreSQL is not ready. Exiting..." + exit 1 +else + echo_with_timestamp "PostgreSQL is ready to accept connections." +fi + +# Verify database accessibility +echo_with_timestamp "Verifying database accessibility..." +if ! su - $POSTGRES_USER -c "psql -p ${POSTGRES_PORT} -d ${POSTGRES_DB} -c 'SELECT 1;'" >/dev/null 2>&1; then + echo_with_timestamp "ERROR: PostgreSQL is running but the database is not accessible. Exiting..." + exit 1 +else + echo_with_timestamp "PostgreSQL database is accessible." +fi + +# Start Redis +echo_with_timestamp "Starting Redis..." +su - $POSTGRES_USER -c 'redis-server --daemonize yes' + # Run Django commands -cd /app echo_with_timestamp "Running Django commands..." +python manage.py collectstatic --noinput || true +python manage.py makemigrations --noinput || true python manage.py migrate --noinput || true echo_with_timestamp "Checking if Django superuser exists..." if ! python manage.py shell -c "from django.contrib.auth import get_user_model; exit(0) if get_user_model().objects.filter(username='${DJANGO_SUPERUSER_USERNAME}').exists() else exit(1)"; then @@ -206,68 +125,10 @@ else echo_with_timestamp "Superuser already exists. Skipping creation." fi -# Always start Gunicorn -echo "🚀 Starting Gunicorn..." -su - $POSTGRES_USER -c "cd /app && gunicorn --workers=4 --worker-class=gevent --timeout=300 --bind 0.0.0.0:${ADMIN_PORT} dispatcharr.wsgi:application &" -gunicorn_pid=$(pgrep -x gunicorn | sort | head -n1) -echo "✅ Gunicorn started with PID $gunicorn_pid" -pids+=("$gunicorn_pid") +# Start Celery +echo_with_timestamp "Starting Celery..." +su - $POSTGRES_USER -c 'cd /app && celery -A dispatcharr worker --loglevel=info &' -echo "🚀 Starting nginx..." -nginx -nginx_pid=$(pgrep nginx | sort | head -n1) -echo "✅ nginx started with PID $nginx_pid" -pids+=("$nginx_pid") - -# Log PIDs -echo "📝 Process PIDs: ${pids[*]}" - -echo " - - %%%% - %%%%%%%%%%% - %%%%%%%%%%%%%%% - %%%% %%%%%%%%%% - %%%%% %%%%%%%%%% - @%%%% %%%%%%%%%% - %%%% * %%%%%%%%%% - %%%% **** %%%%%%%%%% - %%%% ******* %%%%%%%% - %%%% *********** %%%%%% - %%%% ************** %%%% - %%%% ************* % - %%%% ********** @%%% % - %%%% ******* %%%%%% - %%%% **** %%%%%%%%%% - %%%% %%%%%%%%%% - %%%% %%%%%%%%%% - %%%% %%%%%%%%% - %%%% %%%%%%%%%@ - %%%%%%%%% - @%%%%%%%%%% - %%%% - -DISPACTHARR HAS SUCCESSFULLY STARTED -" -# Wait for at least one process to exit and log the process that exited first -if [ ${#pids[@]} -gt 0 ]; then - echo "⏳ Waiting for processes to exit..." - while kill -0 "${pids[@]}" 2>/dev/null; do - sleep 1 # Wait for a second before checking again - done - - echo "🚨 One of the processes exited! Checking which one..." - - for pid in "${pids[@]}"; do - if ! kill -0 "$pid" 2>/dev/null; then - process_name=$(ps -p "$pid" -o comm=) - echo "❌ Process $process_name (PID: $pid) has exited!" - fi - done -else - echo "❌ No processes started. Exiting." - exit 1 -fi - -# Cleanup and stop remaining processes -cleanup +# Start Gunicorn +echo_with_timestamp "Starting Gunicorn..." +su - $POSTGRES_USER -c 'cd /app && gunicorn --workers=4 --worker-class=gevent --timeout=300 --bind 0.0.0.0:9191 dispatcharr.wsgi:application' diff --git a/docker/nginx.conf b/docker/nginx.conf deleted file mode 100644 index 966ebd63..00000000 --- a/docker/nginx.conf +++ /dev/null @@ -1,15 +0,0 @@ -server { - listen 9191; - server_name yourdomain.com; - - location /static/ { - root /app; # Base directory for static files - } - - location / { - proxy_pass http://127.0.0.1:5656; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } -}