Skip to content

Commit 51addf3

Browse files
authored
Adding new experimental resources (#1021)
Added `databricks_external_location` resource
1 parent d0940ab commit 51addf3

File tree

8 files changed

+211
-2
lines changed

8 files changed

+211
-2
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package catalog
2+
3+
import (
4+
"context"
5+
"net/url"
6+
7+
"github.com/databrickslabs/terraform-provider-databricks/common"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
)
10+
11+
type ExternalLocationsAPI struct {
12+
client *common.DatabricksClient
13+
context context.Context
14+
}
15+
16+
func NewExternalLocationsAPI(ctx context.Context, m interface{}) ExternalLocationsAPI {
17+
return ExternalLocationsAPI{m.(*common.DatabricksClient), ctx}
18+
}
19+
20+
type ExternalLocationInfo struct {
21+
Name string `json:"name" tf:"force_new"`
22+
URL string `json:"url"`
23+
CredentialName string `json:"credential_name"`
24+
Comment string `json:"comment,omitempty"`
25+
Owner string `json:"owner,omitempty" tf:"computed"`
26+
MetastoreID string `json:"metastore_id,omitempty" tf:"computed"`
27+
}
28+
29+
func (a ExternalLocationsAPI) create(el *ExternalLocationInfo) error {
30+
return a.client.Post(a.context, "/unity-catalog/external-locations", el, &el)
31+
}
32+
33+
func (a ExternalLocationsAPI) get(name string) (el ExternalLocationInfo, err error) {
34+
err = a.client.Get(a.context, "/unity-catalog/external-locations/"+url.PathEscape(name), nil, &el)
35+
return
36+
}
37+
38+
func (a ExternalLocationsAPI) update(name string, el ExternalLocationInfo) error {
39+
return a.client.Patch(a.context, "/unity-catalog/external-locations/"+url.PathEscape(name), el)
40+
}
41+
42+
func (a ExternalLocationsAPI) delete(name string) error {
43+
return a.client.Delete(a.context, "/unity-catalog/external-locations/"+url.PathEscape(name), nil)
44+
}
45+
46+
func ResourceExternalLocation() *schema.Resource {
47+
s := common.StructToSchema(ExternalLocationInfo{},
48+
func(m map[string]*schema.Schema) map[string]*schema.Schema {
49+
return m
50+
})
51+
return common.Resource{
52+
Schema: s,
53+
Create: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
54+
var el ExternalLocationInfo
55+
common.DataToStructPointer(d, s, &el)
56+
err := NewExternalLocationsAPI(ctx, c).create(&el)
57+
if err != nil {
58+
return err
59+
}
60+
d.SetId(el.Name)
61+
return nil
62+
},
63+
Read: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
64+
el, err := NewExternalLocationsAPI(ctx, c).get(d.Id())
65+
if err != nil {
66+
return err
67+
}
68+
return common.StructToData(el, s, d)
69+
},
70+
Update: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
71+
var el ExternalLocationInfo
72+
common.DataToStructPointer(d, s, &el)
73+
return NewExternalLocationsAPI(ctx, c).update(d.Id(), ExternalLocationInfo{
74+
Name: d.Id(),
75+
URL: el.URL,
76+
CredentialName: el.CredentialName,
77+
Comment: el.Comment,
78+
Owner: el.Owner,
79+
})
80+
},
81+
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
82+
return NewExternalLocationsAPI(ctx, c).delete(d.Id())
83+
},
84+
}.ToResource()
85+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package catalog
2+
3+
import (
4+
"testing"
5+
6+
"github.com/databrickslabs/terraform-provider-databricks/qa"
7+
)
8+
9+
func TestExternalLocationCornerCases(t *testing.T) {
10+
qa.ResourceCornerCases(t, ResourceExternalLocation())
11+
}
12+
13+
func TestCreateExternalLocation(t *testing.T) {
14+
qa.ResourceFixture{
15+
Fixtures: []qa.HTTPFixture{
16+
{
17+
Method: "POST",
18+
Resource: "/api/2.0/unity-catalog/external-locations",
19+
ExpectedRequest: ExternalLocationInfo{
20+
Name: "abc",
21+
URL: "s3://foo/bar",
22+
CredentialName: "bcd",
23+
Comment: "def",
24+
},
25+
},
26+
{
27+
Method: "GET",
28+
Resource: "/api/2.0/unity-catalog/external-locations/abc",
29+
Response: ExternalLocationInfo {
30+
Owner: "efg",
31+
MetastoreID: "fgh",
32+
},
33+
},
34+
},
35+
Resource: ResourceExternalLocation(),
36+
Create: true,
37+
HCL: `
38+
name = "abc"
39+
url = "s3://foo/bar"
40+
credential_name = "bcd"
41+
comment = "def"
42+
`,
43+
}.ApplyNoError(t)
44+
}

