Skip to content

Commit

Permalink
feat: implement Relay-style VirtualFolderNode GQL query (#2165)
Browse files Browse the repository at this point in the history
This PR adds new `VirtualFolderNode` GQL Query, which acts as an another version of `VirtualFolder` GQL Query with relay support.

<!-- readthedocs-preview sorna start -->
----
📚 Documentation preview 📚: https://sorna--2165.org.readthedocs.build/en/2165/

<!-- readthedocs-preview sorna end -->

<!-- readthedocs-preview sorna-ko start -->
----
📚 Documentation preview 📚: https://sorna-ko--2165.org.readthedocs.build/ko/2165/

<!-- readthedocs-preview sorna-ko end -->
  • Loading branch information
kyujin-cho committed May 28, 2024
1 parent 3d5d53a commit 7b0b9d3
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 4 deletions.
1 change: 1 addition & 0 deletions changes/2165.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add relay-aware `VirtualFolderNode` GQL Query
52 changes: 52 additions & 0 deletions src/ai/backend/manager/api/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ type Queries {
storage_volume(id: String): StorageVolume
storage_volume_list(limit: Int!, offset: Int!, filter: String, order: String): StorageVolumeList
vfolder(id: String): VirtualFolder

"""Added in 24.03.4."""
vfolder_node(id: String!): VirtualFolderNode

"""Added in 24.03.4."""
vfolder_nodes(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): VirtualFolderConnection
vfolder_list(limit: Int!, offset: Int!, filter: String, order: String, domain_name: String, group_id: UUID, access_key: String): VirtualFolderList
vfolder_permission_list(limit: Int!, offset: Int!, filter: String, order: String): VirtualFolderPermissionList
vfolder_own_list(limit: Int!, offset: Int!, filter: String, order: String, domain_name: String, access_key: String): VirtualFolderList
Expand Down Expand Up @@ -691,6 +697,52 @@ type StorageVolumeList implements PaginatedList {
total_count: Int!
}

type VirtualFolderNode implements Node {
"""The ID of the object"""
id: ID!
host: String
quota_scope_id: String
name: String
user: UUID
user_email: String
group: UUID
group_name: String
creator: String
unmanaged_path: String
usage_mode: String
permission: String
ownership_type: String
max_files: Int
max_size: BigInt
created_at: DateTime
modified_at: DateTime
last_used: DateTime
num_files: Int
cur_size: BigInt
cloneable: Boolean
status: String
}

type VirtualFolderConnection {
"""Pagination data for this connection."""
pageInfo: PageInfo!

"""Contains the nodes in this connection."""
edges: [VirtualFolderEdge]!

"""Total count of the GQL nodes of the query."""
count: Int
}

"""A Relay edge containing a `VirtualFolder` and its cursor."""
type VirtualFolderEdge {
"""The item at the end of the edge"""
node: VirtualFolderNode

"""A cursor for use in pagination"""
cursor: String!
}

type VirtualFolderList implements PaginatedList {
items: [VirtualFolder]!
total_count: Int!
Expand Down
17 changes: 16 additions & 1 deletion src/ai/backend/manager/models/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from ai.backend.common.types import ClusterMode, ResourceSlot
from ai.backend.manager.defs import SERVICE_MAX_RETRIES

from ..api.exceptions import EndpointNotFound, EndpointTokenNotFound
from ..api.exceptions import EndpointNotFound, EndpointTokenNotFound, ObjectNotFound
from .base import (
GUID,
Base,
Expand All @@ -38,6 +38,7 @@
from .image import ImageNode, ImageRefType, ImageRow
from .routing import RouteStatus, Routing
from .user import UserRole
from .vfolder import VFolderRow, VirtualFolderNode

if TYPE_CHECKING:
from .gql import GraphQueryContext
Expand Down Expand Up @@ -155,6 +156,7 @@ class EndpointRow(Base):
routings = relationship("RoutingRow", back_populates="endpoint_row")
tokens = relationship("EndpointTokenRow", back_populates="endpoint_row")
image_row = relationship("ImageRow", back_populates="endpoints")
model_row = relationship("VFolderRow", back_populates="endpoints")
created_user_row = relationship(
"UserRow", back_populates="created_endpoints", foreign_keys="EndpointRow.created_user"
)
Expand Down Expand Up @@ -437,6 +439,7 @@ class Meta:
resource_slots = graphene.JSONString()
url = graphene.String()
model = graphene.UUID()
model_vfolder = VirtualFolderNode()
model_mount_destiation = graphene.String(
deprecation_reason="Deprecated since 24.03.4; use `model_mount_destination` instead"
)
Expand Down Expand Up @@ -663,6 +666,18 @@ async def resolve_status(self, info: graphene.ResolveInfo) -> str:
return "DEGRADED"
return "PROVISIONING"

async def resolve_model_vfolder(self, info: graphene.ResolveInfo) -> VirtualFolderNode:
if not self.model:
raise ObjectNotFound(object_name="VFolder")

ctx: GraphQueryContext = info.context

async with ctx.db.begin_readonly_session() as sess:
vfolder_row = await VFolderRow.get(
sess, uuid.UUID(self.model), load_user=True, load_group=True
)
return VirtualFolderNode.from_row(info, vfolder_row)

async def resolve_errors(self, info: graphene.ResolveInfo) -> Any:
error_routes = [r for r in self.routings if r.status == RouteStatus.FAILED_TO_START.name]
errors = []
Expand Down
43 changes: 43 additions & 0 deletions src/ai/backend/manager/models/gql.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@
SetQuotaScope,
UnsetQuotaScope,
VirtualFolder,
VirtualFolderConnection,
VirtualFolderList,
VirtualFolderNode,
VirtualFolderPermission,
VirtualFolderPermissionList,
ensure_quota_scope_accessible_by_user,
Expand Down Expand Up @@ -512,6 +514,13 @@ class Queries(graphene.ObjectType):
id=graphene.String(),
)

vfolder_node = graphene.Field(
VirtualFolderNode, id=graphene.String(required=True), description="Added in 24.03.4."
)
vfolder_nodes = PaginatedConnectionField(
VirtualFolderConnection, description="Added in 24.03.4."
)

vfolder_list = graphene.Field( # legacy non-paginated list
VirtualFolderList,
limit=graphene.Int(required=True),
Expand Down Expand Up @@ -846,13 +855,15 @@ async def resolve_domains(
) -> Sequence[Domain]:
return await Domain.load_all(info.context, is_active=is_active)

@staticmethod
async def resolve_group_node(
root: Any,
info: graphene.ResolveInfo,
id: str,
):
return await GroupNode.get_node(info, id)

@staticmethod
async def resolve_group_nodes(
root: Any,
info: graphene.ResolveInfo,
Expand All @@ -876,6 +887,38 @@ async def resolve_group_nodes(
last,
)

@staticmethod
async def resolve_vfolder_node(
root: Any,
info: graphene.ResolveInfo,
id: str,
):
return await VirtualFolderNode.get_node(info, id)

@staticmethod
async def resolve_vfolder_nodes(
root: Any,
info: graphene.ResolveInfo,
*,
filter: str | None = None,
order: str | None = None,
offset: int | None = None,
after: str | None = None,
first: int | None = None,
before: str | None = None,
last: int | None = None,
) -> ConnectionResolverResult:
return await VirtualFolderNode.get_connection(
info,
filter,
order,
offset,
after,
first,
before,
last,
)

@staticmethod
async def resolve_group(
root: Any,
Expand Down
1 change: 1 addition & 0 deletions src/ai/backend/manager/models/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class GroupRow(Base):
users = relationship("AssocGroupUserRow", back_populates="group")
resource_policy_row = relationship("ProjectResourcePolicyRow", back_populates="projects")
kernels = relationship("KernelRow", back_populates="group_row")
vfolder_row = relationship("VFolderRow", back_populates="group_row")


def _build_group_query(cond: sa.sql.BinaryExpression, domain_name: str) -> sa.sql.Select:
Expand Down
2 changes: 2 additions & 0 deletions src/ai/backend/manager/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ class UserRow(Base):

main_keypair = relationship("KeyPairRow", foreign_keys=users.c.main_access_key)

vfolder_row = relationship("VFolderRow", back_populates="user_row")


class UserGroup(graphene.ObjectType):
id = graphene.UUID()
Expand Down
Loading

0 comments on commit 7b0b9d3

Please sign in to comment.