Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/10033.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Apply RBAC permission validators to model deployment service actions
8 changes: 4 additions & 4 deletions src/ai/backend/manager/api/rest/service/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,9 @@ async def update_route(
traffic_ratio=params.traffic_ratio,
)

result = await self._model_serving.update_route.wait_for_complete(action)
await self._model_serving.update_route.wait_for_complete(action)

resp = SuccessResponseModel(success=result.success)
resp = SuccessResponseModel(success=True)
return APIResponse.build(HTTPStatus.OK, resp)

# ------------------------------------------------------------------
Expand All @@ -494,9 +494,9 @@ async def delete_route(
route_id=path_params.route_id,
)

result = await self._model_serving.delete_route.wait_for_complete(action)
await self._model_serving.delete_route.wait_for_complete(action)

resp = SuccessResponseModel(success=result.success)
resp = SuccessResponseModel(success=True)
return APIResponse.build(HTTPStatus.OK, resp)

# ------------------------------------------------------------------
Expand Down
34 changes: 33 additions & 1 deletion src/ai/backend/manager/services/model_serving/actions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,42 @@

from ai.backend.common.data.permission.types import EntityType
from ai.backend.manager.actions.action import BaseAction
from ai.backend.manager.actions.action.scope import BaseScopeAction, BaseScopeActionResult
from ai.backend.manager.actions.action.single_entity import (
BaseSingleEntityAction,
BaseSingleEntityActionResult,
)
from ai.backend.manager.actions.action.types import FieldData


class ModelServiceAction(BaseAction):
@override
@classmethod
def entity_type(cls) -> EntityType:
return EntityType.MODEL_SERVICE
return EntityType.MODEL_DEPLOYMENT


class ModelServiceScopeAction(BaseScopeAction):
@override
@classmethod
def entity_type(cls) -> EntityType:
return EntityType.MODEL_DEPLOYMENT


class ModelServiceScopeActionResult(BaseScopeActionResult):
pass


class ModelServiceSingleEntityAction(BaseSingleEntityAction):
@override
@classmethod
def entity_type(cls) -> EntityType:
return EntityType.MODEL_DEPLOYMENT

@override
def field_data(self) -> FieldData | None:
return None


class ModelServiceSingleEntityActionResult(BaseSingleEntityActionResult):
pass
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,50 @@
from dataclasses import dataclass
from typing import override

from ai.backend.manager.actions.action import BaseActionResult
from ai.backend.common.data.permission.types import RBACElementType, ScopeType
from ai.backend.manager.actions.types import ActionOperationType
from ai.backend.manager.data.model_serving.creator import ModelServiceCreator
from ai.backend.manager.data.model_serving.types import ServiceInfo
from ai.backend.manager.services.model_serving.actions.base import ModelServiceAction
from ai.backend.manager.data.permission.types import RBACElementRef
from ai.backend.manager.services.model_serving.actions.base import (
ModelServiceScopeAction,
ModelServiceScopeActionResult,
)


@dataclass
class CreateModelServiceAction(ModelServiceAction):
class CreateModelServiceAction(ModelServiceScopeAction):
request_user_id: uuid.UUID
creator: ModelServiceCreator

@override
def entity_id(self) -> str | None:
return None
_project_id: uuid.UUID

@override
@classmethod
def operation_type(cls) -> ActionOperationType:
return ActionOperationType.CREATE

@override
def scope_type(self) -> ScopeType:
return ScopeType.PROJECT

@override
def scope_id(self) -> str:
return str(self._project_id)

@override
def target_element(self) -> RBACElementRef:
return RBACElementRef(RBACElementType.PROJECT, str(self._project_id))


@dataclass
class CreateModelServiceActionResult(BaseActionResult):
class CreateModelServiceActionResult(ModelServiceScopeActionResult):
data: ServiceInfo
_project_id: uuid.UUID

@override
def scope_type(self) -> ScopeType:
return ScopeType.PROJECT

@override
def entity_id(self) -> str | None:
return str(self.data.endpoint_id)
def scope_id(self) -> str:
return str(self._project_id)
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,37 @@
from dataclasses import dataclass
from typing import override

