Skip to content

Commit 557785b

Browse files
authored
Support serverless workspaces in databricks_mws_workspaces (#4670)
## Changes A new field `compute_mode` has been added to `databricks_mws_workspaces`. This can be set to `SERVERLESS` to indicate that a workspace should be serverless. Serverless workspaces are documented at https://docs.databricks.com/aws/en/admin/workspace/serverless-workspaces. These workspaces need neither `credentials_id` or `storage_configuration_id`, so the setup should be much easier. ## Tests Added an integration test for creating serverless workspaces in AWS. ## Todos - [x] Need to verify if serverless workspaces work in GCP. EDIT: not yet supported. - [x] Need to verify which regions users can specify for serverless workspaces. EDIT: this will be documented shortly. I'll include a link. - [x] The test does not work right now, I think our E2 account still needs to be onboarded. EDIT: our account was onboarded and we verified that this works.
1 parent 6164b4e commit 557785b

File tree

4 files changed

+69
-23
lines changed

4 files changed

+69
-23
lines changed

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
* Add support for `power_bi_task` in jobs ([#4647](https://github.com/databricks/terraform-provider-databricks/pull/4647))
88
* Add support for `dashboard_task` in jobs ([#4646](https://github.com/databricks/terraform-provider-databricks/pull/4646))
9+
* Add `compute_mode` to `databricks_mws_workspaces` to support creating serverless workspaces ([#4670](https://github.com/databricks/terraform-provider-databricks/pull/4670)).
910

1011
### Bug Fixes
1112

docs/resources/mws_workspaces.md

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,22 @@ This resource allows you to set up [workspaces on AWS](https://docs.databricks.c
1818

1919
## Example Usage
2020

21-
### Creating a Databricks on AWS workspace
21+
### Creating a serverless workspace in AWS
22+
23+
Creating a serverless workspace does not require any prerequisite resources. Simply specify `compute_mode = "SERVERLESS"` when creating the workspace. Serverless workspaces must not include `credentials_id` or `storage_configuration_id`.
24+
25+
To use serverless workspaces, you must enroll in the [Default Storage preview](https://docs.databricks.com/aws/en/storage/express-storage).
26+
27+
```hcl
28+
resource "databricks_mws_workspaces" "serverless_workspace" {
29+
account_id = "" # Your Databricks account ID
30+
workspace_name = "serverless-workspace"
31+
aws_region = "us-east-1"
32+
compute_mode = "SERVERLESS"
33+
}
34+
```
35+
36+
### Creating a workspace on AWS
2237

2338
![Simplest multiworkspace](https://raw.githubusercontent.com/databricks/terraform-provider-databricks/main/docs/simplest-multiworkspace.png)
2439

@@ -85,11 +100,11 @@ output "databricks_token" {
85100
}
86101
```
87102

88-
### Creating a Databricks on AWS workspace with Databricks-Managed VPC
103+
### Creating a workspace on AWS with Databricks-Managed VPC
89104

90105
![VPCs](https://docs.databricks.com/_images/customer-managed-vpc.png)
91106

92-
By default, Databricks creates a VPC in your AWS account for each workspace. Databricks uses it for running clusters in the workspace. Optionally, you can use your VPC for the workspace, using the feature customer-managed VPC. Databricks recommends that you provide your VPC with [databricks_mws_networks](mws_networks.md) so that you can configure it according to your organizations enterprise cloud standards while still conforming to Databricks requirements. You cannot migrate an existing workspace to your VPC. Please see the difference described through IAM policy actions [on this page](https://docs.databricks.com/administration-guide/account-api/iam-role.html).
107+
By default, Databricks creates a VPC in your AWS account for each workspace. Databricks uses it for running clusters in the workspace. Optionally, you can use your VPC for the workspace, using the feature customer-managed VPC. Databricks recommends that you provide your VPC with [databricks_mws_networks](mws_networks.md) so that you can configure it according to your organization's enterprise cloud standards while still conforming to Databricks requirements. You cannot migrate an existing workspace to your VPC. Please see the difference described through IAM policy actions [on this page](https://docs.databricks.com/administration-guide/account-api/iam-role.html).
93108

94109
```hcl
95110
variable "databricks_account_id" {
@@ -209,7 +224,7 @@ output "databricks_token" {
209224

210225
In order to create a [Databricks Workspace that leverages AWS PrivateLink](https://docs.databricks.com/administration-guide/cloud-configurations/aws/privatelink.html) please ensure that you have read and understood the [Enable Private Link](https://docs.databricks.com/administration-guide/cloud-configurations/aws/privatelink.html) documentation and then customise the example above with the relevant examples from [mws_vpc_endpoint](mws_vpc_endpoint.md), [mws_private_access_settings](mws_private_access_settings.md) and [mws_networks](mws_networks.md).
211226

212-
### Creating a Databricks on GCP workspace
227+
### Creating a workspace on GCP
213228

214229
To get workspace running, you have to configure a network object:
215230

@@ -270,11 +285,11 @@ output "databricks_token" {
270285

271286
In order to create a [Databricks Workspace that leverages GCP Private Service Connect](https://docs.gcp.databricks.com/administration-guide/cloud-configurations/gcp/private-service-connect.html) please ensure that you have read and understood the [Enable Private Service Connect](https://docs.gcp.databricks.com/administration-guide/cloud-configurations/gcp/private-service-connect.html) documentation and then customise the example above with the relevant examples from [mws_vpc_endpoint](mws_vpc_endpoint.md), [mws_private_access_settings](mws_private_access_settings.md) and [mws_networks](mws_networks.md).
272287

273-
#### Creating a Databricks on GCP workspace with Databricks-Managed VPC
288+
#### Creating a workspace on GCP with Databricks-Managed VPC
274289

275290
![VPCs](https://docs.databricks.com/_images/customer-managed-vpc.png)
276291

277-
By default, Databricks creates a VPC in your GCP project for each workspace. Databricks uses it for running clusters in the workspace. Optionally, you can use your VPC for the workspace, using the feature customer-managed VPC. Databricks recommends that you provide your VPC with [databricks_mws_networks](mws_networks.md) so that you can configure it according to your organizations enterprise cloud standards while still conforming to Databricks requirements. You cannot migrate an existing workspace to your VPC.
292+
By default, Databricks creates a VPC in your GCP project for each workspace. Databricks uses it for running clusters in the workspace. Optionally, you can use your VPC for the workspace, using the feature customer-managed VPC. Databricks recommends that you provide your VPC with [databricks_mws_networks](mws_networks.md) so that you can configure it according to your organization's enterprise cloud standards while still conforming to Databricks requirements. You cannot migrate an existing workspace to your VPC.
278293

279294
```hcl
280295
variable "databricks_account_id" {
@@ -324,7 +339,8 @@ The following arguments are available:
324339
* `workspace_name` - name of the workspace, will appear on UI.
325340
* `network_id` - (Optional) `network_id` from [networks](mws_networks.md).
326341
* `aws_region` - (AWS only) region of VPC.
327-
* `storage_configuration_id` - (AWS only)`storage_configuration_id` from [storage configuration](mws_storage_configurations.md).
342+
* `storage_configuration_id` - (AWS only, Optional) `storage_configuration_id` from [storage configuration](mws_storage_configurations.md). This must not be specified when `compute_mode` is set to `SERVERLESS`.
343+
* `credentials_id` - (AWS only, Optional) `credentials_id` from [credentials](mws_credentials.md). This must not be specified when `compute_mode` is set to `SERVERLESS`.
328344
* `managed_services_customer_managed_key_id` - (Optional) `customer_managed_key_id` from [customer managed keys](mws_customer_managed_keys.md) with `use_cases` set to `MANAGED_SERVICES`. This is used to encrypt the workspace's notebook and secret data in the control plane.
329345
* `storage_customer_managed_key_id` - (Optional) `customer_managed_key_id` from [customer managed keys](mws_customer_managed_keys.md) with `use_cases` set to `STORAGE`. This is used to encrypt the DBFS Storage & Cluster Volumes.
330346
* `location` - (GCP only) region of the subnet.
@@ -337,6 +353,7 @@ The following arguments are available:
337353
* `private_access_settings_id` - (Optional) Canonical unique identifier of [databricks_mws_private_access_settings](mws_private_access_settings.md) in Databricks Account.
338354
* `custom_tags` - (Optional / AWS only) - The custom tags key-value pairing that is attached to this workspace. These tags will be applied to clusters automatically in addition to any `default_tags` or `custom_tags` on a cluster level. Please note it can take up to an hour for custom_tags to be set due to scheduling on Control Plane. After custom tags are applied, they can be modified however they can never be completely removed.
339355
* `pricing_tier` - (Optional) - The pricing tier of the workspace.
356+
* `compute_mode` - (Optional) - The compute mode for the workspace. When unset, a classic workspace is created, and both `credentials_id` and `storage_configuration_id` must be specified. When set to `SERVERLESS`, the resulting workspace is a serverless workspace, and `credentials_id` and `storage_configuration_id` must not be set. The only allowed value for this is `SERVERLESS`. Changing this field requires recreation of the workspace.
340357

341358
### token block
342359

@@ -369,6 +386,7 @@ In addition to all arguments above, the following attributes are exported:
369386
* `workspace_url` - (String) URL of the workspace
370387
* `custom_tags` - (Map) Custom Tags (if present) added to workspace
371388
* `gcp_workspace_sa` - (String, GCP only) identifier of a service account created for the workspace in form of `db-<workspace-id>@prod-gcp-<region>.iam.gserviceaccount.com`
389+
* `effective_compute_mode` - (String) The effective compute mode for the workspace. This is either `SERVERLESS` for serverless workspaces or `HYBRID` for classic workspaces.
372390

373391
## Timeouts
374392

mws/mws_workspaces_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,22 @@ func TestMwsAccWorkspaces(t *testing.T) {
7676
})
7777
}
7878

79+
func TestMwsAccWorkspaces_Serverless(t *testing.T) {
80+
acceptance.LoadAccountEnv(t)
81+
if !acceptance.IsAws(t) {
82+
acceptance.Skipf(t)("TestMwsAccWorkspaces_Serverless is currently only supported on AWS")
83+
}
84+
acceptance.AccountLevel(t, acceptance.Step{
85+
Template: `
86+
resource "databricks_mws_workspaces" "this" {
87+
account_id = "{env.DATABRICKS_ACCOUNT_ID}"
88+
workspace_name = "terra-{var.RANDOM}"
89+
aws_region = "{env.AWS_REGION}"
90+
compute_mode = "SERVERLESS"
91+
}`,
92+
})
93+
}
94+
7995
func TestMwsAccWorkspacesTokenUpdate(t *testing.T) {
8096
acceptance.AccountLevel(t, acceptance.Step{
8197
Template: `

mws/resource_mws_workspaces.go

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/hashicorp/go-cty/cty"
2222
"github.com/hashicorp/terraform-plugin-log/tflog"
2323
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
24+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
2425
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
2526
)
2627

@@ -104,6 +105,8 @@ type Workspace struct {
104105
Cloud string `json:"cloud,omitempty" tf:"computed"`
105106
Location string `json:"location,omitempty"`
106107
CustomTags map[string]string `json:"custom_tags,omitempty"` // Optional for AWS, not allowed for GCP
108+
ComputeMode string `json:"compute_mode,omitempty" tf:"force_new"`
109+
EffectiveComputeMode string `json:"effective_compute_mode" tf:"computed"`
107110
}
108111

109112
// this type alias hack is required for Marshaller to work without an infinite loop
@@ -141,6 +144,9 @@ func (w *Workspace) MarshalJSON() ([]byte, error) {
141144
if w.StorageCustomerManagedKeyID != "" {
142145
workspaceCreationRequest["storage_customer_managed_key_id"] = w.StorageCustomerManagedKeyID
143146
}
147+
if w.ComputeMode != "" {
148+
workspaceCreationRequest["compute_mode"] = w.ComputeMode
149+
}
144150
return json.Marshal(workspaceCreationRequest)
145151
}
146152

@@ -314,6 +320,10 @@ func (a WorkspacesAPI) Read(mwsAcctID, workspaceID string) (Workspace, error) {
314320
host := generateWorkspaceHostname(a.client, mwsWorkspace)
315321
mwsWorkspace.WorkspaceURL = fmt.Sprintf("https://%s", host)
316322
}
323+
// Set the effective compute mode to the compute mode
324+
mwsWorkspace.EffectiveComputeMode = mwsWorkspace.ComputeMode
325+
mwsWorkspace.ComputeMode = ""
326+
317327
return mwsWorkspace, err
318328
}
319329

@@ -546,23 +556,13 @@ func ResourceMwsWorkspaces() common.Resource {
546556
common.CustomizeSchemaPath(s, "gke_config").SetDeprecated(getGkeDeprecationMessage("gke_config", docOptions))
547557
common.CustomizeSchemaPath(s, "gcp_managed_network_config", "gke_cluster_pod_ip_range").SetDeprecated(getGkeDeprecationMessage("gcp_managed_network_config.gke_cluster_pod_ip_range", docOptions))
548558
common.CustomizeSchemaPath(s, "gcp_managed_network_config", "gke_cluster_service_ip_range").SetDeprecated(getGkeDeprecationMessage("gcp_managed_network_config.gke_cluster_service_ip_range", docOptions))
559+
common.CustomizeSchemaPath(s, "compute_mode").SetValidateDiagFunc(validation.ToDiagFunc(validation.StringInSlice([]string{"SERVERLESS"}, false)))
549560
return s
550561
})
551562
p := common.NewPairSeparatedID("account_id", "workspace_id", "/").Schema(
552563
func(_ map[string]*schema.Schema) map[string]*schema.Schema {
553564
return workspaceSchema
554565
})
555-
requireFields := func(onThisCloud bool, d *schema.ResourceData, fields ...string) error {
556-
if !onThisCloud {
557-
return nil
558-
}
559-
for _, fieldName := range fields {
560-
if d.Get(fieldName) == workspaceSchema[fieldName].ZeroValue() {
561-
return fmt.Errorf("%s is required", fieldName)
562-
}
563-
}
564-
return nil
565-
}
566566
return common.Resource{
567567
Schema: workspaceSchema,
568568
SchemaVersion: 3,
@@ -577,11 +577,22 @@ func ResourceMwsWorkspaces() common.Resource {
577577
var workspace Workspace
578578
workspacesAPI := NewWorkspacesAPI(ctx, c)
579579
common.DataToStructPointer(d, workspaceSchema, &workspace)
580-
if err := requireFields(c.IsAws(), d, "aws_region", "credentials_id", "storage_configuration_id"); err != nil {
581-
return err
582-
}
583-
if err := requireFields(c.IsGcp(), d, "location"); err != nil {
584-
return err
580+
if c.IsAws() {
581+
if _, ok := d.GetOk("aws_region"); !ok {
582+
return fmt.Errorf("aws_region is required for AWS workspaces")
583+
}
584+
if d.Get("compute_mode") != "SERVERLESS" {
585+
if _, ok := d.GetOk("credentials_id"); !ok {
586+
return fmt.Errorf("credentials_id is required for non-serverless workspaces")
587+
}
588+
if _, ok := d.GetOk("storage_configuration_id"); !ok {
589+
return fmt.Errorf("storage_configuration_id is required for non-serverless workspaces")
590+
}
591+
}
592+
} else if c.IsGcp() {
593+
if _, ok := d.GetOk("location"); !ok {
594+
return fmt.Errorf("location is required for GCP workspaces")
595+
}
585596
}
586597
if !c.IsAws() && workspace.CustomTags != nil {
587598
return fmt.Errorf("custom_tags are only allowed for AWS workspaces")

0 commit comments

Comments
 (0)