Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Vector Search Endpoints #3191

Merged
merged 14 commits into from
Feb 15, 2024
48 changes: 48 additions & 0 deletions docs/resources/vector_search_endpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
subcategory: "Vector Search"
---
# databricks_vector_search_endpoint Resource

-> **Note** This resource could be only used on Unity Catalog-enabled workspace!

This resource allows you to create [Vector Search Endpoint](https://docs.databricks.com/en/generative-ai/vector-search.html) in Databricks. Vector Search is a serverless similarity search engine that allows you to store a vector representation of your data, including metadata, in a vector database. The Vector Search Endpoint is used to create and access vector search indexes.

## Example Usage


```hcl
resource "databricks_vector_search_endpoint" "this" {
name = "vector-search-test"
endpoint_type = "STANDARD"
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) Name of the Vector Search Endpoint to create. If name is changed, Vector Search Endpoint is recreated.
* `endpoint_type` (Required) type of Vector Search Endpoint. Currently only accepting single value: `STANDARD` (See [documentation](https://docs.databricks.com/api/workspace/vectorsearchendpoints/createendpoint) for the list of currently supported values). If it's changed, Vector Search Endpoint is recreated.

## Attribute Reference

In addition to all arguments above, the following attributes are exported:

* `id` - The same as the name of the endpoint.
* `creator` - Creator of the endpoint.
* `creation_timestamp` - Timestamp of endpoint creation (milliseconds).
* `last_updated_user` - User who last updated the endpoint.
* `last_updated_timestamp` - Timestamp of last update to the endpoint (milliseconds).
* `endpoint_id` - Unique internal identifier of the endpoint (UUID).
* `num_indexes` - Number of indexes on the endpoint.
* `endpoint_status` - Object describing the current status of the endpoint consisting of following fields:
* `state` - Current state of the endpoint. Currently following values are supported: `PROVISIONING`, `ONLINE`, `OFFLINE`.
* `message` - Additional status message.

## Import

The resource can be imported using the name of the Vector Search Endpoint

```bash
terraform import databricks_vector_search_endpoint.this <endpoint-name>
```
1 change: 1 addition & 0 deletions exporter/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2168,6 +2168,7 @@ func TestImportingNotebooksWorkspaceFiles(t *testing.T) {
Response: workspace.ObjectList{
Objects: []workspace.ObjectStatus{notebookStatus, fileStatus},
},
ReuseRequest: true,
},
{
Method: "GET",
Expand Down
30 changes: 30 additions & 0 deletions internal/acceptance/vector_search_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package acceptance

import (
"fmt"
"os"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
)

func TestUcAccVectorSearchEndpoint(t *testing.T) {
cloudEnv := os.Getenv("CLOUD_ENV")
switch cloudEnv {
case "ucws", "azure":
default:
t.Skipf("not available on %s", cloudEnv)
}

name := fmt.Sprintf("terraform-test-vector-search-%[1]s",
acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum))
unityWorkspaceLevel(t, step{
Template: fmt.Sprintf(`
resource "databricks_vector_search_endpoint" "this" {
name = "%s"
endpoint_type = "STANDARD"
}
`, name),
},
)
}
2 changes: 2 additions & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/databricks/terraform-provider-databricks/sql"
"github.com/databricks/terraform-provider-databricks/storage"
"github.com/databricks/terraform-provider-databricks/tokens"
"github.com/databricks/terraform-provider-databricks/vectorsearch"
"github.com/databricks/terraform-provider-databricks/workspace"
)

Expand Down Expand Up @@ -173,6 +174,7 @@ func DatabricksProvider() *schema.Provider {
"databricks_user": scim.ResourceUser().ToResource(),
"databricks_user_instance_profile": aws.ResourceUserInstanceProfile().ToResource(),
"databricks_user_role": aws.ResourceUserRole().ToResource(),
"databricks_vector_search_endpoint": vectorsearch.ResourceVectorSearchEndpoint().ToResource(),
"databricks_volume": catalog.ResourceVolume().ToResource(),
"databricks_workspace_conf": workspace.ResourceWorkspaceConf().ToResource(),
"databricks_workspace_file": workspace.ResourceWorkspaceFile().ToResource(),
Expand Down
85 changes: 85 additions & 0 deletions vectorsearch/resource_vector_search_endpoint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package vectorsearch

import (
"context"
"time"

"github.com/databricks/terraform-provider-databricks/common"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/databricks/databricks-sdk-go/service/vectorsearch"
)

const DefaultProvisionTimeout = 45 * time.Minute
alexott marked this conversation as resolved.
Show resolved Hide resolved

func ResourceVectorSearchEndpoint() common.Resource {
s := common.StructToSchema(
vectorsearch.EndpointInfo{},
func(s map[string]*schema.Schema) map[string]*schema.Schema {
common.CustomizeSchemaPath(s, "name").SetRequired().SetForceNew()
common.CustomizeSchemaPath(s, "endpoint_type").SetRequired().SetForceNew()
delete(s, "id")
alexott marked this conversation as resolved.
Show resolved Hide resolved
common.CustomizeSchemaPath(s, "creator").SetReadOnly()
common.CustomizeSchemaPath(s, "creation_timestamp").SetReadOnly()
common.CustomizeSchemaPath(s, "last_updated_timestamp").SetReadOnly()
common.CustomizeSchemaPath(s, "last_updated_user").SetReadOnly()
common.CustomizeSchemaPath(s, "endpoint_status").SetReadOnly()
common.CustomizeSchemaPath(s, "num_indexes").SetReadOnly()
common.CustomizeSchemaPath(s).AddNewField("endpoint_id", &schema.Schema{
Type: schema.TypeString,
Computed: true,
})
alexott marked this conversation as resolved.
Show resolved Hide resolved

return s
})

return common.Resource{
Create: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
w, err := c.WorkspaceClient()
if err != nil {
return err
}
var req vectorsearch.CreateEndpoint
common.DataToStructPointer(d, s, &req)
wait, err := w.VectorSearchEndpoints.CreateEndpoint(ctx, req)
if err != nil {
return err
}
endpoint, err := wait.GetWithTimeout(d.Timeout(schema.TimeoutCreate))
if err != nil {
return err
}
d.SetId(endpoint.Name)
return nil
},
Read: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
w, err := c.WorkspaceClient()
if err != nil {
return err
}
endpoint, err := w.VectorSearchEndpoints.GetEndpointByEndpointName(ctx, d.Id())
if err != nil {
return err
}
err = common.StructToData(*endpoint, s, d)
if err != nil {
return err
}
d.Set("endpoint_id", endpoint.Id)
return nil
},
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
w, err := c.WorkspaceClient()
if err != nil {
return err
}
return w.VectorSearchEndpoints.DeleteEndpointByEndpointName(ctx, d.Id())
},
StateUpgraders: []schema.StateUpgrader{},
Schema: s,
SchemaVersion: 0,
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(DefaultProvisionTimeout),
},
}
}
83 changes: 83 additions & 0 deletions vectorsearch/resource_vector_search_endpoint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package vectorsearch

import (
"testing"

"github.com/databricks/databricks-sdk-go/experimental/mocks"
"github.com/databricks/databricks-sdk-go/qa/poll"
"github.com/databricks/terraform-provider-databricks/qa"

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

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

func TestVectorSearchEndpointCornerCases(t *testing.T) {
qa.ResourceCornerCases(t, ResourceVectorSearchEndpoint())
}

func TestVectorSearchEndpointCreate(t *testing.T) {
alexott marked this conversation as resolved.
Show resolved Hide resolved
ei := &vectorsearch.EndpointInfo{
Name: "abc",
EndpointStatus: &vectorsearch.EndpointStatus{State: "ONLINE"},
Id: "1234-5678",
}
d, err := qa.ResourceFixture{
MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) {
e := w.GetMockVectorSearchEndpointsAPI().EXPECT()
e.CreateEndpoint(mock.Anything, vectorsearch.CreateEndpoint{
Name: "abc",
EndpointType: "STANDARD",
}).Return(&vectorsearch.WaitGetEndpointVectorSearchEndpointOnline[vectorsearch.EndpointInfo]{Poll: poll.Simple(*ei)}, nil)

e.GetEndpointByEndpointName(mock.Anything, "abc").Return(ei, nil)
},
Resource: ResourceVectorSearchEndpoint(),
HCL: `
name = "abc"
endpoint_type = "STANDARD"
`,
Create: true,
}.Apply(t)
assert.NoError(t, err)
assert.Equal(t, "abc", d.Id())
assert.Equal(t, "1234-5678", d.Get("endpoint_id"))
}

func TestVectorSearchEndpointRead(t *testing.T) {
ei := &vectorsearch.EndpointInfo{
Name: "abc",
EndpointStatus: &vectorsearch.EndpointStatus{State: "ONLINE"},
Id: "1234-5678",
}
d, err := qa.ResourceFixture{
MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) {
e := w.GetMockVectorSearchEndpointsAPI().EXPECT()
e.GetEndpointByEndpointName(mock.Anything, "abc").Return(ei, nil)
},
Resource: ResourceVectorSearchEndpoint(),
ID: "abc",
HCL: `
name = "abc"
endpoint_type = "STANDARD"
`,
Read: true,
}.Apply(t)
assert.NoError(t, err)
assert.Equal(t, "abc", d.Id())
assert.Equal(t, "1234-5678", d.Get("endpoint_id"))
}

func TestResourcePASDelete(t *testing.T) {
d, err := qa.ResourceFixture{
MockWorkspaceClientFunc: func(a *mocks.MockWorkspaceClient) {
a.GetMockVectorSearchEndpointsAPI().EXPECT().DeleteEndpointByEndpointName(mock.Anything, "abc").Return(nil)
},
Resource: ResourceVectorSearchEndpoint(),
Delete: true,
ID: "abc",
}.Apply(t)
assert.NoError(t, err)
assert.Equal(t, "abc", d.Id())
}
Loading