Skip to content
Draft
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/9372.fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Migrate groups table's `container_registry` to `container_registry_id` based schema
28 changes: 18 additions & 10 deletions docs/manager/graphql-reference/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -941,11 +941,13 @@
integration_id: String
resource_policy: String

"""
Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.
"""
container_registry: JSONString

Check notice on line 947 in docs/manager/graphql-reference/schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Field 'GroupNode.container_registry' description changed from 'Added in 24.03.7.' to 'Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.'

Field 'GroupNode.container_registry' description changed from 'Added in 24.03.7.' to 'Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.'

"""Added in 24.03.7. One of ['GENERAL', 'MODEL_STORE']."""
type: String

"""Added in 24.03.7."""
container_registry: JSONString
scaling_groups: [String]

"""Added in 25.3.0."""
Expand Down Expand Up @@ -1068,11 +1070,13 @@
integration_id: String
resource_policy: String

"""Added in 24.03.0."""
type: String
"""
Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.
"""
container_registry: JSONString

Check notice on line 1076 in docs/manager/graphql-reference/schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Field 'Group.container_registry' description changed from 'Added in 24.03.0.' to 'Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.'

Field 'Group.container_registry' description changed from 'Added in 24.03.0.' to 'Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.'

"""Added in 24.03.0."""
container_registry: JSONString
type: String
scaling_groups: [String]
}

Expand Down Expand Up @@ -2698,7 +2702,7 @@
group: Group
}

input GroupInput {

Check failure on line 2705 in docs/manager/graphql-reference/schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Input field 'container_registry' was removed from input object type 'GroupInput'

Removing an input field will cause existing queries that use this input field to error.
"""Added in 24.03.0. Available values: GENERAL, MODEL_STORE"""
type: String = "GENERAL"
description: String = ""
Expand All @@ -2709,8 +2713,10 @@
integration_id: String = ""
resource_policy: String = "default"

"""Added in 24.03.0"""
container_registry: JSONString = "{}"
"""
Added in 25.3.0. The default container registry used as the target for session commits when no container registry is explicitly specified.
"""
container_registry_id: UUID

Check warning on line 2719 in docs/manager/graphql-reference/schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Input field 'container_registry_id' was added to input object type 'GroupInput'

Input field 'container_registry_id' was added to input object type 'GroupInput'
}

type ModifyGroup {
Expand All @@ -2719,7 +2725,7 @@
group: Group
}

input ModifyGroupInput {

Check failure on line 2728 in docs/manager/graphql-reference/schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Input field 'container_registry' was removed from input object type 'ModifyGroupInput'

Removing an input field will cause existing queries that use this input field to error.
name: String
description: String
is_active: Boolean
Expand All @@ -2731,8 +2737,10 @@
integration_id: String
resource_policy: String

"""Added in 24.03.0"""
container_registry: JSONString = "{}"
"""
Added in 25.3.0. The default container registry used as the target for session commits when no container registry is explicitly specified.
"""
container_registry_id: UUID

Check warning on line 2743 in docs/manager/graphql-reference/schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Input field 'container_registry_id' was added to input object type 'ModifyGroupInput'

Input field 'container_registry_id' was added to input object type 'ModifyGroupInput'
}

"""Instead of deleting the group, just mark it as inactive."""
Expand Down
28 changes: 18 additions & 10 deletions docs/manager/graphql-reference/supergraph.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -4607,11 +4607,13 @@ type Group
integration_id: String
resource_policy: String

"""Added in 24.03.0."""
type: String
"""
Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.
"""
container_registry: JSONString

"""Added in 24.03.0."""
container_registry: JSONString
type: String
scaling_groups: [String]
}

Expand Down Expand Up @@ -4653,8 +4655,10 @@ input GroupInput
integration_id: String = ""
resource_policy: String = "default"

"""Added in 24.03.0"""
container_registry: JSONString = "{}"
"""
Added in 25.3.0. The default container registry used as the target for session commits when no container registry is explicitly specified.
"""
container_registry_id: UUID
}

type GroupNode implements Node
Expand All @@ -4678,11 +4682,13 @@ type GroupNode implements Node
integration_id: String @join__field(graph: GRAPHENE)
resource_policy: String @join__field(graph: GRAPHENE)

"""
Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.
"""
container_registry: JSONString @join__field(graph: GRAPHENE)

"""Added in 24.03.7. One of ['GENERAL', 'MODEL_STORE']."""
type: String @join__field(graph: GRAPHENE)

"""Added in 24.03.7."""
container_registry: JSONString @join__field(graph: GRAPHENE)
scaling_groups: [String] @join__field(graph: GRAPHENE)

"""Added in 25.3.0."""
Expand Down Expand Up @@ -6421,8 +6427,10 @@ input ModifyGroupInput
integration_id: String
resource_policy: String

"""Added in 24.03.0"""
container_registry: JSONString = "{}"
"""
Added in 25.3.0. The default container registry used as the target for session commits when no container registry is explicitly specified.
"""
container_registry_id: UUID
}

