#!/bin/bash set -e # Ожидание готовности PostgreSQL wait_for_postgres() { echo "Waiting for PostgreSQL..." python -c " import psycopg2 import os import sys dbname = os.environ.get('DB_NAME', 'inventory_db') user = os.environ.get('DB_USER', 'postgres') password = os.environ.get('DB_PASSWORD', 'postgres') host = os.environ.get('DB_HOST', 'db') port = os.environ.get('DB_PORT', '5432') print(f'Attempting connection to: host={host} port={port} dbname={dbname} user={user}') try: conn = psycopg2.connect( dbname=dbname, user=user, password=password, host=host, port=port ) conn.close() print('Connection successful!') exit(0) except Exception as e: print(f'Error connecting to PostgreSQL: {e}', file=sys.stderr) exit(1) " while [ $? -ne 0 ]; do echo "PostgreSQL is unavailable - sleeping" sleep 2 python -c " import psycopg2 import os import sys try: conn = psycopg2.connect( dbname=os.environ.get('DB_NAME', 'inventory_db'), user=os.environ.get('DB_USER', 'postgres'), password=os.environ.get('DB_PASSWORD', 'postgres'), host=os.environ.get('DB_HOST', 'db'), port=os.environ.get('DB_PORT', '5432') ) conn.close() exit(0) except Exception as e: print(f'Retry error: {e}', file=sys.stderr) exit(1) " done echo "PostgreSQL is up!" } # Ожидание готовности Redis wait_for_redis() { echo "Waiting for Redis..." python -c " import redis import os import sys host = os.environ.get('REDIS_HOST', 'redis') port = int(os.environ.get('REDIS_PORT', '6379')) db = int(os.environ.get('REDIS_DB', '0')) print(f'Attempting connection to Redis: host={host} port={port} db={db}') try: r = redis.Redis(host=host, port=port, db=db) r.ping() print('Redis connection successful!') exit(0) except Exception as e: print(f'Error connecting to Redis: {e}', file=sys.stderr) exit(1) " while [ $? -ne 0 ]; do echo "Redis is unavailable - sleeping" sleep 2 python -c " import redis import os import sys try: r = redis.Redis( host=os.environ.get('REDIS_HOST', 'redis'), port=int(os.environ.get('REDIS_PORT', '6379')), db=int(os.environ.get('REDIS_DB', '0')) ) r.ping() exit(0) except Exception as e: print(f'Redis retry error: {e}', file=sys.stderr) exit(1) " done echo "Redis is up!" } # Создание папок media и staticfiles с правильными правами setup_directories() { echo "Setting up media and static directories..." # Определяем пути (в Docker BASE_DIR = /app, поэтому MEDIA_ROOT = /app/myproject/media) MEDIA_ROOT="/app/myproject/media" STATIC_ROOT="/app/myproject/staticfiles" # Создаем папки если их нет (рекурсивно) # Важно: создаем структуру папок для tenants mkdir -p "$MEDIA_ROOT/tenants" "$STATIC_ROOT" # Устанавливаем права доступа (без скрытия ошибок - чтобы увидеть проблемы) # Сначала меняем владельца на appuser (так как мы root) chown -R appuser:appuser "$MEDIA_ROOT" "$STATIC_ROOT" # Используем 777 для папок media, чтобы контейнер мог писать независимо от прав на хосте # Это безопасно, так как доступ контролируется на уровне Docker volume # Устанавливаем права рекурсивно на все существующие файлы и папки find "$MEDIA_ROOT" -type d -exec chmod 777 {} \; find "$MEDIA_ROOT" -type f -exec chmod 666 {} \; chmod -R 755 "$STATIC_ROOT" # Проверка что media доступна для записи if ! touch "$MEDIA_ROOT/.test" 2>/dev/null; then echo "ERROR: Cannot write to $MEDIA_ROOT" ls -la "$MEDIA_ROOT" exit 1 fi rm -f "$MEDIA_ROOT/.test" echo "Media directory is writable: $MEDIA_ROOT" echo "Media directory created/checked: $MEDIA_ROOT (permissions set)" echo "Static directory created/checked: $STATIC_ROOT" } # Применение миграций и создание суперпользователя run_migrations() { echo "Running migrations for shared apps..." gosu appuser python manage.py migrate_schemas --shared echo "Running migrations for tenant schemas..." gosu appuser python manage.py migrate_schemas --tenant echo "Collecting static files..." gosu appuser python manage.py collectstatic --noinput # Устанавливаем права ПОСЛЕ collectstatic echo "Setting permissions on static files..." STATIC_ROOT="/app/myproject/staticfiles" find "$STATIC_ROOT" -type d -exec chmod 755 {} \; 2>/dev/null || true find "$STATIC_ROOT" -type f -exec chmod 644 {} \; 2>/dev/null || true echo "Ensuring public tenant exists..." gosu appuser python /app/docker/create_public_tenant.py } # Создание PlatformAdmin если не существует create_platform_admin() { echo "Creating PlatformAdmin if not exists..." python manage.py shell << EOF from platform_admin.models import PlatformAdmin import os # Создаём PlatformAdmin из переменных окружения email = os.environ.get('PLATFORM_ADMIN_EMAIL', 'admin@platform.com') password = os.environ.get('PLATFORM_ADMIN_PASSWORD') name = os.environ.get('PLATFORM_ADMIN_NAME', 'Platform Admin') if not password: print('WARNING: PLATFORM_ADMIN_PASSWORD not set. Skipping PlatformAdmin creation.') print('Create PlatformAdmin manually via Django shell:') print(' from platform_admin.models import PlatformAdmin') print(' PlatformAdmin.objects.create_superuser(email="...", name="...", password="...")') else: if not PlatformAdmin.objects.filter(email=email).exists(): admin = PlatformAdmin.objects.create_superuser( email=email, name=name, password=password ) print(f'PlatformAdmin {email} created successfully!') else: print(f'PlatformAdmin {email} already exists.') EOF } # Если manage.py не в текущей директории, но есть в подпапке myproject if [ ! -f "manage.py" ] && [ -d "myproject" ]; then # Пытаемся войти в директорию, перенаправляя ошибки в /dev/null if cd myproject 2>/dev/null; then echo "Changing directory to myproject..." # Устанавливаем PYTHONPATH чтобы Python мог найти модуль myproject export PYTHONPATH=$(pwd):$PYTHONPATH echo "PYTHONPATH set to: $PYTHONPATH" else # Если не можем войти в директорию (проблема с правами), устанавливаем PYTHONPATH из текущей директории echo "Warning: Cannot access myproject directory (permission denied). Setting PYTHONPATH to include myproject..." export PYTHONPATH=/app/myproject:$PYTHONPATH echo "PYTHONPATH set to: $PYTHONPATH" fi fi case "$1" in web) wait_for_postgres wait_for_redis setup_directories run_migrations create_platform_admin echo "Starting Gunicorn..." exec gosu appuser gunicorn myproject.wsgi:application \ --bind 0.0.0.0:8000 \ --workers 3 \ --threads 2 \ --timeout 600 \ --access-logfile - \ --error-logfile - \ --capture-output ;; celery-worker) wait_for_postgres wait_for_redis setup_directories echo "Starting Celery Worker for photo processing and product import..." exec gosu appuser celery -A myproject worker \ -l info \ --concurrency=4 \ -Q celery,photo_processing ;; celery-beat) wait_for_postgres wait_for_redis echo "Starting Celery Beat..." exec gosu appuser celery -A myproject beat -l info ;; migrate) wait_for_postgres # Миграции тоже запускаем от gosu gosu appuser python manage.py migrate_schemas --shared gosu appuser python manage.py migrate_schemas --tenant gosu appuser python manage.py collectstatic --noinput # Права уже выставлены setup_directories (который запускается перед этим в case web/celery, # но для migrate мы можем вызвать его явно или просто поправить права на статику) # В данном блоке setup_directories не вызывался в оригинальном скрипте, но лучше вызвать если хотим гарантий # setup_directories # Для migrate обычно важно просто создать схемы. create_platform_admin ;; collectstatic) wait_for_postgres setup_directories echo "Collecting static files..." gosu appuser python manage.py collectstatic --noinput echo "Setting permissions on static files..." STATIC_ROOT="/app/myproject/staticfiles" find "$STATIC_ROOT" -type d -exec chmod 755 {} \; 2>/dev/null || true find "$STATIC_ROOT" -type f -exec chmod 644 {} \; 2>/dev/null || true echo "Static files collected and permissions set." ;; shell) exec gosu appuser python manage.py shell ;; *) exec "$@" ;; esac