ALM-2 / backend /api /routes /sqlite_fallback_routes.py
ACA050's picture
Upload 520 files
2ed8996 verified
Raw
History Blame Contribute Delete
13 kB
"""
API routes for SQLite fallback database management.
Provides endpoints for monitoring, testing, and managing
the SQLite fallback database system.
"""
import logging
from typing import Dict, Any
from fastapi import APIRouter, HTTPException, status, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from core.database import get_db
from core.fallback_database import (
check_database_health,
get_current_database_type,
switch_to_primary,
switch_to_fallback
)
from core.sqlite_fallback_manager import SQLiteFallbackManager, test_fallback_mechanism
from schemas.response_schema import SuccessResponse, ErrorResponse
from api.dependencies.auth import get_current_active_user
from db_models.user import User
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/sqlite-fallback", tags=["sqlite-fallback"])
@router.get("/status", response_model=SuccessResponse)
async def get_fallback_status(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Get SQLite fallback database status.
Args:
current_user: Current authenticated user
db: Database session
Returns:
SuccessResponse: Fallback database status
Raises:
HTTPException: If status check fails
"""
try:
# Only allow superusers to access fallback status
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. Superuser access required."
)
manager = SQLiteFallbackManager()
status_info = await manager.get_fallback_status()
# Add current database type information
is_healthy, active_db_type = await check_database_health()
status_info.update({
"current_active_database": active_db_type,
"overall_healthy": is_healthy
})
return SuccessResponse(
message="SQLite fallback status retrieved successfully",
data=status_info
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to get fallback status: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to retrieve fallback status"
)
@router.post("/test", response_model=SuccessResponse)
async def test_fallback_system(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Test SQLite fallback mechanism.
Args:
current_user: Current authenticated user
db: Database session
Returns:
SuccessResponse: Test results
Raises:
HTTPException: If test fails
"""
try:
# Only allow superusers to test fallback system
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. Superuser access required."
)
test_results = await test_fallback_mechanism()
return SuccessResponse(
message="SQLite fallback test completed",
data=test_results
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to test fallback system: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to test fallback system"
)
@router.post("/switch-to-primary", response_model=SuccessResponse)
async def force_switch_to_primary(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Force switch back to primary PostgreSQL database.
Args:
current_user: Current authenticated user
db: Database session
Returns:
SuccessResponse: Switch operation result
Raises:
HTTPException: If switch fails
"""
try:
# Only allow superusers to switch databases
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. Superuser access required."
)
success = await switch_to_primary()
if success:
return SuccessResponse(
message="Successfully switched to primary PostgreSQL database",
data={"current_database": "primary"}
)
else:
return SuccessResponse(
message="Failed to switch to primary database - database not available",
data={"current_database": get_current_database_type()}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to switch to primary database: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to switch to primary database"
)
@router.post("/switch-to-fallback", response_model=SuccessResponse)
async def force_switch_to_fallback(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Force switch to SQLite fallback database.
Args:
current_user: Current authenticated user
db: Database session
Returns:
SuccessResponse: Switch operation result
Raises:
HTTPException: If switch fails
"""
try:
# Only allow superusers to switch databases
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. Superuser access required."
)
success = await switch_to_fallback()
if success:
return SuccessResponse(
message="Successfully switched to SQLite fallback database",
data={"current_database": "fallback"}
)
else:
return SuccessResponse(
message="Failed to switch to fallback database - fallback not available",
data={"current_database": get_current_database_type()}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to switch to fallback database: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to switch to fallback database"
)
@router.post("/migrate-from-primary", response_model=SuccessResponse)
async def migrate_from_primary_database(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Migrate data from primary PostgreSQL to SQLite fallback.
Args:
current_user: Current authenticated user
db: Database session
Returns:
SuccessResponse: Migration result
Raises:
HTTPException: If migration fails
"""
try:
# Only allow superusers to perform migration
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. Superuser access required."
)
manager = SQLiteFallbackManager()
success = await manager.migrate_from_postgresql()
if success:
return SuccessResponse(
message="Data migration from PostgreSQL to SQLite completed successfully",
data={"migration_status": "completed"}
)
else:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Data migration failed"
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to migrate from primary database: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to migrate from primary database"
)
@router.post("/sync-to-primary", response_model=SuccessResponse)
async def sync_to_primary_database(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Sync data from SQLite fallback back to primary PostgreSQL.
Args:
current_user: Current authenticated user
db: Database session
Returns:
SuccessResponse: Sync result
Raises:
HTTPException: If sync fails
"""
try:
# Only allow superusers to perform sync
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. Superuser access required."
)
manager = SQLiteFallbackManager()
success = await manager.sync_to_postgresql()
if success:
return SuccessResponse(
message="Data sync from SQLite to PostgreSQL completed successfully",
data={"sync_status": "completed"}
)
else:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Data sync failed"
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to sync to primary database: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to sync to primary database"
)
@router.post("/backup", response_model=SuccessResponse)
async def backup_fallback_database(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Create backup of SQLite fallback database.
Args:
current_user: Current authenticated user
db: Database session
Returns:
SuccessResponse: Backup result
Raises:
HTTPException: If backup fails
"""
try:
# Only allow superusers to create backups
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. Superuser access required."
)
manager = SQLiteFallbackManager()
success = await manager.backup_fallback_database()
if success:
return SuccessResponse(
message="SQLite fallback database backup created successfully",
data={"backup_status": "completed"}
)
else:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Database backup failed"
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to backup fallback database: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to backup fallback database"
)
@router.delete("/cleanup", response_model=SuccessResponse)
async def cleanup_fallback_database(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Clean up (remove) SQLite fallback database file.
Args:
current_user: Current authenticated user
db: Database session
Returns:
SuccessResponse: Cleanup result
Raises:
HTTPException: If cleanup fails
"""
try:
# Only allow superusers to cleanup database
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. Superuser access required."
)
manager = SQLiteFallbackManager()
success = await manager.cleanup_fallback_database()
if success:
return SuccessResponse(
message="SQLite fallback database cleaned up successfully",
data={"cleanup_status": "completed"}
)
else:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Database cleanup failed"
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to cleanup fallback database: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to cleanup fallback database"
)