Skip to content

Commit

Permalink
internal/privatestate: Handle terraform-plugin-sdk private state in N…
Browse files Browse the repository at this point in the history
…ewData (#452)

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.
  • Loading branch information
bflad committed Aug 12, 2022
1 parent 330a87f commit eea9faa
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/452.txt
@@ -0,0 +1,3 @@
```release-note:bug
resource: Prevented `Error Decoding Private State` errors on resources previously managed by terraform-plugin-sdk
```
15 changes: 15 additions & 0 deletions internal/privatestate/data.go
Expand Up @@ -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.
Expand Down Expand Up @@ -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"+
Expand Down
13 changes: 13 additions & 0 deletions internal/privatestate/data_test.go
Expand Up @@ -2,6 +2,7 @@ package privatestate

import (
"context"
"encoding/json"
"fmt"
"testing"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -410,6 +419,10 @@ func TestNewData(t *testing.T) {
},
},
},
"sdk-ignore": {
data: sdkJSON,
expected: nil,
},
}

for name, testCase := range testCases {
Expand Down

0 comments on commit eea9faa

Please sign in to comment.