Skip to content
Merged
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 NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
### CLI

### Bundles
* Added support for model serving endpoints in deployment bind/unbind commands ([#2634](https://github.com/databricks/cli/pull/2634))

### API Changes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
bundle:
name: bind-model-serving-endpoint-test-$UNIQUE_NAME

resources:
model_serving_endpoints:
endpoint1:
name: $ENDPOINT_NAME
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
bundle:
name: bind-model-serving-endpoint-test-[UNIQUE_NAME]

resources:
model_serving_endpoints:
endpoint1:
name: test-endpoint-[UUID]

>>> [CLI] serving-endpoints create test-endpoint-[UUID]
{
"name": "test-endpoint-[UUID]",
"permission_level": "CAN_MANAGE",
"route_optimized": false,
"state": {
"config_update": "NOT_UPDATING",
"ready": "NOT_READY"
}
}

>>> [CLI] serving-endpoints get test-endpoint-[UUID]
{
"name": "test-endpoint-[UUID]",
"permission_level": "CAN_MANAGE",
"route_optimized": false,
"state": {
"config_update": "NOT_UPDATING",
"ready": "NOT_READY"
}
}

>>> [CLI] bundle deployment bind endpoint1 test-endpoint-[UUID]
Updating deployment state...
Successfully bound model_serving_endpoint with an id 'test-endpoint-[UUID]'. Run 'bundle deploy' to deploy changes to your workspace

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/bind-model-serving-endpoint-test-[UNIQUE_NAME]/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> [CLI] serving-endpoints get test-endpoint-[UUID]
{
"name": "test-endpoint-[UUID]",
"permission_level": "CAN_MANAGE",
"route_optimized": false,
"state": {
"config_update": "NOT_UPDATING",
"ready": "NOT_READY"
}
}

>>> [CLI] bundle deployment unbind endpoint1
Updating deployment state...

>>> [CLI] bundle destroy --auto-approve
All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/bind-model-serving-endpoint-test-[UNIQUE_NAME]/default

Deleting files...
Destroy complete!

>>> [CLI] serving-endpoints get test-endpoint-[UUID]
{
"name": "test-endpoint-[UUID]",
"permission_level": "CAN_MANAGE",
"route_optimized": false,
"state": {
"config_update": "NOT_UPDATING",
"ready": "NOT_READY"
}
}

>>> [CLI] serving-endpoints delete test-endpoint-[UUID]
30 changes: 30 additions & 0 deletions acceptance/bundle/deployment/bind/model-serving-endpoint/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
ENDPOINT_NAME="test-endpoint-$(uuid)"
if [ -z "$CLOUD_ENV" ]; then
ENDPOINT_NAME="test-endpoint-6260d50f-e8ff-4905-8f28-812345678903"
fi
export ENDPOINT_NAME
envsubst < databricks.yml.tmpl > databricks.yml
cat databricks.yml

# Create a pre-defined serving endpoint:
trace $CLI serving-endpoints create "${ENDPOINT_NAME}" | jq '{name, permission_level, route_optimized, state}'

cleanup() {
trace $CLI serving-endpoints delete "${ENDPOINT_NAME}"
}
trap cleanup EXIT

trace $CLI serving-endpoints get "${ENDPOINT_NAME}" | jq '{name, permission_level, route_optimized, state}'

trace $CLI bundle deployment bind endpoint1 "${ENDPOINT_NAME}"

trace $CLI bundle deploy

trace $CLI serving-endpoints get "${ENDPOINT_NAME}" | jq '{name, permission_level, route_optimized, state}'

trace $CLI bundle deployment unbind endpoint1

trace $CLI bundle destroy --auto-approve

# Read the pre-defined serving-endpoint again (expecting it still exists and is not deleted):
trace $CLI serving-endpoints get "${ENDPOINT_NAME}" | jq '{name, permission_level, route_optimized, state}'
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Local = true
Cloud = true

Ignore = [
"databricks.yml",
]

[[Server]]
Pattern = "POST /api/2.0/serving-endpoints"
Response.Body = '''
{
"name": "test-endpoint-6260d50f-e8ff-4905-8f28-812345678903"
}
'''

[[Server]]
Pattern = "GET /api/2.0/serving-endpoints/"

[[Server]]
Pattern = "GET /api/2.0/serving-endpoints/{endpoint_name}"
Response.Body = '''
{
"name": "test-endpoint-6260d50f-e8ff-4905-8f28-812345678903",
"permission_level": "CAN_MANAGE",
"route_optimized": false,
"state": {
"config_update": "NOT_UPDATING",
"ready": "NOT_READY"
}
}
'''

[[Server]]
Pattern = "DELETE /api/2.0/serving-endpoints/{endpoint_name}"
6 changes: 6 additions & 0 deletions bundle/config/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ func (r *Resources) FindResourceByConfigKey(key string) (ConfigResource, error)
}
}

for k := range r.ModelServingEndpoints {
if k == key {
found = append(found, r.ModelServingEndpoints[k])
}
}

if len(found) == 0 {
return nil, fmt.Errorf("no such resource: %s", key)
}
Expand Down
6 changes: 3 additions & 3 deletions bundle/config/resources/model_serving_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ func (s ModelServingEndpoint) MarshalJSON() ([]byte, error) {
return marshal.Marshal(s)
}

func (s *ModelServingEndpoint) Exists(ctx context.Context, w *databricks.WorkspaceClient, id string) (bool, error) {
func (s *ModelServingEndpoint) Exists(ctx context.Context, w *databricks.WorkspaceClient, name string) (bool, error) {
_, err := w.ServingEndpoints.Get(ctx, serving.GetServingEndpointRequest{
Name: id,
Name: name,
})
if err != nil {
log.Debugf(ctx, "serving endpoint %s does not exist", id)
log.Debugf(ctx, "serving endpoint %s does not exist", name)
return false, err
}
return true, nil
Expand Down
10 changes: 9 additions & 1 deletion bundle/config/resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"strings"
"testing"

"github.com/databricks/databricks-sdk-go/service/serving"

"github.com/databricks/cli/bundle/config/resources"
"github.com/databricks/databricks-sdk-go/experimental/mocks"
"github.com/databricks/databricks-sdk-go/service/apps"
Expand Down Expand Up @@ -164,8 +166,13 @@ func TestResourcesBindSupport(t *testing.T) {
CreateMonitor: &catalog.CreateMonitor{},
},
},
ModelServingEndpoints: map[string]*resources.ModelServingEndpoint{
"my_model_serving_endpoint": {
CreateServingEndpoint: &serving.CreateServingEndpoint{},
},
},
}
unbindableResources := map[string]bool{"model": true, "model_serving_endpoint": true}
unbindableResources := map[string]bool{"model": true}

ctx := context.Background()
m := mocks.NewMockWorkspaceClient(t)
Expand All @@ -179,6 +186,7 @@ func TestResourcesBindSupport(t *testing.T) {
m.GetMockVolumesAPI().EXPECT().Read(mock.Anything, mock.Anything).Return(nil, nil)
m.GetMockAppsAPI().EXPECT().GetByName(mock.Anything, mock.Anything).Return(nil, nil)
m.GetMockQualityMonitorsAPI().EXPECT().Get(mock.Anything, mock.Anything).Return(nil, nil)
m.GetMockServingEndpointsAPI().EXPECT().Get(mock.Anything, mock.Anything).Return(nil, nil)

allResources := supportedResources.AllResources()
for _, group := range allResources {
Expand Down
Loading