diff --git a/acceptance/bundle/resources/vector_search_endpoints/recreate/name/databricks.yml.tmpl b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/databricks.yml.tmpl new file mode 100644 index 00000000000..4b36236fe5c --- /dev/null +++ b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/databricks.yml.tmpl @@ -0,0 +1,11 @@ +bundle: + name: recreate-vs-endpoint-name-$UNIQUE_NAME + +sync: + paths: [] + +resources: + vector_search_endpoints: + my_endpoint: + name: vs-endpoint-$UNIQUE_NAME + endpoint_type: STANDARD diff --git a/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.requests.create.direct.json b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.requests.create.direct.json new file mode 100644 index 00000000000..bcd2b5094d3 --- /dev/null +++ b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.requests.create.direct.json @@ -0,0 +1,8 @@ +{ + "method": "POST", + "path": "/api/2.0/vector-search/endpoints", + "body": { + "endpoint_type": "STANDARD", + "name": "vs-endpoint-[UNIQUE_NAME]" + } +} diff --git a/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.requests.recreate.direct.json b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.requests.recreate.direct.json new file mode 100644 index 00000000000..e78e7270d71 --- /dev/null +++ b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.requests.recreate.direct.json @@ -0,0 +1,12 @@ +{ + "method": "DELETE", + "path": "/api/2.0/vector-search/endpoints/vs-endpoint-[UNIQUE_NAME]" +} +{ + "method": "POST", + "path": "/api/2.0/vector-search/endpoints", + "body": { + "endpoint_type": "STANDARD", + "name": "vs-endpoint-renamed-[UNIQUE_NAME]" + } +} diff --git a/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.test.toml b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.test.toml new file mode 100644 index 00000000000..88423408186 --- /dev/null +++ b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/out.test.toml @@ -0,0 +1,4 @@ +Local = true +Cloud = false +RequiresUnityCatalog = true +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/resources/vector_search_endpoints/recreate/name/output.txt b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/output.txt new file mode 100644 index 00000000000..2826aa21846 --- /dev/null +++ b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/output.txt @@ -0,0 +1,40 @@ + +=== Initial deployment +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/recreate-vs-endpoint-name-[UNIQUE_NAME]/default/files... +Deploying resources... +Updating deployment state... +Deployment complete! + +>>> print_requests.py --keep //vector-search/endpoints + +=== Rename endpoint (should trigger recreation) +>>> update_file.py databricks.yml name: vs-endpoint-[UNIQUE_NAME] name: vs-endpoint-renamed-[UNIQUE_NAME] + +>>> [CLI] bundle plan +recreate vector_search_endpoints.my_endpoint + +Plan: 1 to add, 0 to change, 1 to delete, 0 unchanged + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/recreate-vs-endpoint-name-[UNIQUE_NAME]/default/files... +Deploying resources... +Updating deployment state... +Deployment complete! + +>>> print_requests.py --keep //vector-search/endpoints + +>>> [CLI] vector-search-endpoints get-endpoint vs-endpoint-renamed-[UNIQUE_NAME] +{ + "name": "vs-endpoint-renamed-[UNIQUE_NAME]", + "endpoint_type": "STANDARD" +} + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.vector_search_endpoints.my_endpoint + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/recreate-vs-endpoint-name-[UNIQUE_NAME]/default + +Deleting files... +Destroy complete! diff --git a/acceptance/bundle/resources/vector_search_endpoints/recreate/name/script b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/script new file mode 100644 index 00000000000..9e93af03135 --- /dev/null +++ b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/script @@ -0,0 +1,30 @@ +envsubst < databricks.yml.tmpl > databricks.yml + +cleanup() { + trace $CLI bundle destroy --auto-approve + rm -f out.requests.txt +} +trap cleanup EXIT + +print_requests() { + local label=$1 + trace print_requests.py --keep '//vector-search/endpoints' > out.requests.${label}.$DATABRICKS_BUNDLE_ENGINE.json + rm -f out.requests.txt +} + +title "Initial deployment" +rm -f out.requests.txt +trace $CLI bundle deploy + +print_requests create + +title "Rename endpoint (should trigger recreation)" +trace update_file.py databricks.yml "name: vs-endpoint-$UNIQUE_NAME" "name: vs-endpoint-renamed-$UNIQUE_NAME" + +trace $CLI bundle plan +rm -f out.requests.txt +trace $CLI bundle deploy --auto-approve + +print_requests recreate + +trace $CLI vector-search-endpoints get-endpoint "vs-endpoint-renamed-${UNIQUE_NAME}" | jq '{name, endpoint_type}' diff --git a/acceptance/bundle/resources/vector_search_endpoints/recreate/name/test.toml b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/test.toml new file mode 100644 index 00000000000..18b1a88417e --- /dev/null +++ b/acceptance/bundle/resources/vector_search_endpoints/recreate/name/test.toml @@ -0,0 +1 @@ +Cloud = false diff --git a/acceptance/bundle/resources/vector_search_indexes/recreate/with_endpoint/output.txt b/acceptance/bundle/resources/vector_search_indexes/recreate/with_endpoint/output.txt index deb3c925c09..2453571bd94 100644 --- a/acceptance/bundle/resources/vector_search_indexes/recreate/with_endpoint/output.txt +++ b/acceptance/bundle/resources/vector_search_indexes/recreate/with_endpoint/output.txt @@ -71,6 +71,7 @@ Plan: 1 to add, 0 to change, 1 to delete, 1 unchanged ], "schema_json": "{\"id\":\"int\",\"vector\":\"array\u003cfloat\u003e\"}" }, + "endpoint_id": "[UUID]", "endpoint_name": "vs-endpoint-[UNIQUE_NAME]", "endpoint_uuid": "[UUID]", "index_subtype": "HYBRID", diff --git a/bundle/config/mutator/resourcemutator/apply_bundle_permissions_test.go b/bundle/config/mutator/resourcemutator/apply_bundle_permissions_test.go index 2fbe07b270a..2c1b5bb0c1c 100644 --- a/bundle/config/mutator/resourcemutator/apply_bundle_permissions_test.go +++ b/bundle/config/mutator/resourcemutator/apply_bundle_permissions_test.go @@ -149,12 +149,12 @@ func TestApplyBundlePermissions(t *testing.T) { require.Contains(t, b.Config.Resources.Apps["app_1"].Permissions, resources.AppPermission{Level: "CAN_USE", GroupName: "TestGroup"}) require.Len(t, b.Config.Resources.VectorSearchEndpoints["vs_1"].Permissions, 2) - require.Contains(t, b.Config.Resources.VectorSearchEndpoints["vs_1"].Permissions, resources.Permission{Level: "CAN_MANAGE", UserName: "TestUser"}) - require.Contains(t, b.Config.Resources.VectorSearchEndpoints["vs_1"].Permissions, resources.Permission{Level: "CAN_USE", GroupName: "TestGroup"}) + require.Contains(t, b.Config.Resources.VectorSearchEndpoints["vs_1"].Permissions, resources.VectorSearchEndpointPermission{Level: "CAN_MANAGE", UserName: "TestUser"}) + require.Contains(t, b.Config.Resources.VectorSearchEndpoints["vs_1"].Permissions, resources.VectorSearchEndpointPermission{Level: "CAN_USE", GroupName: "TestGroup"}) require.Len(t, b.Config.Resources.VectorSearchEndpoints["vs_2"].Permissions, 2) - require.Contains(t, b.Config.Resources.VectorSearchEndpoints["vs_2"].Permissions, resources.Permission{Level: "CAN_MANAGE", UserName: "TestUser"}) - require.Contains(t, b.Config.Resources.VectorSearchEndpoints["vs_2"].Permissions, resources.Permission{Level: "CAN_USE", GroupName: "TestGroup"}) + require.Contains(t, b.Config.Resources.VectorSearchEndpoints["vs_2"].Permissions, resources.VectorSearchEndpointPermission{Level: "CAN_MANAGE", UserName: "TestUser"}) + require.Contains(t, b.Config.Resources.VectorSearchEndpoints["vs_2"].Permissions, resources.VectorSearchEndpointPermission{Level: "CAN_USE", GroupName: "TestGroup"}) } func TestWarningOnOverlapPermission(t *testing.T) { diff --git a/bundle/config/resources/permission_types.go b/bundle/config/resources/permission_types.go index 3029ee40b8c..769a61376ce 100644 --- a/bundle/config/resources/permission_types.go +++ b/bundle/config/resources/permission_types.go @@ -9,6 +9,7 @@ import ( "github.com/databricks/databricks-sdk-go/service/pipelines" "github.com/databricks/databricks-sdk-go/service/serving" "github.com/databricks/databricks-sdk-go/service/sql" + "github.com/databricks/databricks-sdk-go/service/vectorsearch" ) // Each resource defines its own permission type so that the JSON schema names them distinctly. @@ -32,4 +33,5 @@ type ( ModelServingEndpointPermission PermissionT[serving.ServingEndpointPermissionLevel] PipelinePermission PermissionT[pipelines.PipelinePermissionLevel] SqlWarehousePermission PermissionT[sql.WarehousePermissionLevel] + VectorSearchEndpointPermission PermissionT[vectorsearch.VectorSearchEndpointPermissionLevel] ) diff --git a/bundle/config/resources/vector_search_endpoint.go b/bundle/config/resources/vector_search_endpoint.go index 5d7ef03ca2d..13f8d790a53 100644 --- a/bundle/config/resources/vector_search_endpoint.go +++ b/bundle/config/resources/vector_search_endpoint.go @@ -16,7 +16,7 @@ type VectorSearchEndpoint struct { BaseResource vectorsearch.CreateEndpoint - Permissions []Permission `json:"permissions,omitempty"` + Permissions []VectorSearchEndpointPermission `json:"permissions,omitempty"` } func (e *VectorSearchEndpoint) UnmarshalJSON(b []byte) error { diff --git a/bundle/direct/dresources/vector_search_index.go b/bundle/direct/dresources/vector_search_index.go index 48ee6f0f968..2d6fab31081 100644 --- a/bundle/direct/dresources/vector_search_index.go +++ b/bundle/direct/dresources/vector_search_index.go @@ -24,7 +24,7 @@ const deleteIndexTimeout = 15 * time.Minute // createIndexTimeout caps the wait for an index to become ready after creation. // Delta sync indexes do an initial sync from the source table, which can stretch // out for large tables. Matches the terraform provider's defaultIndexProvisionTimeout. -// https://github.com/databricks/terraform-provider-databricks/blob/c61a32300445f84efb2bb6827dee35e6e523f4ff/vectorsearch/resource_vector_search_index.go#L19 +// https://github.com/databricks/terraform-provider-databricks/blob/c79d82d9582ab6670468bbff303199906d47905f/vectorsearch/resource_vector_search_index.go#L19 const createIndexTimeout = 75 * time.Minute // VectorSearchIndexState tracks the UUID of the endpoint the index is attached diff --git a/bundle/internal/schema/annotations.yml b/bundle/internal/schema/annotations.yml index 3adb9e9e740..6a8954ee661 100644 --- a/bundle/internal/schema/annotations.yml +++ b/bundle/internal/schema/annotations.yml @@ -1639,6 +1639,19 @@ resources: "permissions": "description": |- PLACEHOLDER + "$fields": + "group_name": + "description": |- + PLACEHOLDER + "level": + "description": |- + PLACEHOLDER + "service_principal_name": + "description": |- + PLACEHOLDER + "user_name": + "description": |- + PLACEHOLDER "vector_search_indexes": "description": |- PLACEHOLDER diff --git a/bundle/internal/validation/generated/enum_fields.go b/bundle/internal/validation/generated/enum_fields.go index d5f62ac45b8..12e8902d5a7 100644 --- a/bundle/internal/validation/generated/enum_fields.go +++ b/bundle/internal/validation/generated/enum_fields.go @@ -225,7 +225,7 @@ var EnumFields = map[string][]string{ "resources.synced_database_tables.*.unity_catalog_provisioning_state": {"ACTIVE", "DEGRADED", "DELETING", "FAILED", "PROVISIONING", "UPDATING"}, "resources.vector_search_endpoints.*.endpoint_type": {"STANDARD", "STORAGE_OPTIMIZED"}, - "resources.vector_search_endpoints.*.permissions[*].level": {"CAN_ATTACH_TO", "CAN_BIND", "CAN_CREATE", "CAN_CREATE_APP", "CAN_EDIT", "CAN_EDIT_METADATA", "CAN_MANAGE", "CAN_MANAGE_PRODUCTION_VERSIONS", "CAN_MANAGE_RUN", "CAN_MANAGE_STAGING_VERSIONS", "CAN_MONITOR", "CAN_MONITOR_ONLY", "CAN_QUERY", "CAN_READ", "CAN_RESTART", "CAN_RUN", "CAN_USE", "CAN_VIEW", "CAN_VIEW_METADATA", "IS_OWNER"}, + "resources.vector_search_endpoints.*.permissions[*].level": {"CAN_CREATE", "CAN_MANAGE", "CAN_USE"}, "resources.vector_search_indexes.*.delta_sync_index_spec.pipeline_type": {"CONTINUOUS", "TRIGGERED"}, "resources.vector_search_indexes.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json index 1afe4321798..05a4468ec84 100644 --- a/bundle/schema/jsonschema.json +++ b/bundle/schema/jsonschema.json @@ -2265,7 +2265,7 @@ "$ref": "#/$defs/string" }, "permissions": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.Permission" + "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.VectorSearchEndpointPermission" }, "target_qps": { "description": "[Public Preview] Target QPS for the endpoint. Mutually exclusive with num_replicas.\nThe actual replica count is calculated at index creation/sync time based on this value.\nBest-effort target; the system does not guarantee this QPS will be achieved.", @@ -2290,6 +2290,35 @@ } ] }, + "resources.VectorSearchEndpointPermission": { + "oneOf": [ + { + "type": "object", + "properties": { + "group_name": { + "$ref": "#/$defs/string" + }, + "level": { + "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/vectorsearch.VectorSearchEndpointPermissionLevel" + }, + "service_principal_name": { + "$ref": "#/$defs/string" + }, + "user_name": { + "$ref": "#/$defs/string" + } + }, + "additionalProperties": false, + "required": [ + "level" + ] + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.\\p{L}+([-_]*[\\p{L}\\p{N}]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, "resources.VectorSearchIndex": { "oneOf": [ { @@ -13008,6 +13037,23 @@ } ] }, + "vectorsearch.VectorSearchEndpointPermissionLevel": { + "oneOf": [ + { + "type": "string", + "description": "Permission level", + "enum": [ + "CAN_CREATE", + "CAN_MANAGE", + "CAN_USE" + ] + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.\\p{L}+([-_]*[\\p{L}\\p{N}]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, "workspace.AzureKeyVaultSecretScopeMetadata": { "oneOf": [ { @@ -13799,6 +13845,20 @@ "pattern": "\\$\\{(var(\\.\\p{L}+([-_]*[\\p{L}\\p{N}]+)*(\\[[0-9]+\\])*)+)\\}" } ] + }, + "resources.VectorSearchEndpointPermission": { + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.VectorSearchEndpointPermission" + } + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.\\p{L}+([-_]*[\\p{L}\\p{N}]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] } }, "config.ArtifactFile": { diff --git a/bundle/schema/jsonschema_for_docs.json b/bundle/schema/jsonschema_for_docs.json index 68b01662512..d6ba389a27f 100644 --- a/bundle/schema/jsonschema_for_docs.json +++ b/bundle/schema/jsonschema_for_docs.json @@ -2259,7 +2259,7 @@ "x-since-version": "v0.298.0" }, "permissions": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.Permission", + "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.VectorSearchEndpointPermission", "x-since-version": "v0.298.0" }, "target_qps": { @@ -2281,6 +2281,27 @@ "name" ] }, + "resources.VectorSearchEndpointPermission": { + "type": "object", + "properties": { + "group_name": { + "$ref": "#/$defs/string" + }, + "level": { + "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/vectorsearch.VectorSearchEndpointPermissionLevel" + }, + "service_principal_name": { + "$ref": "#/$defs/string" + }, + "user_name": { + "$ref": "#/$defs/string" + } + }, + "additionalProperties": false, + "required": [ + "level" + ] + }, "resources.VectorSearchIndex": { "type": "object", "properties": { @@ -11064,6 +11085,15 @@ "An index that supports direct read and write of vectors and metadata through our REST and SDK APIs. With this model, the user manages index updates." ] }, + "vectorsearch.VectorSearchEndpointPermissionLevel": { + "type": "string", + "description": "Permission level", + "enum": [ + "CAN_CREATE", + "CAN_MANAGE", + "CAN_USE" + ] + }, "workspace.AzureKeyVaultSecretScopeMetadata": { "type": "object", "description": "The metadata of the Azure KeyVault for a secret scope of type `AZURE_KEYVAULT`", @@ -11409,6 +11439,12 @@ "items": { "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.SqlWarehousePermission" } + }, + "resources.VectorSearchEndpointPermission": { + "type": "array", + "items": { + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.VectorSearchEndpointPermission" + } } }, "config.ArtifactFile": { diff --git a/libs/testserver/fake_workspace.go b/libs/testserver/fake_workspace.go index d2925fb1e38..772bb5c2223 100644 --- a/libs/testserver/fake_workspace.go +++ b/libs/testserver/fake_workspace.go @@ -153,7 +153,7 @@ type FakeWorkspace struct { RegisteredModels map[string]catalog.RegisteredModelInfo ServingEndpoints map[string]serving.ServingEndpointDetailed VectorSearchEndpoints map[string]vectorsearch.EndpointInfo - VectorSearchIndexes map[string]fakeVectorSearchIndex + VectorSearchIndexes map[string]vectorsearch.VectorIndex SecretScopes map[string]workspace.SecretScope Secrets map[string]map[string]string // scope -> key -> value @@ -301,7 +301,7 @@ func NewFakeWorkspace(url, token string) *FakeWorkspace { }, ServingEndpoints: map[string]serving.ServingEndpointDetailed{}, VectorSearchEndpoints: map[string]vectorsearch.EndpointInfo{}, - VectorSearchIndexes: map[string]fakeVectorSearchIndex{}, + VectorSearchIndexes: map[string]vectorsearch.VectorIndex{}, Repos: map[string]workspace.RepoInfo{}, SecretScopes: map[string]workspace.SecretScope{}, Secrets: map[string]map[string]string{}, diff --git a/libs/testserver/vector_search_indexes.go b/libs/testserver/vector_search_indexes.go index abf90080200..451188cf441 100644 --- a/libs/testserver/vector_search_indexes.go +++ b/libs/testserver/vector_search_indexes.go @@ -15,18 +15,6 @@ import ( // accepts: only alphanumerics and underscores. var indexNamePart = regexp.MustCompile(`^[A-Za-z0-9_]+$`) -// fakeVectorSearchIndex captures the endpoint's UUID at index creation time. -// On the real backend an index is bound to a specific endpoint instance, not -// just the name: deleting and recreating an endpoint with the same name yields -// a different UUID, and the existing index keeps pointing at the OLD UUID -// (i.e. is orphaned). Tracking this here lets tests reason about that drift. -// The field is omitted from JSON responses since the real API doesn't return -// it on the index path; the CLI looks it up via GetEndpointByEndpointName. -type fakeVectorSearchIndex struct { - vectorsearch.VectorIndex - EndpointUuid string `json:"-"` -} - func (s *FakeWorkspace) VectorSearchIndexCreate(req Request) Response { defer s.LockUnlock()() @@ -79,21 +67,24 @@ func (s *FakeWorkspace) VectorSearchIndexCreate(req Request) Response { createReq.DirectAccessIndexSpec.SchemaJson = normalizeSchemaJSON(createReq.DirectAccessIndexSpec.SchemaJson) } - index := fakeVectorSearchIndex{ - VectorIndex: vectorsearch.VectorIndex{ - Creator: s.CurrentUser().UserName, - EndpointName: createReq.EndpointName, - IndexType: createReq.IndexType, - IndexSubtype: indexSubtype, - Name: createReq.Name, - PrimaryKey: createReq.PrimaryKey, - DeltaSyncIndexSpec: remapDeltaSyncSpec(createReq.DeltaSyncIndexSpec), - DirectAccessIndexSpec: createReq.DirectAccessIndexSpec, - Status: &vectorsearch.VectorIndexStatus{ - Ready: true, - }, + // EndpointId is frozen at creation: the index records the UUID of the + // endpoint instance it was bound to and never re-resolves it, so after the + // endpoint is deleted/recreated under the same name it still reports the old + // UUID. This mirrors the orphaned index on the real backend; the CLI detects + // the drift by looking up the live endpoint by name, not from this field. + index := vectorsearch.VectorIndex{ + Creator: s.CurrentUser().UserName, + EndpointId: endpoint.Id, + EndpointName: createReq.EndpointName, + IndexType: createReq.IndexType, + IndexSubtype: indexSubtype, + Name: createReq.Name, + PrimaryKey: createReq.PrimaryKey, + DeltaSyncIndexSpec: remapDeltaSyncSpec(createReq.DeltaSyncIndexSpec), + DirectAccessIndexSpec: createReq.DirectAccessIndexSpec, + Status: &vectorsearch.VectorIndexStatus{ + Ready: true, }, - EndpointUuid: endpoint.Id, } s.VectorSearchIndexes[createReq.Name] = index @@ -177,6 +168,8 @@ func remapDeltaSyncSpec(req *vectorsearch.DeltaSyncVectorIndexSpecRequest) *vect return nil } return &vectorsearch.DeltaSyncVectorIndexSpecResponse{ + ColumnsToIndex: req.ColumnsToIndex, + ColumnsToSync: req.ColumnsToSync, EmbeddingSourceColumns: req.EmbeddingSourceColumns, EmbeddingVectorColumns: req.EmbeddingVectorColumns, EmbeddingWritebackTable: req.EmbeddingWritebackTable,