Skip to content

Commit 17f1faf

Browse files
authored
resource: Add identity to DeleteRequest (#1132)
1 parent ca17ae9 commit 17f1faf

5 files changed

+148
-21
lines changed

internal/fwserver/server_applyresourcechange.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ func (s *Server) ApplyResourceChange(ctx context.Context, req *ApplyResourceChan
7676
deleteReq := &DeleteResourceRequest{
7777
PlannedPrivate: req.PlannedPrivate,
7878
PriorState: req.PriorState,
79+
// MAINTAINER NOTE: There isn't a separate data field for prior identity, like there is with prior_state and planned_state.
80+
// Here the planned_identity field will contain what would be considered the prior identity (since the final identity value
81+
// after deleting will be null).
82+
PriorIdentity: req.PlannedIdentity,
7983
ProviderMeta: req.ProviderMeta,
8084
ResourceSchema: req.ResourceSchema,
8185
IdentitySchema: req.IdentitySchema,

internal/fwserver/server_applyresourcechange_test.go

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ func TestServerApplyResourceChange(t *testing.T) {
6969
Schema: testSchema,
7070
}
7171

72+
testEmptyIdentity := &tfsdk.ResourceIdentity{
73+
Raw: tftypes.NewValue(testIdentityType, nil),
74+
Schema: testIdentitySchema,
75+
}
76+
7277
type testSchemaData struct {
7378
TestComputed types.String `tfsdk:"test_computed"`
7479
TestRequired types.String `tfsdk:"test_required"`
@@ -689,6 +694,52 @@ func TestServerApplyResourceChange(t *testing.T) {
689694
NewState: testEmptyState,
690695
},
691696
},
697+
"delete-request-prioridentity": {
698+
server: &fwserver.Server{
699+
Provider: &testprovider.Provider{},
700+
},
701+
request: &fwserver.ApplyResourceChangeRequest{
702+
PlannedState: testEmptyPlan,
703+
PriorState: &tfsdk.State{
704+
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
705+
"test_computed": tftypes.NewValue(tftypes.String, nil),
706+
"test_required": tftypes.NewValue(tftypes.String, "test-priorstate-value"),
707+
}),
708+
Schema: testSchema,
709+
},
710+
PlannedIdentity: &tfsdk.ResourceIdentity{
711+
Raw: tftypes.NewValue(testIdentityType, map[string]tftypes.Value{
712+
"test_id": tftypes.NewValue(tftypes.String, "id-123"),
713+
}),
714+
Schema: testIdentitySchema,
715+
},
716+
IdentitySchema: testIdentitySchema,
717+
ResourceSchema: testSchema,
718+
Resource: &testprovider.ResourceWithIdentity{
719+
Resource: &testprovider.Resource{
720+
CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) {
721+
resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create")
722+
},
723+
DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
724+
var identityData testIdentitySchemaData
725+
726+
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
727+
728+
if identityData.TestID.ValueString() != "id-123" {
729+
resp.Diagnostics.AddError("Unexpected req.Identity Value", "Got: "+identityData.TestID.ValueString())
730+
}
731+
},
732+
UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) {
733+
resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update")
734+
},
735+
},
736+
},
737+
},
738+
expectedResponse: &fwserver.ApplyResourceChangeResponse{
739+
NewIdentity: testEmptyIdentity,
740+
NewState: testEmptyState,
741+
},
742+
},
692743
"delete-request-providermeta": {
693744
server: &fwserver.Server{
694745
Provider: &testprovider.Provider{},
@@ -982,6 +1033,12 @@ func TestServerApplyResourceChange(t *testing.T) {
9821033
}),
9831034
Schema: testSchema,
9841035
},
1036+
PlannedIdentity: &tfsdk.ResourceIdentity{
1037+
Raw: tftypes.NewValue(testIdentityType, map[string]tftypes.Value{
1038+
"test_id": tftypes.NewValue(tftypes.String, "id-123"),
1039+
}),
1040+
Schema: testIdentitySchema,
1041+
},
9851042
IdentitySchema: testIdentitySchema,
9861043
ResourceSchema: testSchema,
9871044
Resource: &testprovider.ResourceWithIdentity{
@@ -990,10 +1047,11 @@ func TestServerApplyResourceChange(t *testing.T) {
9901047
resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create")
9911048
},
9921049
DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
993-
if resp.Identity == nil || !resp.Identity.Raw.IsNull() {
1050+
// The identity is automatically set to null in the response after the Delete method is called
1051+
if resp.Identity == nil || resp.Identity.Raw.IsNull() {
9941052
resp.Diagnostics.AddError(
9951053
"Unexpected resp.Identity",
996-
"expected resp.Identity to be a null object of the schema type.",
1054+
"expected resp.Identity to be a known non-null object of the schema type.",
9971055
)
9981056
}
9991057
},
@@ -1004,11 +1062,8 @@ func TestServerApplyResourceChange(t *testing.T) {
10041062
},
10051063
},
10061064
expectedResponse: &fwserver.ApplyResourceChangeResponse{
1007-
NewIdentity: &tfsdk.ResourceIdentity{
1008-
Raw: tftypes.NewValue(testIdentityType, nil),
1009-
Schema: testIdentitySchema,
1010-
},
1011-
NewState: testEmptyState,
1065+
NewIdentity: testEmptyIdentity,
1066+
NewState: testEmptyState,
10121067
},
10131068
},
10141069
"update-request-config": {

internal/fwserver/server_deleteresource.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
type DeleteResourceRequest struct {
2222
PlannedPrivate *privatestate.Data
2323
PriorState *tfsdk.State
24+
PriorIdentity *tfsdk.ResourceIdentity
2425
ProviderMeta *tfsdk.Config
2526
ResourceSchema fwschema.Schema
2627
IdentitySchema fwschema.Schema
@@ -98,15 +99,27 @@ func (s *Server) DeleteResource(ctx context.Context, req *DeleteResourceRequest,
9899
resp.Private = req.PlannedPrivate
99100
}
100101

101-
if req.IdentitySchema != nil {
102+
if req.PriorIdentity == nil && req.IdentitySchema != nil {
102103
nullIdentityTfValue := tftypes.NewValue(req.IdentitySchema.Type().TerraformType(ctx), nil)
103104

104-
deleteResp.Identity = &tfsdk.ResourceIdentity{
105+
req.PriorIdentity = &tfsdk.ResourceIdentity{
105106
Schema: req.IdentitySchema,
106107
Raw: nullIdentityTfValue.Copy(),
107108
}
108109
}
109110

111+
if req.PriorIdentity != nil {
112+
deleteReq.Identity = &tfsdk.ResourceIdentity{
113+
Schema: req.PriorIdentity.Schema,
114+
Raw: req.PriorIdentity.Raw.Copy(),
115+
}
116+
117+
deleteResp.Identity = &tfsdk.ResourceIdentity{
118+
Schema: req.PriorIdentity.Schema,
119+
Raw: req.PriorIdentity.Raw.Copy(),
120+
}
121+
}
122+
110123
logging.FrameworkTrace(ctx, "Calling provider defined Resource Delete")
111124
req.Resource.Delete(ctx, deleteReq, &deleteResp)
112125
logging.FrameworkTrace(ctx, "Called provider defined Resource Delete")

internal/fwserver/server_deleteresource_test.go

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ func TestServerDeleteResource(t *testing.T) {
6464
Schema: testSchema,
6565
}
6666

67+
testEmptyIdentity := &tfsdk.ResourceIdentity{
68+
Raw: tftypes.NewValue(testIdentityType, nil),
69+
Schema: testIdentitySchema,
70+
}
71+
6772
type testSchemaData struct {
6873
TestComputed types.String `tfsdk:"test_computed"`
6974
TestRequired types.String `tfsdk:"test_required"`
@@ -163,6 +168,45 @@ func TestServerDeleteResource(t *testing.T) {
163168
NewState: testEmptyState,
164169
},
165170
},
171+
"request-prioridentity": {
172+
server: &fwserver.Server{
173+
Provider: &testprovider.Provider{},
174+
},
175+
request: &fwserver.DeleteResourceRequest{
176+
PriorState: &tfsdk.State{
177+
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
178+
"test_computed": tftypes.NewValue(tftypes.String, nil),
179+
"test_required": tftypes.NewValue(tftypes.String, "test-priorstate-value"),
180+
}),
181+
Schema: testSchema,
182+
},
183+
PriorIdentity: &tfsdk.ResourceIdentity{
184+
Raw: tftypes.NewValue(testIdentityType, map[string]tftypes.Value{
185+
"test_id": tftypes.NewValue(tftypes.String, "id-123"),
186+
}),
187+
Schema: testIdentitySchema,
188+
},
189+
IdentitySchema: testIdentitySchema,
190+
ResourceSchema: testSchema,
191+
Resource: &testprovider.ResourceWithIdentity{
192+
Resource: &testprovider.Resource{
193+
DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
194+
var identityData testIdentitySchemaData
195+
196+
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
197+
198+
if identityData.TestID.ValueString() != "id-123" {
199+
resp.Diagnostics.AddError("Unexpected req.Identity Value", "Got: "+identityData.TestID.ValueString())
200+
}
201+
},
202+
},
203+
},
204+
},
205+
expectedResponse: &fwserver.DeleteResourceResponse{
206+
NewState: testEmptyState,
207+
NewIdentity: testEmptyIdentity,
208+
},
209+
},
166210
"request-providermeta": {
167211
server: &fwserver.Server{
168212
Provider: &testprovider.Provider{},
@@ -365,25 +409,29 @@ func TestServerDeleteResource(t *testing.T) {
365409
}),
366410
Schema: testSchema,
367411
},
412+
PriorIdentity: &tfsdk.ResourceIdentity{
413+
Raw: tftypes.NewValue(testIdentityType, map[string]tftypes.Value{
414+
"test_id": tftypes.NewValue(tftypes.String, "id-123"),
415+
}),
416+
Schema: testIdentitySchema,
417+
},
368418
IdentitySchema: testIdentitySchema,
369419
ResourceSchema: testSchema,
370420
Resource: &testprovider.Resource{
371421
DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
372-
if resp.Identity == nil || !resp.Identity.Raw.IsNull() {
422+
// The identity is automatically set to null in the response after the Delete method is called
423+
if resp.Identity == nil || resp.Identity.Raw.IsNull() {
373424
resp.Diagnostics.AddError(
374425
"Unexpected resp.Identity",
375-
"expected resp.Identity to be a null object of the schema type.",
426+
"expected resp.Identity to be a known non-null object of the schema type.",
376427
)
377428
}
378429
},
379430
},
380431
},
381432
expectedResponse: &fwserver.DeleteResourceResponse{
382-
NewIdentity: &tfsdk.ResourceIdentity{
383-
Raw: tftypes.NewValue(testIdentityType, nil),
384-
Schema: testIdentitySchema,
385-
},
386-
NewState: testEmptyState,
433+
NewIdentity: testEmptyIdentity,
434+
NewState: testEmptyState,
387435
},
388436
},
389437
"response-newidentity-set-to-null": {
@@ -398,6 +446,12 @@ func TestServerDeleteResource(t *testing.T) {
398446
}),
399447
Schema: testSchema,
400448
},
449+
PriorIdentity: &tfsdk.ResourceIdentity{
450+
Raw: tftypes.NewValue(testIdentityType, map[string]tftypes.Value{
451+
"test_id": tftypes.NewValue(tftypes.String, "id-123"),
452+
}),
453+
Schema: testIdentitySchema,
454+
},
401455
IdentitySchema: testIdentitySchema,
402456
ResourceSchema: testSchema,
403457
Resource: &testprovider.Resource{
@@ -410,11 +464,8 @@ func TestServerDeleteResource(t *testing.T) {
410464
},
411465
},
412466
expectedResponse: &fwserver.DeleteResourceResponse{
413-
NewIdentity: &tfsdk.ResourceIdentity{
414-
Raw: tftypes.NewValue(testIdentityType, nil),
415-
Schema: testIdentitySchema,
416-
},
417-
NewState: testEmptyState,
467+
NewIdentity: testEmptyIdentity,
468+
NewState: testEmptyState,
418469
},
419470
},
420471
"response-invalid-newidentity": {

resource/delete.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ type DeleteRequest struct {
1717
// operation.
1818
State tfsdk.State
1919

20+
// Identity is the current identity of the resource prior to the Delete
21+
// operation. If the resource does not support identity, this value will not be set.
22+
Identity *tfsdk.ResourceIdentity
23+
2024
// ProviderMeta is metadata from the provider_meta block of the module.
2125
ProviderMeta tfsdk.Config
2226

0 commit comments

Comments
 (0)