catalog/resource_grants.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,18 @@ var mapping = securableMapping{
129129
"USAGE": true,
130130
"ALL PRIVILEGES": true,
131131
},
132+
"storage_credential": {
133+
"CREATE TABLE": true,
134+
"READ FILES": true,
135+
"WRITE FILES": true,
136+
"ALL PRIVILEGES": true,
137+
},
138+
"external_location": {
139+
"CREATE TABLE": true,
140+
"READ FILES": true,
141+
"WRITE FILES": true,
142+
"ALL PRIVILEGES": true,
143+
},
132144
}
133145

134146
func setToStrings(set *schema.Set) (ss []string) {
@@ -213,6 +225,10 @@ func ResourceGrants() *schema.Resource {
213225
return common.Resource{
214226
Schema: s,
215227
CustomizeDiff: func(ctx context.Context, d *schema.ResourceDiff, c interface{}) error {
228+
if d.Id() == "" {
229+
// unfortunately we cannot do validation before dependent resources exist with tfsdkv2
230+
return nil
231+
}
216232
var grants PermissionsList
217233
common.DiffToStructPointer(d, s, &grants)
218234
return mapping.validate(d, grants)

catalog/resource_grants_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,52 @@ func TestGrantCreate(t *testing.T) {
211211
}.ApplyNoError(t)
212212
}
213213

214+
func TestGrantUpdate(t *testing.T) {
215+
qa.ResourceFixture{
216+
Fixtures: []qa.HTTPFixture{
217+
{
218+
Method: "PATCH",
219+
Resource: "/api/2.0/unity-catalog/permissions/table/foo.bar.baz",
220+
ExpectedRequest: PermissionsDiff{
221+
Changes: []PermissionsChange{
222+
{
223+
Principal: "me",
224+
Add: []string{"MODIFY", "SELECT"},
225+
},
226+
},
227+
},
228+
},
229+
{
230+
Method: "GET",
231+
Resource: "/api/2.0/unity-catalog/permissions/table/foo.bar.baz",
232+
233+
Response: PermissionsList{
234+
Assignments: []PrivilegeAssignment{
235+
{
236+
Principal: "me",
237+
Privileges: []string{"MODIFY", "SELECT"},
238+
},
239+
},
240+
},
241+
},
242+
},
243+
Resource: ResourceGrants(),
244+
Update: true,
245+
ID: "table/foo.bar.baz",
246+
InstanceState: map[string]string{
247+
"table": "foo.bar.baz",
248+
},
249+
HCL: `
250+
table = "foo.bar.baz"
251+
252+
grant {
253+
principal = "me"
254+
privileges = ["MODIFY", "SELECT"]
255+
}
256+
`,
257+
}.ApplyNoError(t)
258+
}
259+
214260
func TestGrantReadMalformedId(t *testing.T) {
215261
qa.ResourceFixture{
216262
Resource: ResourceGrants(),

provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func DatabricksProvider() *schema.Provider {
6060
"databricks_cluster_policy": policies.ResourceClusterPolicy(),
6161
"databricks_dbfs_file": storage.ResourceDBFSFile(),
6262
"databricks_directory": workspace.ResourceDirectory(),
63+
"databricks_external_location": catalog.ResourceExternalLocation(),
6364
"databricks_global_init_script": workspace.ResourceGlobalInitScript(),
6465
"databricks_grants": catalog.ResourceGrants(),
6566
"databricks_group": scim.ResourceGroup(),

qa/testing.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ func (f ResourceFixture) Apply(t *testing.T) (*schema.ResourceData, error) {
224224
return resourceData, fmt.Errorf("resource is not expected to be removed")
225225
}
226226
newState := resourceData.State()
227-
diff, err = schemaMap.Diff(ctx, newState, resourceConfig, nil, client, true)
227+
diff, err = schemaMap.Diff(ctx, newState, resourceConfig, f.Resource.CustomizeDiff, client, true)
228228
if err != nil {
229229
return nil, err
230230
}

scripts/nightly/awsit.tf

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ resource "databricks_mws_storage_configurations" "this" {
9696
storage_configuration_name = "${local.prefix}-cx-terraform-it"
9797
}
9898

99-
output "aws_bucket" {
99+
output "aws_root_bucket" {
100100
value = aws_s3_bucket.root_storage_bucket.bucket
101101
}
102102

@@ -277,4 +277,17 @@ resource "azurerm_container_group" "aws" {
277277
protocol = "TCP"
278278
}
279279
}
280+
}
281+
282+
output "aws_workspace_url" {
283+
value = databricks_mws_workspaces.this.workspace_url
284+
}
285+
286+
output "aws_workspace_id" {
287+
value = databricks_mws_workspaces.this.workspace_id
288+
}
289+
290+
output "aws_workspace_pat" {
291+
value = databricks_mws_workspaces.this.token[0].token_value
292+
sensitive = true
280293
}

scripts/nightly/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ locals {
66
tags = azurerm_resource_group.this.tags
77
}
88

9+
output "prefix" {
10+
value = local.prefix
11+
}
12+
913
output "tags" {
1014
value = local.tags
1115
}

0 commit comments

Comments
 (0)