From 5859dbf8222e1e75a95b0c3a5299a67e938fc6e7 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 12 Aug 2022 12:29:23 -0400 Subject: [PATCH 1/2] internal/privatestate: Handle terraform-plugin-sdk private state in NewData Previously, errors such as these could be returned: ``` Error: Error Decoding Private State with random_password.min, on terraform_plugin_test.tf line 1, in resource "random_password" "min": 1: resource "random_password" "min" { An error was encountered when decoding private state: illegal base64 data at input byte 0. This is always a problem with Terraform or terraform-plugin-framework. Please report this to the provider developer. ``` The new unit test case would fail with the same error prior to this fix. --- .changelog/pending.txt | 3 +++ internal/privatestate/data.go | 15 +++++++++++++++ internal/privatestate/data_test.go | 13 +++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 .changelog/pending.txt diff --git a/.changelog/pending.txt b/.changelog/pending.txt new file mode 100644 index 000000000..1c7f87c0c --- /dev/null +++ b/.changelog/pending.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource: Prevented `Error Decoding Private State` errors on resources previously managed by terraform-plugin-sdk +``` diff --git a/internal/privatestate/data.go b/internal/privatestate/data.go index 89ca3e3c1..ecf610fdf 100644 --- a/internal/privatestate/data.go +++ b/internal/privatestate/data.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/logging" ) // Data contains private state data for the framework and providers. @@ -113,6 +114,20 @@ func NewData(ctx context.Context, data []byte) (*Data, diag.Diagnostics) { err := json.Unmarshal(data, &dataMap) if err != nil { + // terraform-plugin-sdk stored private state by marshalling its data + // as map[string]any, which is slightly incompatible with trying to + // unmarshal it as map[string][]byte. If unmarshalling with + // map[string]any works, we can ignore it for now, as provider + // developers did not have access to managing the private state data. + // + // TODO: We can extract the terraform-plugin-sdk resource timeouts key + // here to extract its prior data, if necessary. + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/400 + if anyErr := json.Unmarshal(data, new(map[string]any)); anyErr == nil { + logging.FrameworkWarn(ctx, "Discarding incompatible resource private state data", map[string]any{logging.KeyError: err.Error()}) + return nil, nil + } + diags.AddError( "Error Decoding Private State", fmt.Sprintf("An error was encountered when decoding private state: %s.\n\n"+ diff --git a/internal/privatestate/data_test.go b/internal/privatestate/data_test.go index 3a7e2ba7b..c8402a8be 100644 --- a/internal/privatestate/data_test.go +++ b/internal/privatestate/data_test.go @@ -2,6 +2,7 @@ package privatestate import ( "context" + "encoding/json" "fmt" "testing" @@ -281,6 +282,14 @@ func TestNewData(t *testing.T) { "providerKeyTwo": []byte(`{"pKeyTwo": {"k2": "two", "k3": 3}}`), }) + sdkJSON, err := json.Marshal(map[string]any{ + "schema_version": "2", + }) + + if err != nil { + t.Fatalf("unexpected error marshaling SDK JSON: %s", err) + } + testCases := map[string]struct { data []byte expected *Data @@ -410,6 +419,10 @@ func TestNewData(t *testing.T) { }, }, }, + "sdk-ignore": { + data: sdkJSON, + expected: nil, + }, } for name, testCase := range testCases { From f0c751e47d79c4ccd3f9e81147012eef0de277a5 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 12 Aug 2022 12:30:09 -0400 Subject: [PATCH 2/2] Update CHANGELOG for #452 --- .changelog/{pending.txt => 452.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{pending.txt => 452.txt} (100%) diff --git a/.changelog/pending.txt b/.changelog/452.txt similarity index 100% rename from .changelog/pending.txt rename to .changelog/452.txt