Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Resource Private State Management #433

Merged
merged 28 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8577ca7
Add privatestate pkg and Data type (#399)
bendbennett Aug 1, 2022
d642544
Fixing map merging and tests. Adding doc (#399)
bendbennett Aug 2, 2022
ca016ec
Amend diagnostic messages and add logging (#399)
bendbennett Aug 2, 2022
129c3c7
Setting up private data for use in ReadResource RPC (#399)
bendbennett Aug 2, 2022
d708e6b
Refactoring and fixing tests (#399)
bendbennett Aug 3, 2022
4f0e917
Call privatestate.NewData directly from fromproto5/6 (#399)
bendbennett Aug 3, 2022
b449d82
Adding tests for proto5/6server private (#399)
bendbennett Aug 3, 2022
007f352
Additional tests for privatestate.NewData (#399)
bendbennett Aug 3, 2022
48e978f
Additional tests for privatestate (#399)
bendbennett Aug 3, 2022
0d591b9
Calling Data.Bytes directly from toproto5/6/readresource (#399)
bendbennett Aug 3, 2022
a551fce
Adding test coverage to verify SetKey behaviour (#399)
bendbennett Aug 3, 2022
39de02f
Adding test coverage for fwserver readresource behaviour (#399)
bendbennett Aug 3, 2022
f07b8ed
Apply suggestions from code review
bendbennett Aug 4, 2022
e541dde
Adding test coverage for proto5/6server readresource behaviour (#399)
bendbennett Aug 4, 2022
d33ea84
Update resource/read.go
bendbennett Aug 4, 2022
650f26d
Configuring private state data for use with create, update and delete…
bendbennett Aug 4, 2022
d39330a
Refactoring Data to use a pointer to a ProviderData struct which hold…
bendbennett Aug 5, 2022
6622cb5
Expanding test coverage around privatestate.Data (#399)
bendbennett Aug 8, 2022
6d96f3c
Ensuring that all instances of privatestate.Provider data that passed…
bendbennett Aug 8, 2022
cbc8aa7
Fixing tests following rebase (#399)
bendbennett Aug 8, 2022
1e187b8
Implementing private state management for import resource state (#399)
bendbennett Aug 8, 2022
91cf4cb
Implementing private state management for ModifyAttribute and ModifyR…
bendbennett Aug 9, 2022
d1a8f94
Apply suggestions from code review
bendbennett Aug 10, 2022
61bf980
Updating following code review (#399)
bendbennett Aug 10, 2022
822ccaa
Apply suggestions from code review
bendbennett Aug 10, 2022
4b07ba7
Updating following code review (#399)
bendbennett Aug 10, 2022
b7343f4
Refactoring to use EmptyData to avoid Data.Provider from being nil (#…
bendbennett Aug 11, 2022
34731b2
Updating changelog entry (#399)
bendbennett Aug 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/433.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:note
A new internal package has been introduced which enables provider developers to read/write framework-managed private state data.
```
11 changes: 9 additions & 2 deletions internal/fromproto5/applyresourcechange.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package fromproto5
import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
)

// ApplyResourceChangeRequest returns the *fwserver.ApplyResourceChangeRequest
Expand All @@ -34,7 +36,6 @@ func ApplyResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.ApplyReso
}

fw := &fwserver.ApplyResourceChangeRequest{
PlannedPrivate: proto5.PlannedPrivate,
ResourceSchema: resourceSchema,
ResourceType: resourceType,
}
Expand Down Expand Up @@ -63,5 +64,11 @@ func ApplyResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.ApplyReso

fw.ProviderMeta = providerMeta

privateData, privateDataDiags := privatestate.NewData(ctx, proto5.PlannedPrivate)

diags.Append(privateDataDiags...)

fw.PlannedPrivate = privateData

return fw, diags
}
56 changes: 51 additions & 5 deletions internal/fromproto5/applyresourcechange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tftypes"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fromproto5"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

func TestApplyResourceChangeRequest(t *testing.T) {
Expand Down Expand Up @@ -44,6 +46,14 @@ func TestApplyResourceChangeRequest(t *testing.T) {
},
}

testProviderKeyValue := privatestate.MustMarshalToJson(map[string][]byte{
"providerKeyOne": []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`),
})

testProviderData := privatestate.MustProviderData(context.Background(), testProviderKeyValue)

testEmptyProviderData := privatestate.EmptyProviderData(context.Background())

testCases := map[string]struct {
input *tfprotov5.ApplyResourceChangeRequest
resourceSchema fwschema.Schema
Expand Down Expand Up @@ -125,14 +135,50 @@ func TestApplyResourceChangeRequest(t *testing.T) {
ResourceSchema: testFwSchema,
},
},
"plannedprivate": {
"plannedprivate-malformed-json": {
input: &tfprotov5.ApplyResourceChangeRequest{
PlannedPrivate: []byte("{}"),
PlannedPrivate: []byte(`{`),
},
resourceSchema: testFwSchema,
expected: &fwserver.ApplyResourceChangeRequest{
ResourceSchema: testFwSchema,
}, expectedDiagnostics: diag.Diagnostics{
diag.NewErrorDiagnostic(
"Error Decoding Private State",
"An error was encountered when decoding private state: unexpected end of JSON input.\n\n"+
"This is always a problem with Terraform or terraform-plugin-framework. Please report this to the provider developer.",
),
},
},
"plannedprivate-empty-json": {
input: &tfprotov5.ApplyResourceChangeRequest{
PlannedPrivate: []byte("{}"),
},
resourceSchema: testFwSchema,
expected: &fwserver.ApplyResourceChangeRequest{
ResourceSchema: testFwSchema,
PlannedPrivate: &privatestate.Data{
Framework: map[string][]byte{},
Provider: testEmptyProviderData,
},
},
},
"plannedprivate": {
input: &tfprotov5.ApplyResourceChangeRequest{
PlannedPrivate: privatestate.MustMarshalToJson(map[string][]byte{
".frameworkKey": []byte(`{"fKeyOne": {"k0": "zero", "k1": 1}}`),
"providerKeyOne": []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`),
}),
},
resourceSchema: testFwSchema,
expected: &fwserver.ApplyResourceChangeRequest{
ResourceSchema: testFwSchema,
PlannedPrivate: &privatestate.Data{
Framework: map[string][]byte{
".frameworkKey": []byte(`{"fKeyOne": {"k0": "zero", "k1": 1}}`),
},
Provider: testProviderData,
},
},
},
"priorstate-missing-schema": {
Expand Down Expand Up @@ -209,7 +255,7 @@ func TestApplyResourceChangeRequest(t *testing.T) {

got, diags := fromproto5.ApplyResourceChangeRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema)

if diff := cmp.Diff(got, testCase.expected); diff != "" {
if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" {
t.Errorf("unexpected difference: %s", diff)
}

Expand Down
11 changes: 9 additions & 2 deletions internal/fromproto5/planresourcechange.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package fromproto5
import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
)

// PlanResourceChangeRequest returns the *fwserver.PlanResourceChangeRequest
Expand All @@ -34,7 +36,6 @@ func PlanResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.PlanResour
}

fw := &fwserver.PlanResourceChangeRequest{
PriorPrivate: proto5.PriorPrivate,
ResourceSchema: resourceSchema,
ResourceType: resourceType,
}
Expand Down Expand Up @@ -63,5 +64,11 @@ func PlanResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.PlanResour

fw.ProviderMeta = providerMeta

privateData, privateDataDiags := privatestate.NewData(ctx, proto5.PriorPrivate)

diags.Append(privateDataDiags...)

fw.PriorPrivate = privateData

return fw, diags
}
26 changes: 21 additions & 5 deletions internal/fromproto5/planresourcechange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tftypes"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fromproto5"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

func TestPlanResourceChangeRequest(t *testing.T) {
Expand Down Expand Up @@ -44,6 +46,12 @@ func TestPlanResourceChangeRequest(t *testing.T) {
},
}

testProviderKeyValue := privatestate.MustMarshalToJson(map[string][]byte{
"providerKeyOne": []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`),
})

testProviderData := privatestate.MustProviderData(context.Background(), testProviderKeyValue)

testCases := map[string]struct {
input *tfprotov5.PlanResourceChangeRequest
resourceSchema fwschema.Schema
Expand Down Expand Up @@ -99,11 +107,19 @@ func TestPlanResourceChangeRequest(t *testing.T) {
},
"priorprivate": {
input: &tfprotov5.PlanResourceChangeRequest{
PriorPrivate: []byte("{}"),
PriorPrivate: privatestate.MustMarshalToJson(map[string][]byte{
".frameworkKey": []byte(`{"fKeyOne": {"k0": "zero", "k1": 1}}`),
"providerKeyOne": []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`),
}),
},
resourceSchema: testFwSchema,
expected: &fwserver.PlanResourceChangeRequest{
PriorPrivate: []byte("{}"),
PriorPrivate: &privatestate.Data{
Framework: map[string][]byte{
".frameworkKey": []byte(`{"fKeyOne": {"k0": "zero", "k1": 1}}`),
},
Provider: testProviderData,
},
ResourceSchema: testFwSchema,
},
},
Expand Down Expand Up @@ -209,7 +225,7 @@ func TestPlanResourceChangeRequest(t *testing.T) {

got, diags := fromproto5.PlanResourceChangeRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema)

if diff := cmp.Diff(got, testCase.expected); diff != "" {
if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" {
t.Errorf("unexpected difference: %s", diff)
}

Expand Down
11 changes: 9 additions & 2 deletions internal/fromproto5/readresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package fromproto5
import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
)

// ReadResourceRequest returns the *fwserver.ReadResourceRequest
Expand All @@ -20,7 +22,6 @@ func ReadResourceRequest(ctx context.Context, proto5 *tfprotov5.ReadResourceRequ
var diags diag.Diagnostics

fw := &fwserver.ReadResourceRequest{
Private: proto5.Private,
ResourceType: resourceType,
}

Expand All @@ -36,5 +37,11 @@ func ReadResourceRequest(ctx context.Context, proto5 *tfprotov5.ReadResourceRequ

fw.ProviderMeta = providerMeta

privateData, privateDataDiags := privatestate.NewData(ctx, proto5.Private)

diags.Append(privateDataDiags...)

fw.Private = privateData

return fw, diags
}
54 changes: 49 additions & 5 deletions internal/fromproto5/readresource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tftypes"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fromproto5"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

func TestReadResourceRequest(t *testing.T) {
Expand Down Expand Up @@ -44,6 +46,14 @@ func TestReadResourceRequest(t *testing.T) {
},
}

testProviderKeyValue := privatestate.MustMarshalToJson(map[string][]byte{
"providerKeyOne": []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`),
})

testProviderData := privatestate.MustProviderData(context.Background(), testProviderKeyValue)

testEmptyProviderData := privatestate.EmptyProviderData(context.Background())

testCases := map[string]struct {
input *tfprotov5.ReadResourceRequest
resourceSchema fwschema.Schema
Expand Down Expand Up @@ -87,13 +97,47 @@ func TestReadResourceRequest(t *testing.T) {
},
},
},
"private": {
"private-malformed-json": {
input: &tfprotov5.ReadResourceRequest{
Private: []byte(`{`),
},
resourceSchema: testFwSchema,
expected: &fwserver.ReadResourceRequest{},
expectedDiagnostics: diag.Diagnostics{
diag.NewErrorDiagnostic(
"Error Decoding Private State",
"An error was encountered when decoding private state: unexpected end of JSON input.\n\n"+
"This is always a problem with Terraform or terraform-plugin-framework. Please report this to the provider developer.",
),
},
},
"private-empty-json": {
input: &tfprotov5.ReadResourceRequest{
Private: []byte("{}"),
},
resourceSchema: testFwSchema,
expected: &fwserver.ReadResourceRequest{
Private: []byte("{}"),
Private: &privatestate.Data{
Framework: map[string][]byte{},
Provider: testEmptyProviderData,
},
},
},
"private": {
input: &tfprotov5.ReadResourceRequest{
Private: privatestate.MustMarshalToJson(map[string][]byte{
".frameworkKey": []byte(`{"fKeyOne": {"k0": "zero", "k1": 1}}`),
"providerKeyOne": []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`),
}),
},
resourceSchema: testFwSchema,
expected: &fwserver.ReadResourceRequest{
Private: &privatestate.Data{
Framework: map[string][]byte{
".frameworkKey": []byte(`{"fKeyOne": {"k0": "zero", "k1": 1}}`),
},
Provider: testProviderData,
},
},
},
"providermeta-missing-data": {
Expand Down Expand Up @@ -136,7 +180,7 @@ func TestReadResourceRequest(t *testing.T) {

got, diags := fromproto5.ReadResourceRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema)

if diff := cmp.Diff(got, testCase.expected); diff != "" {
if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" {
t.Errorf("unexpected difference: %s", diff)
}

Expand Down
11 changes: 9 additions & 2 deletions internal/fromproto6/applyresourcechange.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package fromproto6
import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov6"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
)

// ApplyResourceChangeRequest returns the *fwserver.ApplyResourceChangeRequest
Expand All @@ -34,7 +36,6 @@ func ApplyResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.ApplyReso
}

fw := &fwserver.ApplyResourceChangeRequest{
PlannedPrivate: proto6.PlannedPrivate,
ResourceSchema: resourceSchema,
ResourceType: resourceType,
}
Expand Down Expand Up @@ -63,5 +64,11 @@ func ApplyResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.ApplyReso

fw.ProviderMeta = providerMeta

privateData, privateDataDiags := privatestate.NewData(ctx, proto6.PlannedPrivate)

diags.Append(privateDataDiags...)

fw.PlannedPrivate = privateData

return fw, diags
}
Loading