diff --git a/CHANGELOG.md b/CHANGELOG.md index 250da6efa0..3e37ebafdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 0.2.8 +* Added [databricks_workspace_conf](https://github.com/databrickslabs/terraform-provider-databricks/pull/398) resource * Added [databricks_mws_log_delivery](https://github.com/databrickslabs/terraform-provider-databricks/pull/343) resource for billable usage & audit logs consumption. * Added [databricks_node_type](https://github.com/databrickslabs/terraform-provider-databricks/pull/376) data source for simpler selection of node types across AWS & Azure. * Added [Azure Key Vault support](https://github.com/databrickslabs/terraform-provider-databricks/pull/381) for databricks_secret_scope for Azure CLI authenticated users. diff --git a/README.md b/README.md index 28028bd293..f2e4fd36a1 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ End-to-end workspace creation on [AWS](scripts/awsmt-integration) or [Azure](scr | [databricks_group_member](docs/resources/group_member.md) | [databricks_instance_pool](docs/resources/instance_pool.md) | [databricks_instance_profile](docs/resources/instance_profile.md) +| [databricks_ip_access_list](docs/resources/ip_access_list.md) | [databricks_job](docs/resources/job.md) | [databricks_mws_credentials](docs/resources/mws_credentials.md) | [databricks_mws_customer_managed_keys](docs/resources/mws_customer_managed_keys.md) @@ -40,6 +41,7 @@ End-to-end workspace creation on [AWS](scripts/awsmt-integration) or [Azure](scr | [databricks_token](docs/resources/token.md) | [databricks_user](docs/resources/user.md) | [databricks_user_instance_profile](docs/resources/user_instance_profile.md) +| [databricks_workspace_conf](docs/resources/workspace_conf.md) | [Contributing and Development Guidelines](CONTRIBUTING.md) | [Changelog](CHANGELOG.md) diff --git a/docs/resources/ip_access_list.md b/docs/resources/ip_access_list.md new file mode 100644 index 0000000000..e54fd5a41d --- /dev/null +++ b/docs/resources/ip_access_list.md @@ -0,0 +1,43 @@ +# databricks_ip_access_list Resource + +Security-conscious enterprises that use cloud SaaS applications need to restrict access to their own employees. Authentication helps to prove user identity, but that does not enforce network location of the users. Accessing a cloud service from an unsecured network can pose security risks to an enterprise, especially when the user may have authorized access to sensitive or personal data. Enterprise network perimeters apply security policies and limit access to external services (for example, firewalls, proxies, DLP, and logging), so access beyond these controls are assumed to be untrusted. Please see [IP Access List](https://docs.databricks.com/security/network/ip-access-list.html) for full feature documentation. + +-> **Note** The total number of IP addresses and CIDR scopes provided across all ACL Lists in a workspace can not exceed 1000. Refer to the docs above for specifics. + +## Example Usage + +```hcl +resource "databricks_workspace_conf" "this" { + custom_config = { + "enableIpAccessLists": true + } +} + +resource "databricks_ip_access_list" "allowed-list" { + label = "allow_in" + list_type = "ALLOW" + ip_addresses = [ + "1.2.3.0/24", + "1.2.5.0/24" + ] + depends_on = [databricks_workspace_conf.this] +} +``` +## Argument Reference + +The following arguments are supported: + +* `list_type` - Can only be "ALLOW" or "BLOCK" +* `ip_addresses` - This is a field to allow the group to have instance pool create priviliges. +* `label` - (Optional) This is the display name for the given IP ACL List. +* `enabled` - (Optional) Boolean `true` or `false` indicating whether this list should be active. Defaults to `true` + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `list_id` - Canonical unique identifier for the IP Access List. + +## Import + +Importing this resource is not currently supported. \ No newline at end of file diff --git a/docs/resources/ip_accessl_list.md b/docs/resources/ip_accessl_list.md deleted file mode 100644 index 1fd8346032..0000000000 --- a/docs/resources/ip_accessl_list.md +++ /dev/null @@ -1,40 +0,0 @@ -# databricks_ip_access_list Resource - -This resource allows you to create IP Access Lists in Databricks to control access to your workspace by IP. All IPs and CIDR ranges from each enabled list is put together applying type "BLACKLIST" first, then if still allowed type "WHITELIST" is checked. Please see [IP Access List](https://docs.databricks.com/security/network/ip-access-list.html) for full feature documentation. - --> **Note** The total number of IP addresses and CIDR scopes provided across all ACL Lists in a workspace can not exceed 1000. Refer to the docs above for specifics. - -## Example Usage - -```hcl -resource "databricks_ip_access_list" "allowed-list" { - label = "allow_in" - list_type = "ALLOW" - ip_addresses = [ - "1.2.3.0/24", - "1.2.5.0/24" - ] - depends_on = [] -} -``` -## Argument Reference - -The following arguments are supported: - -* `label` - **(Optional)** This is the display name for the given IP ACL List. - -* `list_type` - **(Required)** Can only be "ALLOW" or "BLOCK" - -* `ip_addresses` - **(Required)** This is a field to allow the group to have instance pool create priviliges. - -* `enabled` - **(Optional)** Boolean `true` or `false` indicating whether this list should be active. Defaults to `true` - -## Attribute Reference - -In addition to all arguments above, the following attributes are exported: - -* `list_id` - Canonical unique identifier for the IP Access List. - -## Import - --> **Note** Importing this resource is not currently supported. \ No newline at end of file diff --git a/docs/resources/workspace_conf.md b/docs/resources/workspace_conf.md new file mode 100644 index 0000000000..172f147bc0 --- /dev/null +++ b/docs/resources/workspace_conf.md @@ -0,0 +1,29 @@ +# databricks_workspace_conf Resource + +-> **Note** This resource has evolving API, which may change in future versions of provider. + +Manages workspace configuration for expert usage. Currently, more than one instance of resource can exist in Terraform state, though there's no deterministic behavior, when they manage same property. We strongly recommend to use single `databricks_workspace_conf` per workspace. + +## Example Usage + +Allows specification of custom configuration properties for expert usage: + + * `enableIpAccessLists` - enables the use of [databricks_ip_access_list](ip_accessl_list.md) resources + +```hcl +resource "databricks_workspace_conf" "this" { + custom_config = { + "enableIpAccessLists": true + } +} +``` + +## Argument Reference + +The following arguments are available: + +* `custom_config` - (Required) Key-value map of strings, that represent workspace configuration. Upon resource deletion, properties that start with `enable` or `enforce` will be reset to `false` value, regardless of initial default one. + +## Import + +This resource cannot support import. \ No newline at end of file diff --git a/internal/qa/testing.go b/internal/qa/testing.go index 1b0a6b5e8d..e82a21f1df 100644 --- a/internal/qa/testing.go +++ b/internal/qa/testing.go @@ -63,9 +63,10 @@ type HTTPFixture struct { // ResourceFixture helps testing resources and commands type ResourceFixture struct { - Fixtures []HTTPFixture - Resource *schema.Resource - State map[string]interface{} + Fixtures []HTTPFixture + Resource *schema.Resource + InstanceState map[string]string + State map[string]interface{} // HCL might be useful to test nested blocks HCL string CommandMock common.CommandMock @@ -167,7 +168,20 @@ func (f ResourceFixture) Apply(t *testing.T) (*schema.ResourceData, error) { strings.ReplaceAll(diagsToString(diags), "\"", "")) } } - resourceData := schema.TestResourceDataRaw(t, f.Resource.Schema, f.State) + c := terraform.NewResourceConfigRaw(f.State) + sm := schema.InternalMap(f.Resource.Schema) + is := &terraform.InstanceState{ + Attributes: f.InstanceState, + } + diff, err := sm.Diff(context.Background(), is, c, nil, nil, true) + if err != nil { + return nil, err + } + resourceData, err := sm.Data(is, diff) + if err != nil { + return nil, err + } + //resourceData := schema.TestResourceDataRaw(t, f.Resource.Schema, f.State) err = f.Resource.InternalValidate(f.Resource.Schema, !f.NonWritable) if err != nil { return nil, err diff --git a/workspace/acceptance/workspace_conf_test.go b/workspace/acceptance/workspace_conf_test.go index b619a555cd..aba7b13688 100644 --- a/workspace/acceptance/workspace_conf_test.go +++ b/workspace/acceptance/workspace_conf_test.go @@ -10,29 +10,29 @@ import ( "github.com/stretchr/testify/assert" ) -func TestWorkspaceConfFullLifecycle(t *testing.T) { +func TestAccWorkspaceConfFullLifecycle(t *testing.T) { acceptance.AccTest(t, resource.TestCase{ - Steps: []resource.TestStep{ { Config: ` - resource "databricks_workspace_conf" "features" { - enable_ip_access_lists = "true" - } - `, + resource "databricks_workspace_conf" "this" { + custom_config = { + "enableIpAccessLists": true + } + }`, Check: resource.ComposeTestCheckFunc( - acceptance.ResourceCheck("databricks_workspace_conf.features", + acceptance.ResourceCheck("databricks_workspace_conf.this", func(client *common.DatabricksClient, id string) error { - workspaceConf, err := workspace.NewWorkspaceConfAPI(client).Read("enableIpAccessLists") - if err != nil { - return err + conf := map[string]interface{}{ + "enableIpAccessLists": nil, } - assert.Len(t, workspaceConf, 1) - assert.Equal(t, workspaceConf["enableIpAccessLists"], "true") + err := workspace.NewWorkspaceConfAPI(client).Read(&conf) + assert.NoError(t, err) + assert.Len(t, conf, 1) + assert.Equal(t, conf["enableIpAccessLists"], "true") return nil }), ), - ExpectNonEmptyPlan: true, }, }, }) diff --git a/workspace/resource_databricks_workspace_conf.go b/workspace/resource_databricks_workspace_conf.go deleted file mode 100644 index 2b27cdbe5c..0000000000 --- a/workspace/resource_databricks_workspace_conf.go +++ /dev/null @@ -1,83 +0,0 @@ -package workspace - -// Preview feature: https://docs.databricks.com/security/network/ip-access-list.html -// REST API: https://docs.databricks.com/dev-tools/api/latest/ip-access-list.html#operation/create-list - -import ( - "strconv" - - "github.com/databrickslabs/databricks-terraform/common" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func ResourceWorkspaceConf() *schema.Resource { - return &schema.Resource{ - Create: resourceWorkspaceConfCreateOrUpdate, - Read: resourceWorkspaceConfRead, - Update: resourceWorkspaceConfCreateOrUpdate, - Delete: resourceWorkspaceConfDelete, - - Schema: map[string]*schema.Schema{ - "enable_ip_access_lists": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - }, - } -} - -var ( - // Keeping the model simple (non-existent) with the client operating on map[string]string - // This is a map from tf name to json name - tfNameToJsonName = map[string]string{ - "enable_ip_access_lists": "enableIpAccessLists", - } -) - -func resourceWorkspaceConfCreateOrUpdate(d *schema.ResourceData, m interface{}) error { - wsConfMap := map[string]string{ - tfNameToJsonName["enable_ip_access_lists"]: strconv.FormatBool(d.Get("enable_ip_access_lists").(bool)), // fmt.sprintf TODO - } - err := NewWorkspaceConfAPI(m).Update(wsConfMap) - // 404 check not needed as this only return 400, 401, and 500 on error - if err != nil { - return err - } - - d.SetId("workspace_configs") // Setting to a single id--expected only one config object - - return resourceWorkspaceConfRead(d, m) -} - -func resourceWorkspaceConfRead(d *schema.ResourceData, m interface{}) (err error) { - resp, err := NewWorkspaceConfAPI(m).Read(tfNameToJsonName["enable_ip_access_lists"]) - // 404 check not required as the service only return 400 errors - if e, ok := err.(common.APIError); ok && e.IsMissing() { - d.SetId("") - return nil - } - if err != nil { - // check 404 (missing) and set id to empty string for tf - return - } - - val, e2 := strconv.ParseBool(resp[tfNameToJsonName["enable_ip_access_lists"]]) - if e2 != nil { - val = false - } - err = d.Set("enable_ip_access_lists", val) - if err != nil { - return - } - - return -} - -func resourceWorkspaceConfDelete(d *schema.ResourceData, m interface{}) (_ error) { - // For IP Access Lists, you can't set to null or "" once it is set. Only true/false allowed - wsConfMap := map[string]string{ - tfNameToJsonName["enable_ip_access_lists"]: "false", - } - return NewWorkspaceConfAPI(m).Update(wsConfMap) -} diff --git a/workspace/resource_workspace_conf.go b/workspace/resource_workspace_conf.go new file mode 100644 index 0000000000..93bbc85d60 --- /dev/null +++ b/workspace/resource_workspace_conf.go @@ -0,0 +1,123 @@ +package workspace + +// Preview feature: https://docs.databricks.com/security/network/ip-access-list.html +// REST API: https://docs.databricks.com/dev-tools/api/latest/ip-access-list.html#operation/create-list + +import ( + "context" + "log" + "strings" + + "github.com/databrickslabs/databricks-terraform/common" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// WorkspaceConfAPI exposes the workspace configurations API +type WorkspaceConfAPI struct { + client *common.DatabricksClient +} + +// NewWorkspaceConfAPI returns workspace conf API +func NewWorkspaceConfAPI(m interface{}) WorkspaceConfAPI { + return WorkspaceConfAPI{client: m.(*common.DatabricksClient)} +} + +// Update will handle creation of new values as well as deletes. Deleting just implies that a value of "" or +// the appropriate disable string like "false" is sent with the appropriate key +func (a WorkspaceConfAPI) Update(workspaceConfMap map[string]interface{}) error { + return a.client.Patch("/workspace-conf", workspaceConfMap) +} + +// Read just returns back a map of keys and values which keys are the configuration items and values are the settings +func (a WorkspaceConfAPI) Read(conf *map[string]interface{}) error { + keys := []string{} + for k := range *conf { + keys = append(keys, k) + } + return a.client.Get("/workspace-conf", map[string]string{ + "keys": strings.Join(keys, ","), + }, &conf) +} + +// ResourceWorkspaceConf maintains workspace configuration for specified keys +func ResourceWorkspaceConf() *schema.Resource { + readContext := func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + wsConfAPI := NewWorkspaceConfAPI(m) + config := d.Get("custom_config").(map[string]interface{}) + log.Printf("[DEBUG] Config available in state: %v", config) + err := wsConfAPI.Read(&config) + if err != nil { + return diag.FromErr(err) + } + log.Printf("[DEBUG] Setting new config to state: %v", config) + // nolint + d.Set("custom_config", config) + return nil + } + + updateContext := func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + wsConfAPI := NewWorkspaceConfAPI(m) + o, n := d.GetChange("custom_config") + old, okOld := o.(map[string]interface{}) + new, okNew := n.(map[string]interface{}) + if !okNew || !okOld { + return diag.Errorf("Internal type casting error") + } + log.Printf("[DEBUG] Old worspace config: %v, new: %v", old, new) + patch := map[string]interface{}{} + for k, v := range new { + patch[k] = v + } + for k := range old { + _, keep := new[k] + if keep { + continue + } + log.Printf("[DEBUG] Erasing configuration of %s", k) + if strings.HasPrefix(k, "enable") || + strings.HasPrefix(k, "enforce") || + strings.HasSuffix(k, "Enabled") { + patch[k] = "false" + } else { + patch[k] = "" + } + } + err := wsConfAPI.Update(patch) + if err != nil { + return diag.FromErr(err) + } + d.SetId("_") + return readContext(ctx, d, m) + } + + return &schema.Resource{ + ReadContext: readContext, + CreateContext: updateContext, + UpdateContext: updateContext, + DeleteContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + config := d.Get("custom_config").(map[string]interface{}) + for k := range config { + if strings.HasPrefix(k, "enable") || + strings.HasPrefix(k, "enforce") || + strings.HasSuffix(k, "Enabled") { + config[k] = "false" + } else { + config[k] = "" + } + } + wsConfAPI := NewWorkspaceConfAPI(m) + err := wsConfAPI.Update(config) + if err != nil { + return diag.FromErr(err) + } + return nil + }, + Schema: map[string]*schema.Schema{ + "custom_config": { + Type: schema.TypeMap, + Optional: true, + }, + }, + } +} diff --git a/workspace/resource_databricks_workspace_conf_test.go b/workspace/resource_workspace_conf_test.go similarity index 60% rename from workspace/resource_databricks_workspace_conf_test.go rename to workspace/resource_workspace_conf_test.go index 72e969f1bc..a4482f6618 100644 --- a/workspace/resource_databricks_workspace_conf_test.go +++ b/workspace/resource_workspace_conf_test.go @@ -1,8 +1,5 @@ package workspace -// Preview feature: https://docs.databricks.com/security/network/ip-access-list.html -// REST API: https://docs.databricks.com/dev-tools/api/latest/ip-access-list.html#operation/create-list - import ( "net/http" "testing" @@ -16,41 +13,34 @@ func TestWorkspaceConfCreate(t *testing.T) { d, err := qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ { - Method: http.MethodGet, - Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", - Response: map[string]string{ + Method: http.MethodPatch, + Resource: "/api/2.0/workspace-conf", + ExpectedRequest: map[string]string{ "enableIpAccessLists": "true", }, }, { - Method: http.MethodPatch, - Resource: "/api/2.0/workspace-conf", - ExpectedRequest: map[string]string{ + Method: http.MethodGet, + Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", + Response: map[string]interface{}{ "enableIpAccessLists": "true", }, }, }, Resource: ResourceWorkspaceConf(), - State: map[string]interface{}{ - "enable_ip_access_lists": "true", - }, + HCL: `custom_config { + enableIpAccessLists = "true" + }`, Create: true, }.Apply(t) assert.NoError(t, err, err) - assert.Equal(t, "workspace_configs", d.Id()) - assert.Equal(t, true, d.Get("enable_ip_access_lists")) + assert.Equal(t, "_", d.Id()) + assert.Equal(t, "true", d.Get("custom_config.enableIpAccessLists")) } func TestWorkspaceConfCreate_Error(t *testing.T) { d, err := qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ - { - Method: http.MethodGet, - Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", - Response: map[string]string{ - "enableIpAccessLists": "true", - }, - }, { Method: http.MethodPatch, Resource: "/api/2.0/workspace-conf", @@ -65,9 +55,9 @@ func TestWorkspaceConfCreate_Error(t *testing.T) { }, }, Resource: ResourceWorkspaceConf(), - State: map[string]interface{}{ - "enable_ip_access_lists": "true", - }, + HCL: `custom_config { + enableIpAccessLists = "true" + }`, Create: true, }.Apply(t) qa.AssertErrorStartsWith(t, err, "Internal error happened") @@ -78,42 +68,41 @@ func TestWorkspaceConfUpdate(t *testing.T) { d, err := qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ { - Method: http.MethodGet, - Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", - Response: map[string]string{ + Method: http.MethodPatch, + Resource: "/api/2.0/workspace-conf", + ExpectedRequest: map[string]string{ "enableIpAccessLists": "true", + "enableSomething": "false", + "someProperty": "", }, }, { - Method: http.MethodPatch, - Resource: "/api/2.0/workspace-conf", - ExpectedRequest: map[string]string{ + Method: http.MethodGet, + Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", + Response: map[string]string{ "enableIpAccessLists": "true", }, }, }, Resource: ResourceWorkspaceConf(), - State: map[string]interface{}{ - "enable_ip_access_lists": "true", + InstanceState: map[string]string{ + "custom_config.enableSomething": "true", + "custom_config.someProperty": "thing", }, + HCL: `custom_config { + enableIpAccessLists = "true" + }`, Update: true, - ID: "workspace_configs", + ID: "_", }.Apply(t) assert.NoError(t, err, err) - assert.Equal(t, "workspace_configs", d.Id()) - assert.Equal(t, true, d.Get("enable_ip_access_lists")) + assert.Equal(t, "_", d.Id()) + assert.Equal(t, "true", d.Get("custom_config.enableIpAccessLists")) } func TestWorkspaceConfUpdate_Error(t *testing.T) { _, err := qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ - { - Method: http.MethodGet, - Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", - Response: map[string]string{ - "enableIpAccessLists": "true", - }, - }, { Method: http.MethodPatch, Resource: "/api/2.0/workspace-conf", @@ -128,53 +117,29 @@ func TestWorkspaceConfUpdate_Error(t *testing.T) { }, }, Resource: ResourceWorkspaceConf(), - State: map[string]interface{}{ - "enable_ip_access_lists": "true", - }, + HCL: `custom_config { + enableIpAccessLists = "true" + }`, Update: true, - ID: "workspace_configs", + ID: "_", }.Apply(t) qa.AssertErrorStartsWith(t, err, "Internal error happened") } func TestWorkspaceConfRead(t *testing.T) { - d, err := qa.ResourceFixture{ - Fixtures: []qa.HTTPFixture{ - { - Method: http.MethodGet, - Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", - Response: map[string]string{ - "enableIpAccessLists": "true", - }, - }, - }, - Resource: ResourceWorkspaceConf(), - Read: true, - ID: "workspace_configs", - }.Apply(t) - assert.NoError(t, err, err) - assert.Equal(t, true, d.Get("enable_ip_access_lists")) -} - -func TestWorkspaceConfRead_NotFound(t *testing.T) { - d, err := qa.ResourceFixture{ + _, err := qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ { Method: http.MethodGet, - Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", - Response: common.APIErrorBody{ - ErrorCode: "NOT_FOUND", - Message: "Item not found", - }, - Status: 404, + Resource: "/api/2.0/workspace-conf?", + Response: map[string]string{}, }, }, Resource: ResourceWorkspaceConf(), Read: true, - ID: "workspace_configs", + ID: "_", }.Apply(t) assert.NoError(t, err, err) - assert.Equal(t, "", d.Id(), "Id should be empty for missing resources") } func TestWorkspaceConfRead_Error(t *testing.T) { @@ -182,7 +147,7 @@ func TestWorkspaceConfRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: http.MethodGet, - Resource: "/api/2.0/workspace-conf?keys=enableIpAccessLists", + Resource: "/api/2.0/workspace-conf?", Response: common.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", @@ -192,34 +157,41 @@ func TestWorkspaceConfRead_Error(t *testing.T) { }, Resource: ResourceWorkspaceConf(), Read: true, - ID: "workspace_configs", + ID: "_", }.Apply(t) qa.AssertErrorStartsWith(t, err, "Internal error happened") - assert.Equal(t, "workspace_configs", d.Id(), "Id should not be empty for error reads") + assert.Equal(t, "_", d.Id(), "Id should not be empty for error reads") } func TestWorkspaceConfDelete(t *testing.T) { - // interrestingly enough, once you set ip access lists, you cant reset to null--only true/false are valid d, err := qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ { Method: http.MethodPatch, Resource: "/api/2.0/workspace-conf", ExpectedRequest: map[string]string{ - "enableIpAccessLists": "false", + "enableFancyThing": "false", + "enableSomething": "false", + "enforceSomethingElse": "false", + "someProperty": "", }, }, }, + HCL: `custom_config { + enableSomething = "true" + enforceSomethingElse = "true" + enableFancyThing = "false" + someProperty = "thing" + }`, Resource: ResourceWorkspaceConf(), Delete: true, - ID: "workspace_configs", + ID: "_", }.Apply(t) assert.NoError(t, err, err) - assert.Equal(t, "workspace_configs", d.Id()) + assert.Equal(t, "_", d.Id()) } func TestWorkspaceConfDelete_Error(t *testing.T) { - // interrestingly enough, once you set ip access lists, you cant reset to null--only true/false are valid d, err := qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ { @@ -234,8 +206,8 @@ func TestWorkspaceConfDelete_Error(t *testing.T) { }, Resource: ResourceWorkspaceConf(), Delete: true, - ID: "workspace_configs", + ID: "_", }.Apply(t) qa.AssertErrorStartsWith(t, err, "Internal error happened") - assert.Equal(t, "workspace_configs", d.Id()) + assert.Equal(t, "_", d.Id()) } diff --git a/workspace/workspace_configrations.go b/workspace/workspace_configrations.go deleted file mode 100644 index 6453f8bd2d..0000000000 --- a/workspace/workspace_configrations.go +++ /dev/null @@ -1,38 +0,0 @@ -package workspace - -import "github.com/databrickslabs/databricks-terraform/common" - -// WorkspaceConfAPI exposes the workspace configurations API -type WorkspaceConfAPI struct { - Client *common.DatabricksClient -} - -func NewWorkspaceConfAPI(m interface{}) WorkspaceConfAPI { - return WorkspaceConfAPI{Client: m.(*common.DatabricksClient)} -} - -// Update will handle creation of new values as well as deletes. Deleting just implies that a value of "" or -// the appropriate disable string like "false" is sent with the appropriate key -// TODO: map[string]string is the only thing accepted by the API currently. If you send in another type, you get the response -// { -// "error_code": "BAD_REQUEST", -// "message": "Values must be strings" -//} -// This is the case for any key tested. It would be worth finding any internal documentation detailing workspace-conf -func (a WorkspaceConfAPI) Update(workspaceConfMap map[string]string) (err error) { - err = a.Client.Patch("/workspace-conf", workspaceConfMap) - return -} - -// Read just returns back a map of keys and values which keys are the configuration items and values are the settings -func (a WorkspaceConfAPI) Read(keys string) (wsConfResp map[string]string, err error) { - wsConfQuery := struct { - Keys string `json:"keys,omitempty" url:"keys,omitempty"` - }{ - Keys: keys, - } - wsConfResp = map[string]string{} - err = a.Client.Get("/workspace-conf", wsConfQuery, &wsConfResp) - - return -} diff --git a/workspace/workspace_configrations_integration_test.go b/workspace/workspace_configrations_integration_test.go deleted file mode 100644 index d04b13869e..0000000000 --- a/workspace/workspace_configrations_integration_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package workspace - -import ( - "testing" - - "github.com/databrickslabs/databricks-terraform/common" - "github.com/stretchr/testify/assert" -) - -func TestWorkspaceConfiguration(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test in short mode.") - } - - client := common.NewClientFromEnvironment() - - wsConfMap := map[string]string{ - "enableIpAccessLists": "true", - } - err := NewWorkspaceConfAPI(client).Update(wsConfMap) - assert.NoError(t, err, err) - resp, err := NewWorkspaceConfAPI(client).Read("enableIpAccessLists") - t.Log(resp["enableIpAccessLists"]) - assert.NoError(t, err, err) -}