- Updated database configuration to switch from SQLite to PostgreSQL, including changes to alembic.ini, Docker Compose, and environment settings. - Refactored application code to utilize PostgreSQL database adapters, ensuring compatibility with the new database structure. - Enhanced API routes and data handling to support the new database, including adjustments in data models and query logic. - Introduced new job processing mechanisms for full synchronization of AMO CRM entities, leveraging FastStream for background tasks. - Improved logging and error handling across the application to facilitate better monitoring and debugging. - Removed obsolete SQLite adapter files and migrations, streamlining the project structure for PostgreSQL integration.
258 lines
7.4 KiB
Python
258 lines
7.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Docker setup script for AMO CRM service with FastStream.
|
|
|
|
This script helps set up and manage Docker containers for the AMO CRM service
|
|
with FastStream workers.
|
|
"""
|
|
|
|
import subprocess
|
|
import sys
|
|
import os
|
|
import logging
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def run_command(command: str, capture_output: bool = False) -> subprocess.CompletedProcess:
|
|
"""
|
|
Run a shell command.
|
|
|
|
Args:
|
|
command: Command to execute
|
|
capture_output: Whether to capture output
|
|
|
|
Returns:
|
|
CompletedProcess result
|
|
"""
|
|
logger.info(f"Running: {command}")
|
|
return subprocess.run(
|
|
command.split(),
|
|
capture_output=capture_output,
|
|
text=True
|
|
)
|
|
|
|
|
|
def check_docker() -> bool:
|
|
"""
|
|
Check if Docker is installed and running.
|
|
|
|
Returns:
|
|
True if Docker is available, False otherwise
|
|
"""
|
|
try:
|
|
result = run_command("docker --version", capture_output=True)
|
|
if result.returncode == 0:
|
|
logger.info(f"Docker found: {result.stdout.strip()}")
|
|
|
|
# Check if Docker daemon is running
|
|
result = run_command("docker info", capture_output=True)
|
|
if result.returncode == 0:
|
|
logger.info("Docker daemon is running")
|
|
return True
|
|
else:
|
|
logger.error("Docker daemon is not running")
|
|
return False
|
|
else:
|
|
logger.error("Docker not found")
|
|
return False
|
|
except FileNotFoundError:
|
|
logger.error("Docker not installed")
|
|
return False
|
|
|
|
|
|
def check_docker_compose() -> bool:
|
|
"""
|
|
Check if Docker Compose is installed.
|
|
|
|
Returns:
|
|
True if Docker Compose is available, False otherwise
|
|
"""
|
|
try:
|
|
result = run_command("docker-compose --version", capture_output=True)
|
|
if result.returncode == 0:
|
|
logger.info(f"Docker Compose found: {result.stdout.strip()}")
|
|
return True
|
|
else:
|
|
# Try docker compose (newer syntax)
|
|
result = run_command("docker compose version", capture_output=True)
|
|
if result.returncode == 0:
|
|
logger.info(f"Docker Compose found: {result.stdout.strip()}")
|
|
return True
|
|
else:
|
|
logger.error("Docker Compose not found")
|
|
return False
|
|
except FileNotFoundError:
|
|
logger.error("Docker Compose not installed")
|
|
return False
|
|
|
|
|
|
def create_env_file() -> None:
|
|
"""Create .env file from template if it doesn't exist."""
|
|
env_file = Path(".env")
|
|
env_example = Path("env.example")
|
|
|
|
if not env_file.exists() and env_example.exists():
|
|
logger.info("Creating .env file from template")
|
|
env_file.write_text(env_example.read_text())
|
|
logger.warning("Please edit .env file with your configuration")
|
|
elif not env_file.exists():
|
|
logger.warning(".env file not found and no template available")
|
|
|
|
|
|
def create_directories() -> None:
|
|
"""Create necessary directories."""
|
|
directories = ["data", "credentials", "ssl"]
|
|
|
|
for directory in directories:
|
|
path = Path(directory)
|
|
if not path.exists():
|
|
logger.info(f"Creating directory: {directory}")
|
|
path.mkdir(exist_ok=True)
|
|
|
|
|
|
def build_images() -> bool:
|
|
"""
|
|
Build Docker images.
|
|
|
|
Returns:
|
|
True if successful, False otherwise
|
|
"""
|
|
logger.info("Building Docker images...")
|
|
result = run_command("docker-compose build")
|
|
return result.returncode == 0
|
|
|
|
|
|
def start_services(mode: str = "dev") -> bool:
|
|
"""
|
|
Start Docker services.
|
|
|
|
Args:
|
|
mode: Deployment mode (dev or prod)
|
|
|
|
Returns:
|
|
True if successful, False otherwise
|
|
"""
|
|
if mode == "prod":
|
|
logger.info("Starting services in production mode...")
|
|
result = run_command("docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d")
|
|
else:
|
|
logger.info("Starting services in development mode...")
|
|
result = run_command("docker-compose up -d")
|
|
|
|
return result.returncode == 0
|
|
|
|
|
|
def stop_services() -> bool:
|
|
"""
|
|
Stop Docker services.
|
|
|
|
Returns:
|
|
True if successful, False otherwise
|
|
"""
|
|
logger.info("Stopping services...")
|
|
result = run_command("docker-compose down")
|
|
return result.returncode == 0
|
|
|
|
|
|
def show_logs(service: str = None, follow: bool = False) -> None:
|
|
"""
|
|
Show service logs.
|
|
|
|
Args:
|
|
service: Specific service to show logs for
|
|
follow: Whether to follow logs
|
|
"""
|
|
if service:
|
|
command = f"docker-compose logs {'--follow' if follow else ''} {service}"
|
|
else:
|
|
command = f"docker-compose logs {'--follow' if follow else ''}"
|
|
|
|
run_command(command)
|
|
|
|
|
|
def show_status() -> None:
|
|
"""Show status of all services."""
|
|
logger.info("Service status:")
|
|
run_command("docker-compose ps")
|
|
|
|
logger.info("\nService health:")
|
|
run_command("docker-compose exec app python -c \"import requests; print('API:', requests.get('http://localhost:8000/health').json())\"")
|
|
|
|
|
|
def main() -> None:
|
|
"""Main function."""
|
|
parser = argparse.ArgumentParser(description="Docker setup for AMO CRM service")
|
|
parser.add_argument("action", choices=["setup", "start", "stop", "restart", "logs", "status", "build"],
|
|
help="Action to perform")
|
|
parser.add_argument("--mode", choices=["dev", "prod"], default="dev",
|
|
help="Deployment mode")
|
|
parser.add_argument("--service", help="Specific service for logs")
|
|
parser.add_argument("--follow", action="store_true", help="Follow logs")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Check prerequisites
|
|
if not check_docker():
|
|
logger.error("Docker is required but not available")
|
|
sys.exit(1)
|
|
|
|
if not check_docker_compose():
|
|
logger.error("Docker Compose is required but not available")
|
|
sys.exit(1)
|
|
|
|
# Execute action
|
|
if args.action == "setup":
|
|
logger.info("Setting up AMO CRM service with FastStream...")
|
|
create_env_file()
|
|
create_directories()
|
|
|
|
if build_images():
|
|
logger.info("Setup completed successfully!")
|
|
logger.info("Next steps:")
|
|
logger.info("1. Edit .env file with your configuration")
|
|
logger.info("2. Run: python scripts/docker_setup.py start")
|
|
else:
|
|
logger.error("Setup failed during image build")
|
|
sys.exit(1)
|
|
|
|
elif args.action == "build":
|
|
if not build_images():
|
|
logger.error("Build failed")
|
|
sys.exit(1)
|
|
|
|
elif args.action == "start":
|
|
if not start_services(args.mode):
|
|
logger.error("Failed to start services")
|
|
sys.exit(1)
|
|
|
|
logger.info("Services started successfully!")
|
|
logger.info("API available at: http://localhost:8000")
|
|
logger.info("API documentation: http://localhost:8000/docs")
|
|
|
|
elif args.action == "stop":
|
|
if not stop_services():
|
|
logger.error("Failed to stop services")
|
|
sys.exit(1)
|
|
|
|
elif args.action == "restart":
|
|
logger.info("Restarting services...")
|
|
stop_services()
|
|
if not start_services(args.mode):
|
|
logger.error("Failed to restart services")
|
|
sys.exit(1)
|
|
|
|
elif args.action == "logs":
|
|
show_logs(args.service, args.follow)
|
|
|
|
elif args.action == "status":
|
|
show_status()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|