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.
78 lines
3.0 KiB
78 lines
3.0 KiB
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from fastapi import Query
|
|
|
|
from app.api.dependencies import get_policy_service
|
|
from app.schemas.policy import (
|
|
PlacementDecisionBackendSummary,
|
|
PlacementDecisionResponse,
|
|
PlacementPolicyListResponse,
|
|
PlacementPolicyMutationResponse,
|
|
PlacementPolicySummary,
|
|
UpsertPlacementPolicyRequest,
|
|
)
|
|
from app.services.policy_service import PolicyService
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _policy_to_summary(policy) -> PlacementPolicySummary:
|
|
return PlacementPolicySummary(
|
|
id=policy.id,
|
|
file_class=policy.file_class,
|
|
require_local=policy.require_local,
|
|
stable_replica_count=policy.stable_replica_count,
|
|
opportunistic_replica_count=policy.opportunistic_replica_count,
|
|
preferred_backend_ids=PolicyService._decode_backend_ids(policy.preferred_backend_ids_json),
|
|
excluded_backend_ids=PolicyService._decode_backend_ids(policy.excluded_backend_ids_json),
|
|
max_non_local_size_bytes=policy.max_non_local_size_bytes,
|
|
created_at=policy.created_at,
|
|
updated_at=policy.updated_at,
|
|
)
|
|
|
|
|
|
@router.get("/placement", response_model=PlacementPolicyListResponse)
|
|
async def list_placement_policies(
|
|
service: PolicyService = Depends(get_policy_service),
|
|
) -> PlacementPolicyListResponse:
|
|
policies = await service.list_policies()
|
|
return PlacementPolicyListResponse(items=[_policy_to_summary(policy) for policy in policies])
|
|
|
|
|
|
@router.get("/placement/preview", response_model=PlacementDecisionResponse)
|
|
async def preview_placement_decision(
|
|
mime_type: str | None = Query(default=None),
|
|
size_bytes: int | None = Query(default=None, ge=0),
|
|
service: PolicyService = Depends(get_policy_service),
|
|
) -> PlacementDecisionResponse:
|
|
decision = await service.get_placement_decision(mime_type, size_bytes=size_bytes)
|
|
return PlacementDecisionResponse(
|
|
file_class=decision.file_class,
|
|
mime_type=mime_type,
|
|
size_bytes=size_bytes,
|
|
non_local_allowed=decision.non_local_allowed,
|
|
policy=_policy_to_summary(decision.policy),
|
|
selected_backends=[
|
|
PlacementDecisionBackendSummary.model_validate(backend, from_attributes=True)
|
|
for backend in decision.backends
|
|
],
|
|
)
|
|
|
|
|
|
@router.put("/placement/{file_class}", response_model=PlacementPolicyMutationResponse)
|
|
async def upsert_placement_policy(
|
|
file_class: str,
|
|
payload: UpsertPlacementPolicyRequest,
|
|
service: PolicyService = Depends(get_policy_service),
|
|
) -> PlacementPolicyMutationResponse:
|
|
policy = await service.upsert_policy(
|
|
file_class=file_class,
|
|
require_local=payload.require_local,
|
|
stable_replica_count=payload.stable_replica_count,
|
|
opportunistic_replica_count=payload.opportunistic_replica_count,
|
|
preferred_backend_ids=payload.preferred_backend_ids,
|
|
excluded_backend_ids=payload.excluded_backend_ids,
|
|
max_non_local_size_bytes=payload.max_non_local_size_bytes,
|
|
)
|
|
return PlacementPolicyMutationResponse(policy=_policy_to_summary(policy))
|
|
|