Skip to content
1 change: 1 addition & 0 deletions changes/10300.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `update_deployment_policy` GQL mutation
36 changes: 36 additions & 0 deletions docs/manager/graphql-reference/supergraph.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -7718,6 +7718,13 @@ type Mutation
"""Added in 25.16.0"""
addModelRevision(input: AddRevisionInput!): AddRevisionPayload! @join__field(graph: STRAWBERRY)

"""
Added in 26.4.0.
Create or update the deployment policy for a given deployment (upsert semantics).
If the deployment already has a policy, it is replaced entirely with the new configuration.
"""
updateDeploymentPolicy(input: UpdateDeploymentPolicyInput!): UpdateDeploymentPolicyPayload! @join__field(graph: STRAWBERRY)

"""Create a new notification channel (admin only)"""
adminCreateNotificationChannel(input: CreateNotificationChannelInput!): CreateNotificationChannelPayload! @join__field(graph: STRAWBERRY)

Expand Down Expand Up @@ -12948,6 +12955,35 @@ type UpdateDeploymentPayload
deployment: ModelDeployment!
}

"""
Added in 26.4.0.
Input for creating or updating a deployment policy (upsert semantics).
Specify the target deployment_id and the desired strategy type.
Exactly one of rolling_update or blue_green must be provided,
matching the chosen strategy type.
If a policy already exists for the deployment, it is replaced entirely.
"""
input UpdateDeploymentPolicyInput
@join__type(graph: STRAWBERRY)
{
deploymentId: ID!
strategy: DeploymentStrategyType!
rollbackOnFailure: Boolean! = false
rollingUpdate: RollingUpdateConfigInput = null
blueGreen: BlueGreenConfigInput = null
}

"""
Added in 26.4.0.
Result payload returned after creating or updating a deployment policy.
Contains the full deployment_policy object reflecting the applied configuration.
"""
type UpdateDeploymentPolicyPayload
@join__type(graph: STRAWBERRY)
{
deploymentPolicy: DeploymentPolicy!
}