from ai.backend.manager.actions.action import BaseActionResult
from ai.backend.common.data.permission.types import RBACElementType
from ai.backend.manager.actions.types import ActionOperationType
from ai.backend.manager.services.model_serving.actions.base import ModelServiceAction
from ai.backend.manager.data.permission.types import RBACElementRef
from ai.backend.manager.services.model_serving.actions.base import (
ModelServiceSingleEntityAction,
ModelServiceSingleEntityActionResult,
)


@dataclass
class DeleteModelServiceAction(ModelServiceAction):
class DeleteModelServiceAction(ModelServiceSingleEntityAction):
service_id: uuid.UUID

@override
def entity_id(self) -> str | None:
return None

@override
@classmethod
def operation_type(cls) -> ActionOperationType:
return ActionOperationType.DELETE

@override
def target_entity_id(self) -> str:
return str(self.service_id)

@override
def target_element(self) -> RBACElementRef:
return RBACElementRef(RBACElementType.MODEL_DEPLOYMENT, str(self.service_id))


@dataclass
class DeleteModelServiceActionResult(BaseActionResult):
success: bool
class DeleteModelServiceActionResult(ModelServiceSingleEntityActionResult):
service_id: uuid.UUID

@override
def entity_id(self) -> str | None:
return None
def target_entity_id(self) -> str:
return str(self.service_id)
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,43 @@
from dataclasses import dataclass
from typing import override

from ai.backend.common.data.permission.types import EntityType
from ai.backend.manager.actions.action import BaseActionResult
from ai.backend.common.data.permission.types import EntityType, RBACElementType
from ai.backend.manager.actions.types import ActionOperationType
from ai.backend.manager.services.model_serving.actions.base import ModelServiceAction
from ai.backend.manager.data.permission.types import RBACElementRef
from ai.backend.manager.services.model_serving.actions.base import (
ModelServiceSingleEntityAction,
ModelServiceSingleEntityActionResult,
)


@dataclass
class DeleteRouteAction(ModelServiceAction):
class DeleteRouteAction(ModelServiceSingleEntityAction):
service_id: uuid.UUID
route_id: uuid.UUID

@override
@classmethod
def entity_type(cls) -> EntityType:
return EntityType.DEPLOYMENT_ROUTE

@override
def entity_id(self) -> str | None:
return None
return EntityType.MODEL_DEPLOYMENT
Comment thread
fregataa marked this conversation as resolved.

@override
@classmethod
def operation_type(cls) -> ActionOperationType:
return ActionOperationType.DELETE

@override
def target_entity_id(self) -> str:
return str(self.route_id)
Comment thread
fregataa marked this conversation as resolved.

@override
def target_element(self) -> RBACElementRef:
return RBACElementRef(RBACElementType.MODEL_DEPLOYMENT, str(self.service_id))


@dataclass
class DeleteRouteActionResult(BaseActionResult):
success: bool
class DeleteRouteActionResult(ModelServiceSingleEntityActionResult):
route_id: uuid.UUID

@override
def entity_id(self) -> str | None:
return None
def target_entity_id(self) -> str:
return str(self.route_id)
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,38 @@
from dataclasses import dataclass
from typing import override

from ai.backend.manager.actions.action import BaseActionResult
from ai.backend.common.data.permission.types import RBACElementType
from ai.backend.manager.actions.types import ActionOperationType
from ai.backend.manager.data.model_serving.types import ServiceInfo
from ai.backend.manager.services.model_serving.actions.base import ModelServiceAction
from ai.backend.manager.data.permission.types import RBACElementRef
from ai.backend.manager.services.model_serving.actions.base import (
ModelServiceSingleEntityAction,
ModelServiceSingleEntityActionResult,
)


@dataclass
class GetModelServiceInfoAction(ModelServiceAction):
class GetModelServiceInfoAction(ModelServiceSingleEntityAction):
service_id: uuid.UUID

@override
def entity_id(self) -> str | None:
return None

@override
@classmethod
def operation_type(cls) -> ActionOperationType:
return ActionOperationType.GET

