Skip to content

Commit ae63552

Browse files
authored
Refactor databricks_permissions to common.Resource (#1253)
1 parent dac4252 commit ae63552

File tree

5 files changed

+223
-78
lines changed

5 files changed

+223
-78
lines changed

access/resource_ipaccesslist_test.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -313,25 +313,23 @@ func TestIPACLDelete(t *testing.T) {
313313
}
314314

315315
func TestIPACLDelete_Error(t *testing.T) {
316-
d, err := qa.ResourceFixture{
316+
qa.ResourceFixture{
317317
Fixtures: []qa.HTTPFixture{
318318
{
319319
Method: http.MethodDelete,
320320
Resource: "/api/2.0/ip-access-lists/" + TestingID,
321321
Response: common.APIErrorBody{
322-
ErrorCode: "FEATURE_DISABLE",
323-
Message: "IP access list is not available in the pricing tier of this workspace",
322+
ErrorCode: "INVALID_STATE",
323+
Message: "Something went wrong",
324324
},
325-
Status: 404,
325+
Status: 400,
326326
},
327327
},
328328
Resource: ResourceIPAccessList(),
329329
Delete: true,
330+
Removed: true,
330331
ID: TestingID,
331-
}.Apply(t)
332-
assert.Error(t, err)
333-
qa.AssertErrorStartsWith(t, err, "IP access list is not available in ")
334-
assert.Equal(t, TestingID, d.Id())
332+
}.ExpectError(t, "Something went wrong")
335333
}
336334

337335
func TestListIpAccessLists(t *testing.T) {

common/resource.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,14 @@ func (r Resource) ToResource() *schema.Resource {
129129
UpdateContext: update,
130130
DeleteContext: func(ctx context.Context, d *schema.ResourceData,
131131
m interface{}) diag.Diagnostics {
132-
if err := recoverable(r.Delete)(ctx, d, m.(*DatabricksClient)); err != nil {
132+
err := recoverable(r.Delete)(ctx, d, m.(*DatabricksClient))
133+
if IsMissing(err) {
134+
log.Printf("[INFO] %s[id=%s] is removed on backend",
135+
ResourceName.GetOrUnknown(ctx), d.Id())
136+
d.SetId("")
137+
return nil
138+
}
139+
if err != nil {
133140
err = nicerError(ctx, err, "delete")
134141
return diag.FromErr(err)
135142
}

common/resource_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,55 @@ func TestImportingCallsRead(t *testing.T) {
3737
assert.Equal(t, 1, d.Get("foo"))
3838
}
3939

40+
func TestHTTP404TriggersResourceRemovalForReadAndDelete(t *testing.T) {
41+
nope := func(ctx context.Context,
42+
d *schema.ResourceData,
43+
c *DatabricksClient) error {
44+
return NotFound("nope")
45+
}
46+
r := Resource{
47+
Create: nope,
48+
Read: nope,
49+
Update: nope,
50+
Delete: nope,
51+
Schema: map[string]*schema.Schema{
52+
"foo": {
53+
Type: schema.TypeInt,
54+
Required: true,
55+
},
56+
},
57+
}.ToResource()
58+
59+
client := &DatabricksClient{}
60+
ctx := context.Background()
61+
d := r.TestResourceData()
62+
63+
// Create propagates 404 error
64+
diags := r.CreateContext(ctx, d, client)
65+
assert.True(t, diags.HasError())
66+
assert.Equal(t, "nope", diags[0].Summary)
67+
68+
// Read removes the resource and swallows 404 error (clears ID)
69+
d.SetId("a")
70+
diags = r.ReadContext(ctx, d, client)
71+
assert.False(t, diags.HasError())
72+
assert.Equal(t, "", d.Id())
73+
74+
// Update propagates 404 error (keeps ID)
75+
d.SetId("b")
76+
diags = r.UpdateContext(ctx, d, client)
77+
assert.True(t, diags.HasError())
78+
assert.Equal(t, "nope", diags[0].Summary)
79+
assert.Equal(t, "b", d.Id())
80+
81+
// Delete removes the resource and swallows 404 error
82+
// if it was removed on backend (clears ID)
83+
d.SetId("c")
84+
diags = r.DeleteContext(ctx, d, client)
85+
assert.False(t, diags.HasError())
86+
assert.Equal(t, "", d.Id())
87+
}
88+
4089
func TestUpdate(t *testing.T) {
4190
r := Resource{
4291
Update: func(ctx context.Context,
@@ -49,6 +98,11 @@ func TestUpdate(t *testing.T) {
4998
c *DatabricksClient) error {
5099
return NotFound("nope")
51100
},
101+
Delete: func(ctx context.Context,
102+
d *schema.ResourceData,
103+
c *DatabricksClient) error {
104+
return NotFound("nope")
105+
},
52106
Schema: map[string]*schema.Schema{
53107
"foo": {
54108
Type: schema.TypeInt,

permissions/resource_permissions.go

Lines changed: 36 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ func (a PermissionsAPI) Read(objectID string) (objectACL ObjectACL, err error) {
208208
// platform propagates INVALID_STATE error for auto-purged clusters in
209209
// the permissions api. this adds "a logical fix" also here, not to introduce
210210
// cross-package dependency on "clusters".
211-
if ok && strings.Contains(apiErr.Message, "Cannot access cluster") {
211+
if ok && strings.Contains(apiErr.Message, "Cannot access cluster") && apiErr.StatusCode == 400 {
212212
apiErr.StatusCode = 404
213213
err = apiErr
214214
return
@@ -292,11 +292,7 @@ func (oa *ObjectACL) ToPermissionsEntity(d *schema.ResourceData, me string) (Per
292292
return entity, nil
293293
}
294294
identifier := path.Base(oa.ObjectID)
295-
err := d.Set(mapping.field, identifier)
296-
if err != nil {
297-
return entity, err
298-
}
299-
return entity, nil
295+
return entity, d.Set(mapping.field, identifier)
300296
}
301297
return entity, fmt.Errorf("unknown object type %s", oa.ObjectType)
302298
}
@@ -346,37 +342,7 @@ func ResourcePermissions() *schema.Resource {
346342
}
347343
return s
348344
})
349-
readContext := func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
350-
id := d.Id()
351-
objectACL, err := NewPermissionsAPI(ctx, m).Read(id)
352-
if common.IsMissing(err) {
353-
log.Printf("[INFO] %s is removed on backend", d.Id())
354-
d.SetId("")
355-
return nil
356-
}
357-
if err != nil {
358-
return diag.FromErr(err)
359-
}
360-
me, err := scim.NewUsersAPI(ctx, m).Me()
361-
if err != nil {
362-
return diag.FromErr(err)
363-
}
364-
entity, err := objectACL.ToPermissionsEntity(d, me.UserName)
365-
if err != nil {
366-
return diag.FromErr(err)
367-
}
368-
if len(entity.AccessControlList) == 0 {
369-
// empty "modifiable" access control list is the same as resource absence
370-
d.SetId("")
371-
return nil
372-
}
373-
err = common.StructToData(entity, s, d)
374-
if err != nil {
375-
return diag.FromErr(err)
376-
}
377-
return nil
378-
}
379-
return &schema.Resource{
345+
return common.Resource{
380346
Schema: s,
381347
CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, c interface{}) error {
382348
client := c.(*common.DatabricksClient)
@@ -407,53 +373,58 @@ func ResourcePermissions() *schema.Resource {
407373
}
408374
return nil
409375
},
410-
ReadContext: readContext,
411-
CreateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
376+
Read: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
377+
id := d.Id()
378+
objectACL, err := NewPermissionsAPI(ctx, c).Read(id)
379+
if err != nil {
380+
return err
381+
}
382+
me, err := scim.NewUsersAPI(ctx, c).Me()
383+
if err != nil {
384+
return err
385+
}
386+
entity, err := objectACL.ToPermissionsEntity(d, me.UserName)
387+
if err != nil {
388+
return err
389+
}
390+
if len(entity.AccessControlList) == 0 {
391+
// empty "modifiable" access control list is the same as resource absence
392+
d.SetId("")
393+
return nil
394+
}
395+
return common.StructToData(entity, s, d)
396+
},
397+
Create: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
412398
var entity PermissionsEntity
413399
common.DataToStructPointer(d, s, &entity)
414400
for _, mapping := range permissionsResourceIDFields() {
415401
if v, ok := d.GetOk(mapping.field); ok {
416-
id, err := mapping.idRetriever(ctx, m.(*common.DatabricksClient), v.(string))
402+
id, err := mapping.idRetriever(ctx, c, v.(string))
417403
if err != nil {
418-
return diag.FromErr(err)
404+
return err
419405
}
420406
objectID := fmt.Sprintf("/%s/%s", mapping.resourceType, id)
421-
err = NewPermissionsAPI(ctx, m).Update(objectID, AccessControlChangeList{
407+
err = NewPermissionsAPI(ctx, c).Update(objectID, AccessControlChangeList{
422408
AccessControlList: entity.AccessControlList,
423409
})
424410
if err != nil {
425-
return diag.FromErr(err)
411+
return err
426412
}
427413
d.SetId(objectID)
428-
return readContext(ctx, d, m)
414+
return nil
429415
}
430416
}
431-
return diag.Errorf("At least one type of resource identifiers must be set")
417+
return errors.New("At least one type of resource identifiers must be set")
432418
},
433-
UpdateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
419+
Update: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
434420
var entity PermissionsEntity
435421
common.DataToStructPointer(d, s, &entity)
436-
err := NewPermissionsAPI(ctx, m).Update(d.Id(), AccessControlChangeList{
422+
return NewPermissionsAPI(ctx, c).Update(d.Id(), AccessControlChangeList{
437423
AccessControlList: entity.AccessControlList,
438424
})
439-
if err != nil {
440-
return diag.FromErr(err)
441-
}
442-
return readContext(ctx, d, m)
443425
},
444-
DeleteContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
445-
err := NewPermissionsAPI(ctx, m).Delete(d.Id())
446-
if common.IsMissing(err) {
447-
log.Printf("[INFO] %s is already removed on backend", d.Id())
448-
return nil
449-
}
450-
if err != nil {
451-
return diag.FromErr(err)
452-
}
453-
return nil
426+
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
427+
return NewPermissionsAPI(ctx, c).Delete(d.Id())
454428
},
455-
Importer: &schema.ResourceImporter{
456-
StateContext: schema.ImportStatePassthroughContext,
457-
},
458-
}
429+
}.ToResource()
459430
}

0 commit comments

Comments
 (0)