"""Added in 25.14.0"""
input UpdateHuggingFaceRegistryInput
@join__type(graph: STRAWBERRY)
Expand Down
32 changes: 32 additions & 0 deletions docs/manager/graphql-reference/v2-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -4074,6 +4074,13 @@ type Mutation {
"""Added in 25.16.0"""
addModelRevision(input: AddRevisionInput!): AddRevisionPayload!

"""
Added in 26.4.0.
Create or update the deployment policy for a given deployment (upsert semantics).
If the deployment already has a policy, it is replaced entirely with the new configuration.
"""
updateDeploymentPolicy(input: UpdateDeploymentPolicyInput!): UpdateDeploymentPolicyPayload!

"""Create a new notification channel (admin only)"""
adminCreateNotificationChannel(input: CreateNotificationChannelInput!): CreateNotificationChannelPayload!

Expand Down Expand Up @@ -7891,6 +7898,31 @@ type UpdateDeploymentPayload {
deployment: ModelDeployment!
}

"""
Added in 26.4.0.
Input for creating or updating a deployment policy (upsert semantics).
Specify the target deployment_id and the desired strategy type.
Exactly one of rolling_update or blue_green must be provided,
matching the chosen strategy type.
If a policy already exists for the deployment, it is replaced entirely.
"""
input UpdateDeploymentPolicyInput {
deploymentId: ID!
strategy: DeploymentStrategyType!
rollbackOnFailure: Boolean! = false
rollingUpdate: RollingUpdateConfigInput = null
blueGreen: BlueGreenConfigInput = null
}

"""
Added in 26.4.0.
Result payload returned after creating or updating a deployment policy.
Contains the full deployment_policy object reflecting the applied configuration.
"""
type UpdateDeploymentPolicyPayload {
deploymentPolicy: DeploymentPolicy!
}

"""Added in 25.14.0"""
input UpdateHuggingFaceRegistryInput {
id: ID!
Expand Down
9 changes: 9 additions & 0 deletions src/ai/backend/manager/api/gql/deployment/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
routes,
sync_replicas,
update_auto_scaling_rule,
# Policy
update_deployment_policy,
update_model_deployment,
update_route_traffic_status,
)
Expand Down Expand Up @@ -144,6 +146,9 @@
UpdateAutoScalingRulePayload,
UpdateDeploymentInput,
UpdateDeploymentPayload,
# Policy (mutation types)
UpdateDeploymentPolicyInputGQL,
UpdateDeploymentPolicyPayloadGQL,
UpdateRouteTrafficStatusInputGQL,
UpdateRouteTrafficStatusPayloadGQL,
get_route_pagination_spec,
Expand Down Expand Up @@ -204,6 +209,8 @@
"DeploymentStrategyTypeGQL",
"RollingUpdateConfigInputGQL",
"RollingUpdateStrategySpecGQL",
"UpdateDeploymentPolicyInputGQL",
"UpdateDeploymentPolicyPayloadGQL",
# Replica Types
"ActivenessStatus",
"LivenessStatus",
Expand Down Expand Up @@ -267,6 +274,8 @@
"deployments",
"sync_replicas",
"update_model_deployment",
# Resolvers - Policy
"update_deployment_policy",
# Resolvers - Replica
"replica",
"replica_status_changed",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
sync_replicas,
update_model_deployment,
)
from .policy import (
update_deployment_policy,
)
from .replica import (
replica,
replica_status_changed,
Expand Down Expand Up @@ -55,6 +58,8 @@
"delete_model_deployment",
"sync_replicas",
"deployment_status_changed",
# Policy
"update_deployment_policy",
# Replica
"replicas",
"replica",
Expand Down
42 changes: 42 additions & 0 deletions src/ai/backend/manager/api/gql/deployment/resolver/policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Deployment policy resolver functions."""

from __future__ import annotations

import strawberry
from strawberry import Info

from ai.backend.manager.api.gql.deployment.types.policy import (
DeploymentPolicyGQL,
UpdateDeploymentPolicyInputGQL,
UpdateDeploymentPolicyPayloadGQL,
)
from ai.backend.manager.api.gql.types import StrawberryGQLContext
from ai.backend.manager.api.gql.utils import check_admin_only, dedent_strip
from ai.backend.manager.services.deployment.actions.deployment_policy.upsert_deployment_policy import (
UpsertDeploymentPolicyAction,
)


@strawberry.mutation( # type: ignore[misc]
description=dedent_strip("""
Added in 26.4.0.
Create or update the deployment policy for a given deployment (upsert semantics).
If the deployment already has a policy, it is replaced entirely with the new configuration.
"""),
)
async def update_deployment_policy(
input: UpdateDeploymentPolicyInputGQL,
info: Info[StrawberryGQLContext],
) -> UpdateDeploymentPolicyPayloadGQL:
"""Update (upsert) a deployment policy for a deployment."""
check_admin_only()
upserter = input.to_upserter()

processor = info.context.processors.deployment
result = await processor.upsert_deployment_policy.wait_for_complete(
UpsertDeploymentPolicyAction(upserter=upserter)
)

return UpdateDeploymentPolicyPayloadGQL(
deployment_policy=DeploymentPolicyGQL.from_data(result.data),
)
4 changes: 4 additions & 0 deletions src/ai/backend/manager/api/gql/deployment/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
DeploymentStrategyTypeGQL,
RollingUpdateConfigInputGQL,
RollingUpdateStrategySpecGQL,
UpdateDeploymentPolicyInputGQL,
UpdateDeploymentPolicyPayloadGQL,
)
from .replica import (
ActivenessStatus,
Expand Down Expand Up @@ -166,6 +168,8 @@
"DeploymentStrategyTypeGQL",
"RollingUpdateConfigInputGQL",
"RollingUpdateStrategySpecGQL",
"UpdateDeploymentPolicyInputGQL",
"UpdateDeploymentPolicyPayloadGQL",
# Replica
"ActivenessStatus",
"LivenessStatus",
Expand Down
64 changes: 64 additions & 0 deletions src/ai/backend/manager/api/gql/deployment/types/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@

from datetime import datetime
from typing import Self
from uuid import UUID

import strawberry
from strawberry import ID
from strawberry.relay import Node, NodeID

from ai.backend.common.data.model_deployment.types import DeploymentStrategy
from ai.backend.manager.api.gql.utils import dedent_strip
from ai.backend.manager.data.deployment.types import DeploymentPolicyData
from ai.backend.manager.data.deployment.upserter import DeploymentPolicyUpserter
from ai.backend.manager.errors.api import InvalidAPIParameters
from ai.backend.manager.errors.deployment import InvalidDeploymentStrategySpec
from ai.backend.manager.models.deployment_policy import BlueGreenSpec, RollingUpdateSpec

Expand Down Expand Up @@ -129,3 +133,63 @@ def to_spec(self) -> BlueGreenSpec:
auto_promote=self.auto_promote,
promote_delay_seconds=self.promote_delay_seconds,
)


# ========== Mutation Input/Payload Types ==========


@strawberry.input(
name="UpdateDeploymentPolicyInput",
description=dedent_strip("""
Added in 26.4.0.
Input for creating or updating a deployment policy (upsert semantics).
Specify the target deployment_id and the desired strategy type.
Exactly one of rolling_update or blue_green must be provided,
matching the chosen strategy type.
If a policy already exists for the deployment, it is replaced entirely.
"""),
)
class UpdateDeploymentPolicyInputGQL:
deployment_id: ID
strategy: DeploymentStrategyTypeGQL
rollback_on_failure: bool = False
rolling_update: RollingUpdateConfigInputGQL | None = None
blue_green: BlueGreenConfigInputGQL | None = None

def to_upserter(self) -> DeploymentPolicyUpserter:
"""Convert to DeploymentPolicyUpserter for the service layer."""

strategy = DeploymentStrategy(self.strategy.value)
strategy_spec: RollingUpdateSpec | BlueGreenSpec
match strategy:
case DeploymentStrategy.ROLLING:
if self.rolling_update is None:
raise InvalidAPIParameters(
"rolling_update config required for ROLLING strategy"
)
strategy_spec = self.rolling_update.to_spec()
case DeploymentStrategy.BLUE_GREEN:
if self.blue_green is None:
raise InvalidAPIParameters("blue_green config required for BLUE_GREEN strategy")
strategy_spec = self.blue_green.to_spec()
case _:
raise InvalidAPIParameters(f"Unsupported deployment strategy: {strategy}")

return DeploymentPolicyUpserter(
deployment_id=UUID(str(self.deployment_id)),
strategy=strategy,
strategy_spec=strategy_spec,
rollback_on_failure=self.rollback_on_failure,
)
Comment on lines +141 to +183


@strawberry.type(
name="UpdateDeploymentPolicyPayload",
description=dedent_strip("""
Added in 26.4.0.
Result payload returned after creating or updating a deployment policy.
Contains the full deployment_policy object reflecting the applied configuration.
"""),
)
class UpdateDeploymentPolicyPayloadGQL:
deployment_policy: DeploymentPolicyGQL
2 changes: 2 additions & 0 deletions src/ai/backend/manager/api/gql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
routes,
sync_replicas,
update_auto_scaling_rule,
update_deployment_policy,
update_model_deployment,
update_route_traffic_status,
)
Expand Down Expand Up @@ -430,6 +431,7 @@ class Mutation:
delete_model_deployment = delete_model_deployment
sync_replicas = sync_replicas
add_model_revision = add_model_revision
update_deployment_policy = update_deployment_policy
# Notification - Admin APIs
admin_create_notification_channel = admin_create_notification_channel
admin_update_notification_channel = admin_update_notification_channel
Expand Down
Loading
Loading