Skip to content
Open
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/9725.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add GraphQL types and resolver stubs for bulk role assignment and revocation
70 changes: 70 additions & 0 deletions docs/manager/graphql-reference/supergraph.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,38 @@ input BlueGreenConfigInput
promoteDelaySeconds: Int! = 0
}

"""
Added in 26.3.0. Error information for a failed user in bulk role assignment.
"""
type BulkAssignRoleError
@join__type(graph: STRAWBERRY)
{
"""UUID of the user that failed."""
userId: UUID!

"""Error message describing the failure."""
message: String!
}

"""Added in 26.3.0. Input for bulk assigning a role to multiple users"""
input BulkAssignRoleInput
@join__type(graph: STRAWBERRY)
{
roleId: UUID!
userIds: [UUID!]!
}

"""Added in 26.3.0. Payload for bulk role assignment mutation."""
type BulkAssignRolePayload
@join__type(graph: STRAWBERRY)
{
"""List of successfully created role assignments."""
assigned: [RoleAssignment!]!

"""List of errors for users that failed to be assigned."""
failed: [BulkAssignRoleError!]!
}

"""Added in 26.2.0. Payload for bulk user creation mutation."""
type BulkCreateUsersV2Payload
@join__type(graph: STRAWBERRY)
Expand Down Expand Up @@ -1502,6 +1534,38 @@ type BulkPurgeUserV2Error
message: String!
}

"""
Added in 26.3.0. Error information for a failed user in bulk role revocation.
"""
type BulkRevokeRoleError
@join__type(graph: STRAWBERRY)
{
"""UUID of the user that failed."""
userId: UUID!

"""Error message describing the failure."""
message: String!
}

"""Added in 26.3.0. Input for bulk revoking a role from multiple users"""
input BulkRevokeRoleInput
@join__type(graph: STRAWBERRY)
{
roleId: UUID!
userIds: [UUID!]!
}

"""Added in 26.3.0. Payload for bulk role revocation mutation."""
type BulkRevokeRolePayload
@join__type(graph: STRAWBERRY)
{
"""List of successfully revoked role assignments."""
revoked: [RoleAssignment!]!

"""List of errors for users that failed to be revoked."""
failed: [BulkRevokeRoleError!]!
}

"""Added in 26.3.0. Payload for bulk user update mutation."""
type BulkUpdateUsersV2Payload
@join__type(graph: STRAWBERRY)
Expand Down Expand Up @@ -7515,6 +7579,12 @@ type Mutation

"""Added in 26.3.0. Revoke a role from a user (admin only)."""
adminRevokeRole(input: RevokeRoleInput!): RoleAssignment! @join__field(graph: STRAWBERRY)

"""Added in 26.3.0. Bulk assign a role to multiple users (admin only)."""
adminBulkAssignRole(input: BulkAssignRoleInput!): BulkAssignRolePayload! @join__field(graph: STRAWBERRY)

"""Added in 26.3.0. Bulk revoke a role from multiple users (admin only)."""
adminBulkRevokeRole(input: BulkRevokeRoleInput!): BulkRevokeRolePayload! @join__field(graph: STRAWBERRY)
}

"""Added in 24.12.0."""
Expand Down
58 changes: 58 additions & 0 deletions docs/manager/graphql-reference/v2-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,32 @@ input BlueGreenConfigInput {
promoteDelaySeconds: Int! = 0
}

"""
Added in 26.3.0. Error information for a failed user in bulk role assignment.
"""
type BulkAssignRoleError {
"""UUID of the user that failed."""
userId: UUID!

"""Error message describing the failure."""
message: String!
}

"""Added in 26.3.0. Input for bulk assigning a role to multiple users"""
input BulkAssignRoleInput {
roleId: UUID!
userIds: [UUID!]!
}

"""Added in 26.3.0. Payload for bulk role assignment mutation."""
type BulkAssignRolePayload {
"""List of successfully created role assignments."""
assigned: [RoleAssignment!]!

"""List of errors for users that failed to be assigned."""
failed: [BulkAssignRoleError!]!
}