type ModifyImage
Expand Down
14 changes: 14 additions & 0 deletions src/ai/backend/common/dto/manager/group/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ class CreateGroupRequest(BaseRequestModel):
)
integration_id: str | None = Field(default=None, description="External integration ID")
resource_policy: str | None = Field(default=None, description="Resource policy name")
container_registry_id: UUID | None = Field(
default=None,
description=(
"The default container registry used as the target for session commits"
" when no container registry is explicitly specified."
),
)


class UpdateGroupRequest(BaseRequestModel):
Expand All @@ -77,6 +84,13 @@ class UpdateGroupRequest(BaseRequestModel):
)
integration_id: str | None = Field(default=None, description="Updated external integration ID")
resource_policy: str | None = Field(default=None, description="Updated resource policy name")
container_registry_id: UUID | None = Field(
default=None,
description=(
"The default container registry used as the target for session commits"
" when no container registry is explicitly specified."
),
)


class AddGroupMembersRequest(BaseRequestModel):
Expand Down
8 changes: 6 additions & 2 deletions src/ai/backend/common/dto/manager/group/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ class GroupDTO(BaseModel):
default=None, description="Allowed vfolder host permissions"
)
resource_policy: str | None = Field(default=None, description="Resource policy name")
container_registry: dict[str, Any] | None = Field(
default=None, description="Container registry configuration"
container_registry_id: UUID | None = Field(
default=None,
description=(
"The default container registry used as the target for session commits"
" when no container registry is explicitly specified."
),
)


Expand Down
98 changes: 82 additions & 16 deletions src/ai/backend/manager/api/gql_legacy/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,15 @@
from ai.backend.manager.models.rbac.context import ClientContext
from ai.backend.manager.models.rbac.permission_defs import ProjectPermission
from ai.backend.manager.models.user import UserRole
from ai.backend.manager.repositories.base import BatchQuerier, NoPagination
from ai.backend.manager.repositories.base.creator import Creator
from ai.backend.manager.repositories.base.updater import Updater
from ai.backend.manager.repositories.container_registry.options import ContainerRegistryConditions
from ai.backend.manager.repositories.group.creators import GroupCreatorSpec
from ai.backend.manager.repositories.group.updaters import GroupUpdaterSpec
from ai.backend.manager.services.container_registry.actions.search_container_registries import (
SearchContainerRegistriesAction,
)
from ai.backend.manager.services.group.actions.create_group import CreateGroupAction
from ai.backend.manager.services.group.actions.delete_group import (
DeleteGroupAction,
Expand Down Expand Up @@ -95,6 +100,8 @@ class GroupNode(graphene.ObjectType): # type: ignore[misc]
class Meta:
interfaces = (AsyncNode,)

_container_registry_id: uuid.UUID | None = None

row_id = graphene.UUID(description="Added in 24.03.7. The undecoded id value stored in DB.")
name = graphene.String()
description = graphene.String()
Expand All @@ -106,8 +113,10 @@ class Meta:
allowed_vfolder_hosts = graphene.JSONString()
integration_id = graphene.String()
resource_policy = graphene.String()
container_registry = graphene.JSONString(
description="Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.",
)
type = graphene.String(description=f"Added in 24.03.7. One of {[t.name for t in ProjectType]}.")
container_registry = graphene.JSONString(description="Added in 24.03.7.")
scaling_groups = graphene.List(
lambda: graphene.String,
)
Expand Down Expand Up @@ -144,7 +153,7 @@ def from_row(
graph_ctx: GraphQueryContext,
row: GroupRow,
) -> Self:
return cls(
obj = cls(
id=row.id,
row_id=row.id,
name=row.name,
Expand All @@ -158,8 +167,9 @@ def from_row(
integration_id=row.integration_id,
resource_policy=row.resource_policy,
type=row.type.name,
container_registry=row.container_registry,
)
obj._container_registry_id = row.container_registry_id
return obj

async def resolve_scaling_groups(self, info: graphene.ResolveInfo) -> Sequence[ScalingGroup]:
graph_ctx: GraphQueryContext = info.context
Expand All @@ -170,6 +180,30 @@ async def resolve_scaling_groups(self, info: graphene.ResolveInfo) -> Sequence[S
sgroups = await loader.load(self.id)
return [sg.name for sg in sgroups]

async def resolve_container_registry(
self, info: graphene.ResolveInfo
) -> dict[str, str | None] | None:
if self._container_registry_id is None:
return None
graph_ctx: GraphQueryContext = info.context
registry_id = uuid.UUID(str(self._container_registry_id))
action = SearchContainerRegistriesAction(
querier=BatchQuerier(
pagination=NoPagination(),
conditions=[ContainerRegistryConditions.by_ids([registry_id])],
),
)
result = await graph_ctx.processors.container_registry.search_container_registries.wait_for_complete(
action
)
if not result.data:
return None
registry = result.data[0]
return {
"registry": registry.registry_name,
"project": registry.project,
}

async def resolve_user_nodes(
self,
info: graphene.ResolveInfo,
Expand Down Expand Up @@ -343,6 +377,8 @@ def parse_value(value: str) -> ProjectPermission:


class Group(graphene.ObjectType): # type: ignore[misc]
_container_registry_id: uuid.UUID | None = None

id = graphene.UUID()
name = graphene.String()
description = graphene.String()
Expand All @@ -354,16 +390,18 @@ class Group(graphene.ObjectType): # type: ignore[misc]
allowed_vfolder_hosts = graphene.JSONString()
integration_id = graphene.String()
resource_policy = graphene.String()
container_registry = graphene.JSONString(
description="Added in 24.03.0. The default container registry resolved from container_registry_id. Kept for backward compatibility.",
)
type = graphene.String(description="Added in 24.03.0.")
container_registry = graphene.JSONString(description="Added in 24.03.0.")

scaling_groups = graphene.List(lambda: graphene.String)

@classmethod
def from_row(cls, graph_ctx: GraphQueryContext, row: Row[Any] | None) -> Group | None:
if row is None:
return None
return cls(
obj = cls(
id=row.id,
name=row.name,
description=row.description,
Expand All @@ -378,14 +416,15 @@ def from_row(cls, graph_ctx: GraphQueryContext, row: Row[Any] | None) -> Group |
integration_id=row.integration_id,
resource_policy=row.resource_policy,
type=row.type.name,
container_registry=row.container_registry,
)
obj._container_registry_id = row.container_registry_id
return obj

@classmethod
def from_dto(cls, dto: GroupData | None) -> Self | None:
if dto is None:
return None
return cls(
obj = cls(
id=dto.id,
name=dto.name,
description=dto.description,
Expand All @@ -400,8 +439,33 @@ def from_dto(cls, dto: GroupData | None) -> Self | None:
integration_id=dto.integration_id,
resource_policy=dto.resource_policy,
type=dto.type.name,
container_registry=dto.container_registry,
)
obj._container_registry_id = dto.container_registry_id
return obj

async def resolve_container_registry(
self, info: graphene.ResolveInfo
) -> dict[str, str | None] | None:
if self._container_registry_id is None:
return None
graph_ctx: GraphQueryContext = info.context
registry_id = uuid.UUID(str(self._container_registry_id))
action = SearchContainerRegistriesAction(
querier=BatchQuerier(
pagination=NoPagination(),
conditions=[ContainerRegistryConditions.by_ids([registry_id])],
),
)
result = await graph_ctx.processors.container_registry.search_container_registries.wait_for_complete(
action
)
if not result.data:
return None
registry = result.data[0]
return {
"registry": registry.registry_name,
"project": registry.project,
}

async def resolve_scaling_groups(self, info: graphene.ResolveInfo) -> Sequence[ScalingGroup]:
graph_ctx: GraphQueryContext = info.context
Expand Down Expand Up @@ -555,8 +619,9 @@ class GroupInput(graphene.InputObjectType): # type: ignore[misc]
allowed_vfolder_hosts = graphene.JSONString(required=False, default_value={})
integration_id = graphene.String(required=False, default_value="")
resource_policy = graphene.String(required=False, default_value="default")
container_registry = graphene.JSONString(
required=False, default_value={}, description="Added in 24.03.0"
container_registry_id = graphene.UUID(
required=False,
description="Added in 25.3.0. The default container registry used as the target for session commits when no container registry is explicitly specified.",
)

def to_action(self, name: str) -> CreateGroupAction:
Expand All @@ -578,7 +643,7 @@ def value_or_none(value: Any) -> Any:
)
integration_id_val = value_or_none(self.integration_id)
resource_policy_val = value_or_none(self.resource_policy)
container_registry_val = value_or_none(self.container_registry)
container_registry_id_val = value_or_none(self.container_registry_id)

return CreateGroupAction(
creator=Creator(
Expand All @@ -592,7 +657,7 @@ def value_or_none(value: Any) -> Any:
allowed_vfolder_hosts=allowed_vfolder_hosts_val,
integration_id=integration_id_val,
resource_policy=resource_policy_val,
container_registry=container_registry_val,
container_registry_id=container_registry_id_val,
)
),
)
Expand All @@ -609,8 +674,9 @@ class ModifyGroupInput(graphene.InputObjectType): # type: ignore[misc]
allowed_vfolder_hosts = graphene.JSONString(required=False)
integration_id = graphene.String(required=False)
resource_policy = graphene.String(required=False)
container_registry = graphene.JSONString(
required=False, default_value={}, description="Added in 24.03.0"
container_registry_id = graphene.UUID(
required=False,
description="Added in 25.3.0. The default container registry used as the target for session commits when no container registry is explicitly specified.",
)

def to_action(self, group_id: uuid.UUID) -> ModifyGroupAction:
Expand Down Expand Up @@ -641,8 +707,8 @@ def to_action(self, group_id: uuid.UUID) -> ModifyGroupAction:
resource_policy=OptionalState[str].from_graphql(
self.resource_policy,
),
container_registry=TriState[dict[str, str]].from_graphql(
self.container_registry,
container_registry_id=TriState[uuid.UUID].from_graphql(
self.container_registry_id,
),
)
return ModifyGroupAction(
Expand Down
Loading
Loading