Skip to content

Commit 5f1d1f6

Browse files
jopemachineclaudelablup-octodog
authored
feat(BA-4631): Add update_deployment_policy GQL mutation (#10300)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: octodog <mu001@lablup.com>
1 parent ceb8537 commit 5f1d1f6

10 files changed

Lines changed: 471 additions & 0 deletions

File tree

changes/10300.feature.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `update_deployment_policy` GQL mutation

docs/manager/graphql-reference/supergraph.graphql

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7718,6 +7718,13 @@ type Mutation
77187718
"""Added in 25.16.0"""
77197719
addModelRevision(input: AddRevisionInput!): AddRevisionPayload! @join__field(graph: STRAWBERRY)
77207720

7721+
"""
7722+
Added in 26.4.0.
7723+
Create or update the deployment policy for a given deployment (upsert semantics).
7724+
If the deployment already has a policy, it is replaced entirely with the new configuration.
7725+
"""
7726+
updateDeploymentPolicy(input: UpdateDeploymentPolicyInput!): UpdateDeploymentPolicyPayload! @join__field(graph: STRAWBERRY)
7727+
77217728
"""Create a new notification channel (admin only)"""
77227729
adminCreateNotificationChannel(input: CreateNotificationChannelInput!): CreateNotificationChannelPayload! @join__field(graph: STRAWBERRY)
77237730

@@ -12948,6 +12955,35 @@ type UpdateDeploymentPayload
1294812955
deployment: ModelDeployment!
1294912956
}
1295012957

12958+
"""
12959+
Added in 26.4.0.
12960+
Input for creating or updating a deployment policy (upsert semantics).
12961+
Specify the target deployment_id and the desired strategy type.
12962+
Exactly one of rolling_update or blue_green must be provided,
12963+
matching the chosen strategy type.
12964+
If a policy already exists for the deployment, it is replaced entirely.
12965+
"""
12966+
input UpdateDeploymentPolicyInput
12967+
@join__type(graph: STRAWBERRY)
12968+
{
12969+
deploymentId: ID!
12970+
strategy: DeploymentStrategyType!
12971+
rollbackOnFailure: Boolean! = false
12972+
rollingUpdate: RollingUpdateConfigInput = null
12973+
blueGreen: BlueGreenConfigInput = null
12974+
}
12975+
12976+
"""
12977+
Added in 26.4.0.
12978+
Result payload returned after creating or updating a deployment policy.
12979+
Contains the full deployment_policy object reflecting the applied configuration.
12980+
"""
12981+
type UpdateDeploymentPolicyPayload
12982+
@join__type(graph: STRAWBERRY)
12983+
{
12984+
deploymentPolicy: DeploymentPolicy!
12985+
}
12986+
1295112987
"""Added in 25.14.0"""
1295212988
input UpdateHuggingFaceRegistryInput
1295312989
@join__type(graph: STRAWBERRY)

