diff --git a/README.md b/README.md index a23ad0ef9f..d622e3d2a6 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ | [databricks_mws_storage_configurations](docs/resources/mws_storage_configurations.md) | [databricks_mws_vpc_endpoint](docs/resources/mws_vpc_endpoint.md) | [databricks_mws_workspaces](docs/resources/mws_workspaces.md) +| [databricks_mws_workspaces](docs/data-sources/mws_workspaces.md) data | [databricks_node_type](docs/data-sources/node_type.md) data | [databricks_notebook](docs/resources/notebook.md) | [databricks_notebook](docs/data-sources/notebook.md) data diff --git a/common/reflect_resource.go b/common/reflect_resource.go index e9a25a4675..7a786eafb6 100644 --- a/common/reflect_resource.go +++ b/common/reflect_resource.go @@ -240,6 +240,15 @@ func typeToSchema(v reflect.Value, t reflect.Type, path []string) map[string]*sc handleSuppressDiff(typeField, scm[fieldName]) case reflect.Map: scm[fieldName].Type = schema.TypeMap + elem := typeField.Type.Elem() + switch elem.Kind() { + case reflect.String: + scm[fieldName].Elem = schema.TypeString + case reflect.Int64: + scm[fieldName].Elem = schema.TypeInt + default: + panic(fmt.Errorf("unsupported map value for %s: %s", fieldName, reflectKind(elem.Kind()))) + } case reflect.Ptr: scm[fieldName].MaxItems = 1 scm[fieldName].Type = schema.TypeList diff --git a/docs/data-sources/mws_workspaces.md b/docs/data-sources/mws_workspaces.md new file mode 100755 index 0000000000..83d53aa5d8 --- /dev/null +++ b/docs/data-sources/mws_workspaces.md @@ -0,0 +1,42 @@ +--- +subcategory: "AWS" +--- +# databricks_mws_workspaces Data Source + +-> **Note** If you have a fully automated setup with workspaces created by [databricks_mws_workspaces](../resources/mws_workspaces.md) or [azurerm_databricks_workspace](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/databricks_workspace), please make sure to add [depends_on attribute](../index.md#data-resources-and-authentication-is-not-configured-errors) in order to prevent _authentication is not configured for provider_ errors. + +Lists all [databricks_mws_workspaces](../resources/mws_workspaces.md) in Databricks Account. + +-> **Note** [`account_id`](../index.md#account_id) provider configuration property is required for this resource to work. + +## Example Usage + +Listing all workspaces in + +```hcl +provider "databricks" { + // other configuration + account_id = "" +} + +data "databricks_mws_workspaces" "all" {} + +output "all_mws_workspaces" { + value = data.databricks_mws_workspaces.all.ids +} +``` + +## Attribute Reference + +-> **Note** This resource has an evolving interface, which may change in future versions of the provider. + +This data source exports the following attributes: + +* `ids` - name-to-id map for all of the workspaces in the account + +## Related Resources + +The following resources are used in the same context: + +* [databricks_mws_workspaces](../resources/mws_workspaces.md) to manage Databricks E2 Workspaces. +* [databricks_metastore_assignment](../resources/metastore_assignment.md) to assign [databricks_metastore](docs/resources/metastore.md) to [databricks_mws_workspaces](../resources/mws_workspaces.md) or [azurerm_databricks_workspace](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/databricks_workspace) diff --git a/mws/acceptance/data_mws_workspaces_test.go b/mws/acceptance/data_mws_workspaces_test.go new file mode 100755 index 0000000000..419a59924f --- /dev/null +++ b/mws/acceptance/data_mws_workspaces_test.go @@ -0,0 +1,36 @@ +package acceptance + +import ( + "fmt" + "os" + + "github.com/databricks/terraform-provider-databricks/internal/acceptance" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "testing" +) + +func TestAccDataSourceMwsWorkspaces(t *testing.T) { + cloudEnv := os.Getenv("CLOUD_ENV") + if cloudEnv != "MWS" { + t.Skip("Cannot run test on non-MWS environment") + } + acceptance.Test(t, []acceptance.Step{ + { + Template: ` + data "databricks_mws_workspaces" "this" { + }`, + Check: func(s *terraform.State) error { + r, ok := s.RootModule().Resources["data.databricks_mws_workspaces.this"] + if !ok { + return fmt.Errorf("data not found in state") + } + ids := r.Primary.Attributes["ids.%"] + if ids == "" { + return fmt.Errorf("ids is empty: %v", r.Primary.Attributes) + } + return nil + }, + }, + }) +} diff --git a/mws/data_mws_workspaces.go b/mws/data_mws_workspaces.go new file mode 100755 index 0000000000..b16a5a0c6d --- /dev/null +++ b/mws/data_mws_workspaces.go @@ -0,0 +1,30 @@ +package mws + +import ( + "context" + "fmt" + + "github.com/databricks/terraform-provider-databricks/common" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceMwsWorkspaces() *schema.Resource { + type mwsWorkspacesData struct { + Ids map[string]int64 `json:"ids,omitempty" tf:"computed"` + } + return common.DataResource(mwsWorkspacesData{}, func(ctx context.Context, e any, c *common.DatabricksClient) error { + data := e.(*mwsWorkspacesData) + if c.AccountID == "" { + return fmt.Errorf("provider block is missing `account_id` property") + } + workspaces, err := NewWorkspacesAPI(ctx, c).List(c.AccountID) + if err != nil { + return err + } + data.Ids = map[string]int64{} + for _, v := range workspaces { + data.Ids[v.WorkspaceName] = v.WorkspaceID + } + return nil + }) +} diff --git a/mws/data_mws_workspaces_test.go b/mws/data_mws_workspaces_test.go new file mode 100755 index 0000000000..f044f3da36 --- /dev/null +++ b/mws/data_mws_workspaces_test.go @@ -0,0 +1,50 @@ +package mws + +import ( + "testing" + + "github.com/databricks/terraform-provider-databricks/qa" +) + +func TestDataSourceMwsWorkspaces(t *testing.T) { + qa.ResourceFixture{ + Fixtures: []qa.HTTPFixture{ + { + Method: "GET", + Resource: "/api/2.0/accounts/abc/workspaces", + + Response: []Workspace{ + { + WorkspaceName: "bcd", + WorkspaceID: 123, + }, + { + WorkspaceName: "def", + WorkspaceID: 456, + }, + }, + }, + }, + AccountID: "abc", + Resource: DataSourceMwsWorkspaces(), + Read: true, + NonWritable: true, + ID: "_", + }.ApplyAndExpectData(t, map[string]any{ + "ids": map[string]any{ + "bcd": 123, + "def": 456, + }, + }) +} + +func TestCatalogsData_Error(t *testing.T) { + qa.ResourceFixture{ + AccountID: "abc", + Fixtures: qa.HTTPFailures, + Resource: DataSourceMwsWorkspaces(), + Read: true, + NonWritable: true, + ID: "_", + }.ExpectError(t, "I'm a teapot") +} diff --git a/provider/provider.go b/provider/provider.go index dca9a9d2b4..e23cae8057 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -47,6 +47,7 @@ func DatabricksProvider() *schema.Provider { "databricks_dbfs_file_paths": storage.DataSourceDbfsFilePaths(), "databricks_group": scim.DataSourceGroup(), "databricks_jobs": jobs.DataSourceJobs(), + "databricks_mws_workspaces": mws.DataSourceMwsWorkspaces(), "databricks_node_type": clusters.DataSourceNodeType(), "databricks_notebook": workspace.DataSourceNotebook(), "databricks_notebook_paths": workspace.DataSourceNotebookPaths(), diff --git a/qa/testing.go b/qa/testing.go index 514d23ba40..e98751edce 100644 --- a/qa/testing.go +++ b/qa/testing.go @@ -85,6 +85,7 @@ type ResourceFixture struct { Azure bool AzureSPN bool Gcp bool + AccountID string Token string // new resource New bool @@ -168,6 +169,9 @@ func (f ResourceFixture) Apply(t *testing.T) (*schema.ResourceData, error) { if f.Gcp { client.GoogleServiceAccount = "sa@prj.iam.gserviceaccount.com" } + if f.AccountID != "" { + client.AccountID = f.AccountID + } if len(f.HCL) > 0 { var out any // TODO: update to HCLv2 somehow, so that importer and this use the same stuff