"""Added in 26.2.0. Error information for a failed user in bulk creation."""
type BulkCreateUserV2Error {
"""Original position in the input list."""
Expand Down Expand Up @@ -975,6 +1001,32 @@ type BulkPurgeUsersV2Payload {
failed: [BulkPurgeUserV2Error!]!
}

"""
Added in 26.3.0. Error information for a failed user in bulk role revocation.
"""
type BulkRevokeRoleError {
"""UUID of the user that failed."""
userId: UUID!

"""Error message describing the failure."""
message: String!
}

"""Added in 26.3.0. Input for bulk revoking a role from multiple users"""
input BulkRevokeRoleInput {
roleId: UUID!
userIds: [UUID!]!
}

"""Added in 26.3.0. Payload for bulk role revocation mutation."""
type BulkRevokeRolePayload {
"""List of successfully revoked role assignments."""
revoked: [RoleAssignment!]!

"""List of errors for users that failed to be revoked."""
failed: [BulkRevokeRoleError!]!
}

"""Added in 26.3.0. Error information for a failed user in bulk update."""
type BulkUpdateUserV2Error {
"""UUID of the user that failed to update."""
Expand Down Expand Up @@ -3948,6 +4000,12 @@ type Mutation {

"""Added in 26.3.0. Revoke a role from a user (admin only)."""
adminRevokeRole(input: RevokeRoleInput!): RoleAssignment!

"""Added in 26.3.0. Bulk assign a role to multiple users (admin only)."""
adminBulkAssignRole(input: BulkAssignRoleInput!): BulkAssignRolePayload!

"""Added in 26.3.0. Bulk revoke a role from multiple users (admin only)."""
adminBulkRevokeRole(input: BulkRevokeRoleInput!): BulkRevokeRolePayload!
}

"""An object with a Globally Unique ID"""
Expand Down
13 changes: 13 additions & 0 deletions src/ai/backend/manager/api/gql/rbac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from .resolver import (
admin_assign_role,
admin_bulk_assign_role,
admin_bulk_revoke_role,
admin_create_permission,
admin_create_role,
admin_delete_permission,
Expand All @@ -19,6 +21,10 @@
)
from .types import (
AssignRoleInput,
BulkAssignRoleInput,
BulkAssignRolePayloadGQL,
BulkRevokeRoleInput,
BulkRevokeRolePayloadGQL,
CreatePermissionInput,
CreateRoleInput,
EntityConnection,
Expand Down Expand Up @@ -72,6 +78,11 @@
"CreatePermissionInput",
"AssignRoleInput",
"RevokeRoleInput",
"BulkAssignRoleInput",
"BulkRevokeRoleInput",
# Payloads
"BulkAssignRolePayloadGQL",
"BulkRevokeRolePayloadGQL",
# Connections
"RoleConnection",
"PermissionConnection",
Expand All @@ -94,4 +105,6 @@
"admin_delete_permission",
"admin_assign_role",
"admin_revoke_role",
"admin_bulk_assign_role",
"admin_bulk_revoke_role",
)
4 changes: 4 additions & 0 deletions src/ai/backend/manager/api/gql/rbac/resolver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
)
from .role import (
admin_assign_role,
admin_bulk_assign_role,
admin_bulk_revoke_role,
admin_create_role,
admin_delete_role,
admin_purge_role,
Expand Down Expand Up @@ -41,4 +43,6 @@
"admin_purge_role",
"admin_assign_role",
"admin_revoke_role",
"admin_bulk_assign_role",
"admin_bulk_revoke_role",
]
54 changes: 54 additions & 0 deletions src/ai/backend/manager/api/gql/rbac/resolver/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
)
from ai.backend.manager.api.gql.rbac.types import (
AssignRoleInput,
BulkAssignRoleErrorGQL,
BulkAssignRoleInput,
BulkAssignRolePayloadGQL,
BulkRevokeRoleErrorGQL,
BulkRevokeRoleInput,
BulkRevokeRolePayloadGQL,
CreateRoleInput,
DeleteRoleInput,
DeleteRolePayload,
Expand All @@ -41,6 +47,12 @@
from ai.backend.manager.services.permission_contoller.actions.assign_role import (
AssignRoleAction,
)
from ai.backend.manager.services.permission_contoller.actions.bulk_assign_role import (
BulkAssignRoleAction,
)
from ai.backend.manager.services.permission_contoller.actions.bulk_revoke_role import (
BulkRevokeRoleAction,
)
from ai.backend.manager.services.permission_contoller.actions.create_role import (
CreateRoleAction,
)
Expand Down Expand Up @@ -239,3 +251,45 @@ async def admin_revoke_role(
)
)
return RoleAssignmentGQL.from_revocation_data(action_result.data)


@strawberry.mutation(
description="Added in 26.3.0. Bulk assign a role to multiple users (admin only)."
) # type: ignore[misc]
async def admin_bulk_assign_role(
info: Info[StrawberryGQLContext],
input: BulkAssignRoleInput,
) -> BulkAssignRolePayloadGQL:
action_result = (
await info.context.processors.permission_controller.bulk_assign_role.wait_for_complete(
BulkAssignRoleAction(bulk_creator=input.to_bulk_creator())
)
)
return BulkAssignRolePayloadGQL(
assigned=[RoleAssignmentGQL.from_assignment_data(s) for s in action_result.data.successes],
failed=[
BulkAssignRoleErrorGQL(user_id=f.user_id, message=f.message)
for f in action_result.data.failures
],
)


@strawberry.mutation(
description="Added in 26.3.0. Bulk revoke a role from multiple users (admin only)."
) # type: ignore[misc]
async def admin_bulk_revoke_role(
info: Info[StrawberryGQLContext],
input: BulkRevokeRoleInput,
) -> BulkRevokeRolePayloadGQL:
action_result = (
await info.context.processors.permission_controller.bulk_revoke_role.wait_for_complete(
BulkRevokeRoleAction(input=input.to_input())
)
)
return BulkRevokeRolePayloadGQL(
revoked=[RoleAssignmentGQL.from_revocation_data(s) for s in action_result.data.successes],
failed=[
BulkRevokeRoleErrorGQL(user_id=f.user_id, message=f.message)
for f in action_result.data.failures
],
)
12 changes: 12 additions & 0 deletions src/ai/backend/manager/api/gql/rbac/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
)
from .role import (
AssignRoleInput,
BulkAssignRoleErrorGQL,
BulkAssignRoleInput,
BulkAssignRolePayloadGQL,
BulkRevokeRoleErrorGQL,
BulkRevokeRoleInput,
BulkRevokeRolePayloadGQL,
CreateRoleInput,
DeleteRoleInput,
DeleteRolePayload,
Expand Down Expand Up @@ -86,10 +92,16 @@
"PurgeRoleInput",
"AssignRoleInput",
"RevokeRoleInput",
"BulkAssignRoleInput",
"BulkRevokeRoleInput",
# Payloads
"DeletePermissionPayload",
"DeleteRolePayload",
"PurgeRolePayload",
"BulkAssignRoleErrorGQL",
"BulkAssignRolePayloadGQL",
"BulkRevokeRoleErrorGQL",
"BulkRevokeRolePayloadGQL",
# Connections
"PermissionConnection",
"PermissionEdge",
Expand Down
Loading
Loading