Skip to content

Commit 8126230

Browse files
Add validation and translation for served_models and served_entities in serving endpoints (#3880)
## Changes && Why `served_models` was deprecated and the fields in it were moved to `served_endpoints`. The GET API response for a model serving endpoint returns with both `served_models` and `served_entities` even if one is set on the client side (not AIP complaint). In order to simplify the direct deployment logic, this PR translates the `served_models` config to `served_entities`, so that we can keep the core diff logic in direct deployment simple. Note: This is not a breaking change. TF also had the same logic with a conflicts_with annotation for `served_models` and `served_entities` ## Tests New acceptance tests. Manually confirmed that a deployment succeeds with no issues.
1 parent 92d293d commit 8126230

File tree

26 files changed

+242
-63
lines changed

26 files changed

+242
-63
lines changed

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
### Dependency updates
1010

1111
### Bundles
12+
* Add validation that served_models and served_entities are not used at the same time. Add client side translation logic. ([#3880](https://github.com/databricks/cli/pull/3880))
1213

1314
### API Changes
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
bundle:
2+
name: "model_serving_error"
3+
4+
resources:
5+
model_serving_endpoints:
6+
endpoint1:
7+
name: "test-endpoint"
8+
config:
9+
served_models:
10+
- model_name: "my-model"
11+
model_version: "1"
12+
served_entities:
13+
- entity_name: "my-entity"
14+
entity_version: "2"

acceptance/bundle/validate/model_serving_both_fields_error/out.test.toml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Error: Cannot use both served_models and served_entities
2+
in databricks.yml:7:7
3+
4+
Model serving endpoint cannot specify both served_models and served_entities at the same time.
5+
6+
Name: model_serving_error
7+
Target: default
8+
Workspace:
9+
User: [USERNAME]
10+
Path: /Workspace/Users/[USERNAME]/.bundle/model_serving_error/default
11+
12+
Found 1 error
13+
14+
Exit code: 1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$CLI bundle validate
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
bundle:
2+
name: "model_serving_conversion"
3+
4+
resources:
5+
model_serving_endpoints:
6+
endpoint1:
7+
name: "test-endpoint"
8+
config:
9+
served_models:
10+
- model_name: "my-model"
11+
model_version: "1"
12+
scale_to_zero_enabled: true

acceptance/bundle/validate/model_serving_conversion/out.test.toml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Warning: Using served_models is deprecated
2+
in databricks.yml:10:11
3+
4+
The served_models field is deprecated. Please use served_entities instead.
5+
6+
{
7+
"served_entities": [
8+
{
9+
"entity_name": "my-model",
10+
"entity_version": "1",
11+
"scale_to_zero_enabled": true
12+
}
13+
]
14+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$CLI bundle validate -o json | jq .resources.model_serving_endpoints.endpoint1.config
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package resourcemutator
2+
3+
import (
4+
"context"
5+
6+
"github.com/databricks/cli/bundle"
7+
"github.com/databricks/cli/libs/diag"
8+
"github.com/databricks/cli/libs/dyn"
9+
"github.com/databricks/cli/libs/utils"
10+
"github.com/databricks/databricks-sdk-go/service/serving"
11+
)
12+
13+
type modelServingEndpointFixups struct{}
14+
15+
func ModelServingEndpointFixups() bundle.Mutator {
16+
return &modelServingEndpointFixups{}
17+
}
18+
19+
func (m *modelServingEndpointFixups) Name() string {
20+
return "ModelServingEndpointFixups"
21+
}
22+
23+
func servedModelToServedEntity(model serving.ServedModelInput) serving.ServedEntityInput {
24+
return serving.ServedEntityInput{
25+
// served_models does not support ExternalModel, so we set ExternalModel to nil
26+
ExternalModel: nil,
27+
28+
EntityName: model.ModelName,
29+
EntityVersion: model.ModelVersion,
30+
EnvironmentVars: model.EnvironmentVars,
31+
InstanceProfileArn: model.InstanceProfileArn,
32+
MaxProvisionedThroughput: model.MaxProvisionedThroughput,
33+
MinProvisionedThroughput: model.MinProvisionedThroughput,
34+
Name: model.Name,
35+
ProvisionedModelUnits: model.ProvisionedModelUnits,
36+
ScaleToZeroEnabled: model.ScaleToZeroEnabled,
37+
WorkloadSize: model.WorkloadSize,
38+
WorkloadType: serving.ServingModelWorkloadType(model.WorkloadType),
39+
MaxProvisionedConcurrency: model.MaxProvisionedConcurrency,
40+
MinProvisionedConcurrency: model.MinProvisionedConcurrency,
41+
ForceSendFields: utils.FilterFields[serving.ServedEntityInput](model.ForceSendFields),
42+
}
43+
}
44+
45+
func (m *modelServingEndpointFixups) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
46+
var diags diag.Diagnostics
47+
48+
for key, endpoint := range b.Config.Resources.ModelServingEndpoints {
49+
if endpoint == nil || endpoint.Config == nil {
50+
continue
51+
}
52+
53+
// Validate that both ServedModels and ServedEntities are not used at the same time.
54+
if len(endpoint.Config.ServedModels) > 0 && len(endpoint.Config.ServedEntities) > 0 {
55+
diags = diags.Append(diag.Diagnostic{
56+
Severity: diag.Error,
57+
Summary: "Cannot use both served_models and served_entities",
58+
Detail: "Model serving endpoint cannot specify both served_models and served_entities at the same time.",
59+
Locations: []dyn.Location{
60+
b.Config.GetLocation("resources.model_serving_endpoints." + key),
61+
},
62+
})
63+
continue
64+
}
65+
66+
// Convert ServedModels to ServedEntities if specified. ServedModels is a deprecated field, and the service recommends using ServedEntities instead.
67+
// We perform this translation here so that the deployment plan only has to detect served_entities and can ignore served_models.
68+
if len(endpoint.Config.ServedModels) > 0 {
69+
// Add warning recommending served_entities
70+
diags = diags.Append(diag.Diagnostic{
71+
Severity: diag.Warning,
72+
Summary: "Using served_models is deprecated",
73+
Detail: "The served_models field is deprecated. Please use served_entities instead.",
74+
Locations: []dyn.Location{
75+
b.Config.GetLocation("resources.model_serving_endpoints." + key + ".config.served_models"),
76+
},
77+
})
78+
79+
endpoint.Config.ServedEntities = make([]serving.ServedEntityInput, len(endpoint.Config.ServedModels))
80+
for i, model := range endpoint.Config.ServedModels {
81+
endpoint.Config.ServedEntities[i] = servedModelToServedEntity(model)
82+
}
83+
// Clear ServedModels after conversion
84+
endpoint.Config.ServedModels = nil
85+
}
86+
}
87+
88+
return diags
89+
}

0 commit comments

Comments
 (0)