docs/manager/graphql-reference/v2-schema.graphql

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4074,6 +4074,13 @@ type Mutation {
40744074
"""Added in 25.16.0"""
40754075
addModelRevision(input: AddRevisionInput!): AddRevisionPayload!
40764076

4077+
"""
4078+
Added in 26.4.0.
4079+
Create or update the deployment policy for a given deployment (upsert semantics).
4080+
If the deployment already has a policy, it is replaced entirely with the new configuration.
4081+
"""
4082+
updateDeploymentPolicy(input: UpdateDeploymentPolicyInput!): UpdateDeploymentPolicyPayload!
4083+
40774084
"""Create a new notification channel (admin only)"""
40784085
adminCreateNotificationChannel(input: CreateNotificationChannelInput!): CreateNotificationChannelPayload!
40794086

@@ -7891,6 +7898,31 @@ type UpdateDeploymentPayload {
78917898
deployment: ModelDeployment!
78927899
}
78937900

7901+
"""
7902+
Added in 26.4.0.
7903+
Input for creating or updating a deployment policy (upsert semantics).
7904+
Specify the target deployment_id and the desired strategy type.
7905+
Exactly one of rolling_update or blue_green must be provided,
7906+
matching the chosen strategy type.
7907+
If a policy already exists for the deployment, it is replaced entirely.
7908+
"""
7909+
input UpdateDeploymentPolicyInput {
7910+
deploymentId: ID!
7911+
strategy: DeploymentStrategyType!
7912+
rollbackOnFailure: Boolean! = false
7913+
rollingUpdate: RollingUpdateConfigInput = null
7914+
blueGreen: BlueGreenConfigInput = null
7915+
}
7916+
7917+
"""
7918+
Added in 26.4.0.
7919+
Result payload returned after creating or updating a deployment policy.
7920+
Contains the full deployment_policy object reflecting the applied configuration.
7921+
"""
7922+
type UpdateDeploymentPolicyPayload {
7923+
deploymentPolicy: DeploymentPolicy!
7924+
}
7925+
78947926
"""Added in 25.14.0"""
78957927
input UpdateHuggingFaceRegistryInput {
78967928
id: ID!

src/ai/backend/manager/api/gql/deployment/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
routes,
4141
sync_replicas,
4242
update_auto_scaling_rule,
43+
# Policy
44+
update_deployment_policy,
4345
update_model_deployment,
4446
update_route_traffic_status,
4547
)
@@ -144,6 +146,9 @@
144146
UpdateAutoScalingRulePayload,
145147
UpdateDeploymentInput,
146148
UpdateDeploymentPayload,
149+
# Policy (mutation types)
150+
UpdateDeploymentPolicyInputGQL,
151+
UpdateDeploymentPolicyPayloadGQL,
147152
UpdateRouteTrafficStatusInputGQL,
148153
UpdateRouteTrafficStatusPayloadGQL,
149154
get_route_pagination_spec,
@@ -204,6 +209,8 @@
204209
"DeploymentStrategyTypeGQL",
205210
"RollingUpdateConfigInputGQL",
206211
"RollingUpdateStrategySpecGQL",
212+
"UpdateDeploymentPolicyInputGQL",
213+
"UpdateDeploymentPolicyPayloadGQL",
207214
# Replica Types
208215
"ActivenessStatus",
209216
"LivenessStatus",
@@ -267,6 +274,8 @@
267274
"deployments",
268275
"sync_replicas",
269276
"update_model_deployment",
277+
# Resolvers - Policy
278+
"update_deployment_policy",
270279
# Resolvers - Replica
271280
"replica",
272281
"replica_status_changed",

src/ai/backend/manager/api/gql/deployment/resolver/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
sync_replicas,
2222
update_model_deployment,
2323
)
24+
from .policy import (
25+
update_deployment_policy,
26+
)
2427
from .replica import (
2528
replica,
2629
replica_status_changed,
@@ -55,6 +58,8 @@
5558
"delete_model_deployment",
5659
"sync_replicas",
5760
"deployment_status_changed",
61+
# Policy
62+
"update_deployment_policy",
5863
# Replica
5964
"replicas",
6065
"replica",
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Deployment policy resolver functions."""
2+
3+
from __future__ import annotations
4+
5+
import strawberry
6+
from strawberry import Info
7+
8+
from ai.backend.manager.api.gql.deployment.types.policy import (
9+
DeploymentPolicyGQL,
10+
UpdateDeploymentPolicyInputGQL,
11+
UpdateDeploymentPolicyPayloadGQL,
12+
)
13+
from ai.backend.manager.api.gql.types import StrawberryGQLContext
14+
from ai.backend.manager.api.gql.utils import check_admin_only, dedent_strip
15+
from ai.backend.manager.services.deployment.actions.deployment_policy.upsert_deployment_policy import (
16+
UpsertDeploymentPolicyAction,
17+
)
18+
19+
20+
@strawberry.mutation( # type: ignore[misc]
21+
description=dedent_strip("""
22+
Added in 26.4.0.
23+
Create or update the deployment policy for a given deployment (upsert semantics).
24+
If the deployment already has a policy, it is replaced entirely with the new configuration.
25+
"""),
26+
)
27+
async def update_deployment_policy(
28+
input: UpdateDeploymentPolicyInputGQL,
29+
info: Info[StrawberryGQLContext],
30+
) -> UpdateDeploymentPolicyPayloadGQL:
31+
"""Update (upsert) a deployment policy for a deployment."""
32+
check_admin_only()
33+
upserter = input.to_upserter()
34+
35+
processor = info.context.processors.deployment
36+
result = await processor.upsert_deployment_policy.wait_for_complete(
37+
UpsertDeploymentPolicyAction(upserter=upserter)
38+
)
39+
40+
return UpdateDeploymentPolicyPayloadGQL(
41+
deployment_policy=DeploymentPolicyGQL.from_data(result.data),
42+
)

src/ai/backend/manager/api/gql/deployment/types/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
DeploymentStrategyTypeGQL,
5858
RollingUpdateConfigInputGQL,
5959
RollingUpdateStrategySpecGQL,
60+
UpdateDeploymentPolicyInputGQL,
61+
UpdateDeploymentPolicyPayloadGQL,
6062
)
6163
from .replica import (
6264
ActivenessStatus,
@@ -166,6 +168,8 @@
166168
"DeploymentStrategyTypeGQL",
167169
"RollingUpdateConfigInputGQL",
168170
"RollingUpdateStrategySpecGQL",
171+
"UpdateDeploymentPolicyInputGQL",
172+
"UpdateDeploymentPolicyPayloadGQL",
169173
# Replica
170174
"ActivenessStatus",
171175
"LivenessStatus",

src/ai/backend/manager/api/gql/deployment/types/policy.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44

55
from datetime import datetime
66
from typing import Self
7+
from uuid import UUID
78

89
import strawberry
910
from strawberry import ID
1011
from strawberry.relay import Node, NodeID
1112

1213
from ai.backend.common.data.model_deployment.types import DeploymentStrategy
14+
from ai.backend.manager.api.gql.utils import dedent_strip
1315
from ai.backend.manager.data.deployment.types import DeploymentPolicyData
16+
from ai.backend.manager.data.deployment.upserter import DeploymentPolicyUpserter
17+
from ai.backend.manager.errors.api import InvalidAPIParameters
1418
from ai.backend.manager.errors.deployment import InvalidDeploymentStrategySpec
1519
from ai.backend.manager.models.deployment_policy import BlueGreenSpec, RollingUpdateSpec
1620

@@ -129,3 +133,63 @@ def to_spec(self) -> BlueGreenSpec:
129133
auto_promote=self.auto_promote,
130134
promote_delay_seconds=self.promote_delay_seconds,
131135
)
136+
137+
138+
# ========== Mutation Input/Payload Types ==========
139+
140+
141+
@strawberry.input(
142+
name="UpdateDeploymentPolicyInput",
143+
description=dedent_strip("""
144+
Added in 26.4.0.
145+
Input for creating or updating a deployment policy (upsert semantics).
146+
Specify the target deployment_id and the desired strategy type.
147+
Exactly one of rolling_update or blue_green must be provided,
148+
matching the chosen strategy type.
149+
If a policy already exists for the deployment, it is replaced entirely.
150+
"""),
151+
)
152+
class UpdateDeploymentPolicyInputGQL:
153+
deployment_id: ID
154+
strategy: DeploymentStrategyTypeGQL
155+
rollback_on_failure: bool = False
156+
rolling_update: RollingUpdateConfigInputGQL | None = None
157+
blue_green: BlueGreenConfigInputGQL | None = None
158+
159+
def to_upserter(self) -> DeploymentPolicyUpserter:
160+
"""Convert to DeploymentPolicyUpserter for the service layer."""
161+
162+
strategy = DeploymentStrategy(self.strategy.value)
163+
strategy_spec: RollingUpdateSpec | BlueGreenSpec
164+
match strategy:
165+
case DeploymentStrategy.ROLLING:
166+
if self.rolling_update is None:
167+
raise InvalidAPIParameters(
168+
"rolling_update config required for ROLLING strategy"
169+
)
170+
strategy_spec = self.rolling_update.to_spec()
171+
case DeploymentStrategy.BLUE_GREEN:
172+
if self.blue_green is None:
173+
raise InvalidAPIParameters("blue_green config required for BLUE_GREEN strategy")
174+
strategy_spec = self.blue_green.to_spec()
175+
case _:
176+
raise InvalidAPIParameters(f"Unsupported deployment strategy: {strategy}")
177+
178+
return DeploymentPolicyUpserter(
179+
deployment_id=UUID(str(self.deployment_id)),
180+
strategy=strategy,
181+
strategy_spec=strategy_spec,
182+
rollback_on_failure=self.rollback_on_failure,
183+
)
184+
185+
186+
@strawberry.type(
187+
name="UpdateDeploymentPolicyPayload",
188+
description=dedent_strip("""
189+
Added in 26.4.0.
190+
Result payload returned after creating or updating a deployment policy.
191+
Contains the full deployment_policy object reflecting the applied configuration.
192+
"""),
193+
)
194+
class UpdateDeploymentPolicyPayloadGQL:
195+
deployment_policy: DeploymentPolicyGQL

src/ai/backend/manager/api/gql/schema.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
routes,
7777
sync_replicas,
7878
update_auto_scaling_rule,
79+
update_deployment_policy,
7980
update_model_deployment,
8081
update_route_traffic_status,
8182
)
@@ -430,6 +431,7 @@ class Mutation:
430431
delete_model_deployment = delete_model_deployment
431432
sync_replicas = sync_replicas
432433
add_model_revision = add_model_revision
434+
update_deployment_policy = update_deployment_policy
433435
# Notification - Admin APIs
434436
admin_create_notification_channel = admin_create_notification_channel
435437
admin_update_notification_channel = admin_update_notification_channel

0 commit comments

Comments
 (0)