test
Browse files- Dockerfile +12 -4
- app/__init__.py +78 -16
- app/routes/test.py +11 -0
- docker-compose.yml +3 -58
- run_docker.sh +27 -0
Dockerfile
CHANGED
|
@@ -2,9 +2,11 @@ FROM python:3.9-slim
|
|
| 2 |
|
| 3 |
# Set environment variables
|
| 4 |
ENV FLASK_APP=app.py
|
| 5 |
-
ENV FLASK_ENV=
|
| 6 |
ENV PATH="/home/appuser/.local/bin:$PATH"
|
| 7 |
ENV PYTHONUNBUFFERED=1
|
|
|
|
|
|
|
| 8 |
|
| 9 |
# Install system dependencies for OpenCV and other requirements
|
| 10 |
RUN apt-get update && apt-get install -y \
|
|
@@ -43,8 +45,14 @@ RUN echo '#!/bin/sh\npython -c "import flask, flask_sqlalchemy, redis, celery; p
|
|
| 43 |
# Copy the application code
|
| 44 |
COPY --chown=appuser:appuser . .
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
# Make scripts executable
|
| 47 |
-
RUN chmod +x /app/prestart.sh /app/healthcheck.sh /app/start.sh
|
| 48 |
|
| 49 |
# Switch to non-root user
|
| 50 |
USER appuser
|
|
@@ -52,5 +60,5 @@ USER appuser
|
|
| 52 |
# Expose the port
|
| 53 |
EXPOSE 5000
|
| 54 |
|
| 55 |
-
# Run the application
|
| 56 |
-
CMD ["
|
|
|
|
| 2 |
|
| 3 |
# Set environment variables
|
| 4 |
ENV FLASK_APP=app.py
|
| 5 |
+
ENV FLASK_ENV=development
|
| 6 |
ENV PATH="/home/appuser/.local/bin:$PATH"
|
| 7 |
ENV PYTHONUNBUFFERED=1
|
| 8 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 9 |
+
ENV FLASK_DEBUG=1
|
| 10 |
|
| 11 |
# Install system dependencies for OpenCV and other requirements
|
| 12 |
RUN apt-get update && apt-get install -y \
|
|
|
|
| 45 |
# Copy the application code
|
| 46 |
COPY --chown=appuser:appuser . .
|
| 47 |
|
| 48 |
+
# Create a debug script
|
| 49 |
+
RUN echo '#!/bin/bash\n\
|
| 50 |
+
echo "Starting app in debug mode..."\n\
|
| 51 |
+
python -m flask run --host=0.0.0.0 --port=5000 --debug\n\
|
| 52 |
+
' > /app/debug.sh && chmod +x /app/debug.sh
|
| 53 |
+
|
| 54 |
# Make scripts executable
|
| 55 |
+
RUN chmod +x /app/prestart.sh /app/healthcheck.sh /app/start.sh /app/debug.sh
|
| 56 |
|
| 57 |
# Switch to non-root user
|
| 58 |
USER appuser
|
|
|
|
| 60 |
# Expose the port
|
| 61 |
EXPOSE 5000
|
| 62 |
|
| 63 |
+
# Run the application in debug mode
|
| 64 |
+
CMD ["python", "-m", "flask", "run", "--host=0.0.0.0", "--port=5000", "--debug"]
|
app/__init__.py
CHANGED
|
@@ -4,8 +4,18 @@ from flask_login import LoginManager
|
|
| 4 |
from celery import Celery
|
| 5 |
import redis
|
| 6 |
import os
|
|
|
|
|
|
|
| 7 |
from pathlib import Path
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
# Initialize extensions
|
| 10 |
db = SQLAlchemy()
|
| 11 |
login = LoginManager()
|
|
@@ -14,42 +24,94 @@ celery = Celery(__name__)
|
|
| 14 |
cache = None # Initialize later when app context is available
|
| 15 |
|
| 16 |
def create_app(config_class=None):
|
|
|
|
|
|
|
| 17 |
# Create the Flask app
|
| 18 |
app = Flask(__name__)
|
|
|
|
| 19 |
|
| 20 |
# Load configuration
|
| 21 |
if config_class is None:
|
|
|
|
| 22 |
app.config.from_object('config.Config')
|
| 23 |
else:
|
|
|
|
| 24 |
app.config.from_object(config_class)
|
| 25 |
|
| 26 |
# Ensure instance path exists
|
|
|
|
| 27 |
Path(app.config['INSTANCE_PATH']).mkdir(parents=True, exist_ok=True)
|
| 28 |
app.instance_path = app.config['INSTANCE_PATH']
|
| 29 |
|
| 30 |
# Initialize extensions
|
|
|
|
| 31 |
db.init_app(app)
|
|
|
|
|
|
|
| 32 |
login.init_app(app)
|
| 33 |
|
| 34 |
# Configure Celery
|
|
|
|
| 35 |
celery.conf.update(app.config)
|
| 36 |
|
| 37 |
# Initialize Redis cache
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
|
|
|
| 55 |
return app
|
|
|
|
| 4 |
from celery import Celery
|
| 5 |
import redis
|
| 6 |
import os
|
| 7 |
+
import logging
|
| 8 |
+
import sys
|
| 9 |
from pathlib import Path
|
| 10 |
|
| 11 |
+
# Configure logging
|
| 12 |
+
logging.basicConfig(
|
| 13 |
+
level=logging.DEBUG,
|
| 14 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
| 15 |
+
handlers=[logging.StreamHandler(sys.stdout)]
|
| 16 |
+
)
|
| 17 |
+
logger = logging.getLogger(__name__)
|
| 18 |
+
|
| 19 |
# Initialize extensions
|
| 20 |
db = SQLAlchemy()
|
| 21 |
login = LoginManager()
|
|
|
|
| 24 |
cache = None # Initialize later when app context is available
|
| 25 |
|
| 26 |
def create_app(config_class=None):
|
| 27 |
+
logger.info("Starting application initialization...")
|
| 28 |
+
|
| 29 |
# Create the Flask app
|
| 30 |
app = Flask(__name__)
|
| 31 |
+
logger.info("Flask app created")
|
| 32 |
|
| 33 |
# Load configuration
|
| 34 |
if config_class is None:
|
| 35 |
+
logger.info("Loading default configuration...")
|
| 36 |
app.config.from_object('config.Config')
|
| 37 |
else:
|
| 38 |
+
logger.info(f"Loading configuration from {config_class}...")
|
| 39 |
app.config.from_object(config_class)
|
| 40 |
|
| 41 |
# Ensure instance path exists
|
| 42 |
+
logger.info(f"Ensuring instance path exists: {app.config['INSTANCE_PATH']}")
|
| 43 |
Path(app.config['INSTANCE_PATH']).mkdir(parents=True, exist_ok=True)
|
| 44 |
app.instance_path = app.config['INSTANCE_PATH']
|
| 45 |
|
| 46 |
# Initialize extensions
|
| 47 |
+
logger.info("Initializing SQLAlchemy...")
|
| 48 |
db.init_app(app)
|
| 49 |
+
|
| 50 |
+
logger.info("Initializing LoginManager...")
|
| 51 |
login.init_app(app)
|
| 52 |
|
| 53 |
# Configure Celery
|
| 54 |
+
logger.info("Configuring Celery...")
|
| 55 |
celery.conf.update(app.config)
|
| 56 |
|
| 57 |
# Initialize Redis cache
|
| 58 |
+
try:
|
| 59 |
+
logger.info(f"Initializing Redis cache with URL: {app.config['CELERY_BROKER_URL']}")
|
| 60 |
+
global cache
|
| 61 |
+
cache = redis.Redis.from_url(app.config['CELERY_BROKER_URL'])
|
| 62 |
+
logger.info("Redis cache initialized successfully")
|
| 63 |
+
except Exception as e:
|
| 64 |
+
logger.error(f"Error initializing Redis cache: {e}")
|
| 65 |
+
# Continue without Redis for now
|
| 66 |
+
pass
|
| 67 |
+
|
| 68 |
+
# Register test blueprint first (this should always work)
|
| 69 |
+
logger.info("Registering test blueprint...")
|
| 70 |
+
from .routes.test import test_bp
|
| 71 |
+
app.register_blueprint(test_bp)
|
| 72 |
+
|
| 73 |
+
# Register other blueprints
|
| 74 |
+
logger.info("Registering other blueprints...")
|
| 75 |
+
try:
|
| 76 |
+
with app.app_context():
|
| 77 |
+
logger.info("Importing auth blueprint...")
|
| 78 |
+
from .routes.auth import auth_bp
|
| 79 |
+
|
| 80 |
+
logger.info("Importing dashboard blueprint...")
|
| 81 |
+
from .routes.dashboard import dashboard_bp
|
| 82 |
+
|
| 83 |
+
logger.info("Importing API blueprint...")
|
| 84 |
+
from .routes.api import api_bp
|
| 85 |
+
|
| 86 |
+
logger.info("Importing compliance blueprint...")
|
| 87 |
+
from .routes.compliance import compliance_bp
|
| 88 |
+
|
| 89 |
+
logger.info("Importing Google Ads blueprint...")
|
| 90 |
+
from .routes.google_ads import google_ads_bp
|
| 91 |
+
|
| 92 |
+
logger.info("Registering auth blueprint...")
|
| 93 |
+
app.register_blueprint(auth_bp)
|
| 94 |
+
|
| 95 |
+
logger.info("Registering dashboard blueprint...")
|
| 96 |
+
app.register_blueprint(dashboard_bp)
|
| 97 |
+
|
| 98 |
+
logger.info("Registering API blueprint...")
|
| 99 |
+
app.register_blueprint(api_bp)
|
| 100 |
+
|
| 101 |
+
logger.info("Registering compliance blueprint...")
|
| 102 |
+
app.register_blueprint(compliance_bp)
|
| 103 |
+
|
| 104 |
+
logger.info("Registering Google Ads blueprint...")
|
| 105 |
+
app.register_blueprint(google_ads_bp)
|
| 106 |
+
except Exception as e:
|
| 107 |
+
logger.error(f"Error registering blueprints: {e}")
|
| 108 |
+
# Continue without all blueprints for debugging
|
| 109 |
+
pass
|
| 110 |
+
|
| 111 |
+
# Add a simple route directly to the app
|
| 112 |
+
@app.route('/')
|
| 113 |
+
def index():
|
| 114 |
+
return 'Application is running! Try /test for the test endpoint.'
|
| 115 |
|
| 116 |
+
logger.info("Application initialization complete")
|
| 117 |
return app
|
app/routes/test.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Blueprint, jsonify
|
| 2 |
+
|
| 3 |
+
test_bp = Blueprint('test', __name__)
|
| 4 |
+
|
| 5 |
+
@test_bp.route('/test', methods=['GET'])
|
| 6 |
+
def test():
|
| 7 |
+
"""Simple test endpoint to verify the application is working."""
|
| 8 |
+
return jsonify({
|
| 9 |
+
'status': 'success',
|
| 10 |
+
'message': 'The application is working!'
|
| 11 |
+
})
|
docker-compose.yml
CHANGED
|
@@ -8,8 +8,9 @@ services:
|
|
| 8 |
ports:
|
| 9 |
- "5000:5000"
|
| 10 |
environment:
|
| 11 |
-
- FLASK_ENV=
|
| 12 |
-
-
|
|
|
|
| 13 |
- CELERY_BROKER_URL=redis://redis:6379/0
|
| 14 |
- CELERY_RESULT_BACKEND=redis://redis:6379/0
|
| 15 |
- INSTANCE_PATH=/tmp/instance
|
|
@@ -20,8 +21,6 @@ services:
|
|
| 20 |
- ./app/models:/app/models
|
| 21 |
depends_on:
|
| 22 |
- redis
|
| 23 |
-
- postgres
|
| 24 |
-
- selenium-hub
|
| 25 |
restart: unless-stopped
|
| 26 |
healthcheck:
|
| 27 |
test: ["CMD", "/app/healthcheck.sh"]
|
|
@@ -30,43 +29,6 @@ services:
|
|
| 30 |
retries: 3
|
| 31 |
start_period: 40s
|
| 32 |
|
| 33 |
-
celery_worker:
|
| 34 |
-
build:
|
| 35 |
-
context: .
|
| 36 |
-
dockerfile: Dockerfile
|
| 37 |
-
command: celery -A celery_worker.celery worker --loglevel=info
|
| 38 |
-
environment:
|
| 39 |
-
- FLASK_ENV=production
|
| 40 |
-
- DATABASE_URL=postgresql://postgres:example@postgres:5432/facebook_ads
|
| 41 |
-
- CELERY_BROKER_URL=redis://redis:6379/0
|
| 42 |
-
- CELERY_RESULT_BACKEND=redis://redis:6379/0
|
| 43 |
-
- INSTANCE_PATH=/tmp/instance
|
| 44 |
-
- SECRET_KEY=${SECRET_KEY:-default-dev-key-change-in-production}
|
| 45 |
-
- OPENAI_API_KEY=${OPENAI_API_KEY:-sk-mock-key-for-development}
|
| 46 |
-
volumes:
|
| 47 |
-
- ./app:/app/app
|
| 48 |
-
depends_on:
|
| 49 |
-
- web
|
| 50 |
-
- redis
|
| 51 |
-
- postgres
|
| 52 |
-
restart: unless-stopped
|
| 53 |
-
|
| 54 |
-
selenium-hub:
|
| 55 |
-
image: selenium/hub
|
| 56 |
-
ports:
|
| 57 |
-
- "4444:4444"
|
| 58 |
-
restart: unless-stopped
|
| 59 |
-
|
| 60 |
-
chrome-node:
|
| 61 |
-
image: selenium/node-chrome
|
| 62 |
-
shm_size: 2gb
|
| 63 |
-
depends_on:
|
| 64 |
-
- selenium-hub
|
| 65 |
-
environment:
|
| 66 |
-
- HUB_HOST=selenium-hub
|
| 67 |
-
- HUB_PORT=4444
|
| 68 |
-
restart: unless-stopped
|
| 69 |
-
|
| 70 |
redis:
|
| 71 |
image: redis:alpine
|
| 72 |
ports:
|
|
@@ -80,22 +42,5 @@ services:
|
|
| 80 |
timeout: 10s
|
| 81 |
retries: 3
|
| 82 |
|
| 83 |
-
postgres:
|
| 84 |
-
image: postgres:14
|
| 85 |
-
environment:
|
| 86 |
-
- POSTGRES_PASSWORD=example
|
| 87 |
-
- POSTGRES_DB=facebook_ads
|
| 88 |
-
volumes:
|
| 89 |
-
- postgres_data:/var/lib/postgresql/data
|
| 90 |
-
ports:
|
| 91 |
-
- "5432:5432"
|
| 92 |
-
restart: unless-stopped
|
| 93 |
-
healthcheck:
|
| 94 |
-
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
| 95 |
-
interval: 30s
|
| 96 |
-
timeout: 10s
|
| 97 |
-
retries: 3
|
| 98 |
-
|
| 99 |
volumes:
|
| 100 |
-
postgres_data:
|
| 101 |
redis_data:
|
|
|
|
| 8 |
ports:
|
| 9 |
- "5000:5000"
|
| 10 |
environment:
|
| 11 |
+
- FLASK_ENV=development
|
| 12 |
+
- FLASK_DEBUG=1
|
| 13 |
+
- DATABASE_URL=sqlite:////tmp/app.db
|
| 14 |
- CELERY_BROKER_URL=redis://redis:6379/0
|
| 15 |
- CELERY_RESULT_BACKEND=redis://redis:6379/0
|
| 16 |
- INSTANCE_PATH=/tmp/instance
|
|
|
|
| 21 |
- ./app/models:/app/models
|
| 22 |
depends_on:
|
| 23 |
- redis
|
|
|
|
|
|
|
| 24 |
restart: unless-stopped
|
| 25 |
healthcheck:
|
| 26 |
test: ["CMD", "/app/healthcheck.sh"]
|
|
|
|
| 29 |
retries: 3
|
| 30 |
start_period: 40s
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
redis:
|
| 33 |
image: redis:alpine
|
| 34 |
ports:
|
|
|
|
| 42 |
timeout: 10s
|
| 43 |
retries: 3
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
volumes:
|
|
|
|
| 46 |
redis_data:
|
run_docker.sh
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# run_docker.sh - Build and run the Docker container
|
| 3 |
+
|
| 4 |
+
# Stop any running containers
|
| 5 |
+
echo "Stopping any running containers..."
|
| 6 |
+
docker stop facebook-ad-analytics-web 2>/dev/null || true
|
| 7 |
+
docker rm facebook-ad-analytics-web 2>/dev/null || true
|
| 8 |
+
|
| 9 |
+
# Build the Docker image
|
| 10 |
+
echo "Building Docker image..."
|
| 11 |
+
docker build -t facebook-ad-analytics .
|
| 12 |
+
|
| 13 |
+
# Run the container
|
| 14 |
+
echo "Running container..."
|
| 15 |
+
docker run -d --name facebook-ad-analytics-web \
|
| 16 |
+
-p 5000:5000 \
|
| 17 |
+
-e FLASK_ENV=development \
|
| 18 |
+
-e FLASK_DEBUG=1 \
|
| 19 |
+
-e DATABASE_URL=sqlite:////tmp/app.db \
|
| 20 |
+
-e INSTANCE_PATH=/tmp/instance \
|
| 21 |
+
-e SECRET_KEY=dev-secret-key \
|
| 22 |
+
-e OPENAI_API_KEY=sk-mock-key-for-development \
|
| 23 |
+
facebook-ad-analytics
|
| 24 |
+
|
| 25 |
+
# Follow the logs
|
| 26 |
+
echo "Following logs..."
|
| 27 |
+
docker logs -f facebook-ad-analytics-web
|