@override
def target_entity_id(self) -> str:
return str(self.service_id)
Comment thread
fregataa marked this conversation as resolved.

@override
def target_element(self) -> RBACElementRef:
return RBACElementRef(RBACElementType.MODEL_DEPLOYMENT, str(self.service_id))


@dataclass
class GetModelServiceInfoActionResult(BaseActionResult):
class GetModelServiceInfoActionResult(ModelServiceSingleEntityActionResult):
data: ServiceInfo

@override
def entity_id(self) -> str | None:
def target_entity_id(self) -> str:
return str(self.data.endpoint_id)
Comment thread
fregataa marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,43 @@
from dataclasses import dataclass
from typing import override

from ai.backend.manager.actions.action import BaseActionResult
from ai.backend.common.data.permission.types import RBACElementType
from ai.backend.manager.actions.types import ActionOperationType
from ai.backend.manager.data.model_serving.types import EndpointData
from ai.backend.manager.data.permission.types import RBACElementRef
from ai.backend.manager.models.endpoint import EndpointRow
from ai.backend.manager.repositories.base.updater import Updater
from ai.backend.manager.services.model_serving.actions.base import ModelServiceAction
from ai.backend.manager.services.model_serving.actions.base import (
ModelServiceSingleEntityAction,
ModelServiceSingleEntityActionResult,
)


@dataclass
class ModifyEndpointAction(ModelServiceAction):
class ModifyEndpointAction(ModelServiceSingleEntityAction):
endpoint_id: uuid.UUID
updater: Updater[EndpointRow]

@override
def entity_id(self) -> str | None:
return None

@override
@classmethod
def operation_type(cls) -> ActionOperationType:
return ActionOperationType.UPDATE

@override
def target_entity_id(self) -> str:
return str(self.endpoint_id)

@override
def target_element(self) -> RBACElementRef:
return RBACElementRef(RBACElementType.MODEL_DEPLOYMENT, str(self.endpoint_id))


@dataclass
class ModifyEndpointActionResult(BaseActionResult):
class ModifyEndpointActionResult(ModelServiceSingleEntityActionResult):
endpoint_id: uuid.UUID
success: bool
data: EndpointData | None

@override
def entity_id(self) -> str | None:
return str(self.data.id) if self.data is not None else None
def target_entity_id(self) -> str:
return str(self.endpoint_id)
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,44 @@
from dataclasses import dataclass
from typing import override

from ai.backend.common.data.permission.types import EntityType
from ai.backend.manager.actions.action import BaseActionResult
from ai.backend.common.data.permission.types import EntityType, RBACElementType
from ai.backend.manager.actions.types import ActionOperationType
from ai.backend.manager.services.model_serving.actions.base import ModelServiceAction
from ai.backend.manager.data.permission.types import RBACElementRef
from ai.backend.manager.services.model_serving.actions.base import (
ModelServiceSingleEntityAction,
ModelServiceSingleEntityActionResult,
)


@dataclass
class UpdateRouteAction(ModelServiceAction):
class UpdateRouteAction(ModelServiceSingleEntityAction):
service_id: uuid.UUID
route_id: uuid.UUID
traffic_ratio: float

@override
@classmethod
def entity_type(cls) -> EntityType:
return EntityType.DEPLOYMENT_ROUTE

@override
def entity_id(self) -> str | None:
return None
return EntityType.MODEL_DEPLOYMENT
Comment thread
fregataa marked this conversation as resolved.

@override
@classmethod
def operation_type(cls) -> ActionOperationType:
return ActionOperationType.UPDATE

@override
def target_entity_id(self) -> str:
return str(self.route_id)
Comment thread
fregataa marked this conversation as resolved.

@override
def target_element(self) -> RBACElementRef:
return RBACElementRef(RBACElementType.MODEL_DEPLOYMENT, str(self.service_id))


@dataclass
class UpdateRouteActionResult(BaseActionResult):
success: bool
class UpdateRouteActionResult(ModelServiceSingleEntityActionResult):
route_id: uuid.UUID

@override
def entity_id(self) -> str | None:
return None
def target_entity_id(self) -> str:
return str(self.route_id)
Loading
Loading