You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
3.2 KiB
76 lines
3.2 KiB
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends
|
|
|
|
from app.api.dependencies import get_export_service
|
|
from app.core.exceptions import ValidationError
|
|
from app.schemas.export import (
|
|
MetadataExportResponse,
|
|
MetadataImportRequest,
|
|
MetadataImportResponse,
|
|
MetadataRestorePlanResponse,
|
|
MetadataValidationResponse,
|
|
)
|
|
from app.services.export_service import ExportService
|
|
from app.services.job_service import JobService
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/metadata", response_model=MetadataExportResponse)
|
|
async def export_metadata(service: ExportService = Depends(get_export_service)) -> MetadataExportResponse:
|
|
data = await service.export_metadata()
|
|
exported_at = data.pop("exported_at")
|
|
return MetadataExportResponse(exported_at=exported_at, data=data)
|
|
|
|
|
|
@router.get("/metadata/integrity", response_model=MetadataValidationResponse)
|
|
async def metadata_integrity(service: ExportService = Depends(get_export_service)) -> MetadataValidationResponse:
|
|
result = await service.verify_runtime_integrity()
|
|
return MetadataValidationResponse(ok=result["ok"], issues=result["issues"])
|
|
|
|
|
|
@router.post("/metadata/validate", response_model=MetadataValidationResponse)
|
|
async def validate_metadata(
|
|
payload: MetadataImportRequest,
|
|
service: ExportService = Depends(get_export_service),
|
|
) -> MetadataValidationResponse:
|
|
result = await service.validate_metadata_snapshot(payload.data)
|
|
return MetadataValidationResponse(ok=result["ok"], issues=result["issues"])
|
|
|
|
|
|
@router.post("/metadata/restore-plan", response_model=MetadataRestorePlanResponse)
|
|
async def restore_plan(
|
|
payload: MetadataImportRequest,
|
|
service: ExportService = Depends(get_export_service),
|
|
) -> MetadataRestorePlanResponse:
|
|
result = await service.build_restore_plan(payload.data)
|
|
return MetadataRestorePlanResponse(
|
|
ok=result["ok"],
|
|
issues=result["issues"],
|
|
validation_token=result["validation_token"],
|
|
summary=result["summary"],
|
|
)
|
|
|
|
|
|
@router.post("/metadata/import", response_model=MetadataImportResponse)
|
|
async def import_metadata(
|
|
payload: MetadataImportRequest,
|
|
service: ExportService = Depends(get_export_service),
|
|
) -> MetadataImportResponse:
|
|
if not payload.confirm_replace:
|
|
raise ValidationError("Metadata import requires confirm_replace=true.")
|
|
restore_plan_result = await service.build_restore_plan(payload.data)
|
|
if not restore_plan_result["ok"]:
|
|
raise ValidationError("Metadata snapshot is invalid and cannot be imported.")
|
|
if payload.validation_token != restore_plan_result["validation_token"]:
|
|
raise ValidationError("Metadata import requires a current validation_token from restore-plan.")
|
|
imported_tables = await service.import_metadata(payload.data)
|
|
job_service = JobService(service.session)
|
|
reconcile_job = await job_service.enqueue_full_reconcile()
|
|
health_job_count = 0
|
|
for backend in await job_service.backend_repository.list_enabled():
|
|
await job_service.enqueue_backend_health_check(backend.id)
|
|
health_job_count += 1
|
|
scheduled_jobs = [reconcile_job.kind] + ["check_backend_health"] * health_job_count
|
|
return MetadataImportResponse(imported_tables=imported_tables, scheduled_jobs=scheduled_jobs)
|
|
|