Skip to content

Commit

Permalink
Merge pull request #21611 from hashicorp/jbardin/private-data-read
Browse files Browse the repository at this point in the history
Make sure resource private data is carried through the entire resource lifecycle
  • Loading branch information
jbardin authored Jun 5, 2019
2 parents 4124d01 + 4cb6ebe commit e71e3d8
Show file tree
Hide file tree
Showing 14 changed files with 547 additions and 337 deletions.
21 changes: 21 additions & 0 deletions builtin/providers/test/resource_timeout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ resource "test_resource_timeout" "foo" {
},
})
}

func TestResourceTimeout_delete(t *testing.T) {
// If the delete timeout isn't saved until destroy, the cleanup here will
// fail because the default is only 20m.
resource.UnitTest(t, resource.TestCase{
Providers: testAccProviders,
CheckDestroy: testAccCheckResourceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: strings.TrimSpace(`
resource "test_resource_timeout" "foo" {
delete_delay = "25m"
timeouts {
delete = "30m"
}
}
`),
},
},
})
}
func TestResourceTimeout_update(t *testing.T) {
resource.UnitTest(t, resource.TestCase{
Providers: testAccProviders,
Expand Down
3 changes: 2 additions & 1 deletion command/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"time"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/mitchellh/cli"
"github.com/zclconf/go-cty/cty"

Expand Down Expand Up @@ -1392,7 +1393,7 @@ func TestApply_backup(t *testing.T) {

actual := backupState.RootModule().Resources["test_instance.foo"]
expected := originalState.RootModule().Resources["test_instance.foo"]
if !cmp.Equal(actual, expected) {
if !cmp.Equal(actual, expected, cmpopts.EquateEmpty()) {
t.Fatalf(
"wrong aws_instance.foo state\n%s",
cmp.Diff(expected, actual, cmp.Transformer("bytesAsString", func(b []byte) string {
Expand Down
10 changes: 7 additions & 3 deletions command/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"encoding/json"
"flag"
"fmt"
"github.com/hashicorp/terraform/internal/initwd"
"github.com/hashicorp/terraform/registry"
"io"
"io/ioutil"
"log"
Expand All @@ -21,6 +19,9 @@ import (
"syscall"
"testing"

"github.com/hashicorp/terraform/internal/initwd"
"github.com/hashicorp/terraform/registry"

"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/configs/configload"
Expand Down Expand Up @@ -266,7 +267,10 @@ func testState() *states.State {
Type: "test",
}.Absolute(addrs.RootModuleInstance),
)
})
// DeepCopy is used here to ensure our synthetic state matches exactly
// with a state that will have been copied during the command
// operation, and all fields have been copied correctly.
}).DeepCopy()
}

// writeStateForTesting is a helper that writes the given naked state to the
Expand Down
6 changes: 4 additions & 2 deletions command/refresh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"testing"

"github.com/davecgh/go-spew/spew"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/mitchellh/cli"
"github.com/zclconf/go-cty/cty"

Expand Down Expand Up @@ -557,8 +559,8 @@ func TestRefresh_backup(t *testing.T) {
}

newState := testStateRead(t, statePath)
if !reflect.DeepEqual(newState, state) {
t.Fatalf("bad: %#v", newState)
if !cmp.Equal(newState, state, cmpopts.EquateEmpty()) {
t.Fatalf("got:\n%s\nexpected:\n%s\n", newState, state)
}

newState = testStateRead(t, outPath)
Expand Down
6 changes: 6 additions & 0 deletions helper/plugin/grpc_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ func (s *GRPCProviderServer) ReadResource(_ context.Context, req *proto.ReadReso
Msgpack: newStateMP,
}

// helper/schema did previously handle private data during refresh, but
// core is now going to expect this to be maintained in order to
// persist it in the state.
resp.Private = req.Private

return resp, nil
}

Expand Down Expand Up @@ -569,6 +574,7 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
// We don't usually plan destroys, but this can return early in any case.
if proposedNewStateVal.IsNull() {
resp.PlannedState = req.ProposedNewState
resp.PlannedPrivate = req.PriorPrivate
return resp, nil
}

Expand Down
78 changes: 51 additions & 27 deletions helper/resource/state_shim.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package resource

import (
"encoding/json"
"fmt"

"github.com/hashicorp/terraform/addrs"
Expand Down Expand Up @@ -52,43 +53,57 @@ func shimNewState(newState *states.State, providers map[string]terraform.Resourc
resource := getResource(providers, providerType, res.Addr)

for key, i := range res.Instances {
flatmap, err := shimmedAttributes(i.Current, resource)
if err != nil {
return nil, fmt.Errorf("error decoding state for %q: %s", resType, err)
resState := &terraform.ResourceState{
Type: resType,
Provider: res.ProviderConfig.String(),
}

resState := &terraform.ResourceState{
Type: resType,
Primary: &terraform.InstanceState{
// We should always have a Current instance here, but be safe about checking.
if i.Current != nil {
flatmap, err := shimmedAttributes(i.Current, resource)
if err != nil {
return nil, fmt.Errorf("error decoding state for %q: %s", resType, err)
}

var meta map[string]interface{}
if i.Current.Private != nil {
err := json.Unmarshal(i.Current.Private, &meta)
if err != nil {
return nil, err
}
}

resState.Primary = &terraform.InstanceState{
ID: flatmap["id"],
Attributes: flatmap,
Tainted: i.Current.Status == states.ObjectTainted,
},
Provider: res.ProviderConfig.String(),
}
if i.Current.SchemaVersion != 0 {
resState.Primary.Meta = map[string]interface{}{
"schema_version": i.Current.SchemaVersion,
Meta: meta,
}
}

for _, dep := range i.Current.Dependencies {
resState.Dependencies = append(resState.Dependencies, dep.String())
}
if i.Current.SchemaVersion != 0 {
resState.Primary.Meta = map[string]interface{}{
"schema_version": i.Current.SchemaVersion,
}
}

// convert the indexes to the old style flapmap indexes
idx := ""
switch key.(type) {
case addrs.IntKey:
// don't add numeric index values to resources with a count of 0
if len(res.Instances) > 1 {
idx = fmt.Sprintf(".%d", key)
for _, dep := range i.Current.Dependencies {
resState.Dependencies = append(resState.Dependencies, dep.String())
}
case addrs.StringKey:
idx = "." + key.String()
}

mod.Resources[res.Addr.String()+idx] = resState
// convert the indexes to the old style flapmap indexes
idx := ""
switch key.(type) {
case addrs.IntKey:
// don't add numeric index values to resources with a count of 0
if len(res.Instances) > 1 {
idx = fmt.Sprintf(".%d", key)
}
case addrs.StringKey:
idx = "." + key.String()
}

mod.Resources[res.Addr.String()+idx] = resState
}

// add any deposed instances
for _, dep := range i.Deposed {
Expand All @@ -97,10 +112,19 @@ func shimNewState(newState *states.State, providers map[string]terraform.Resourc
return nil, fmt.Errorf("error decoding deposed state for %q: %s", resType, err)
}

var meta map[string]interface{}
if dep.Private != nil {
err := json.Unmarshal(dep.Private, &meta)
if err != nil {
return nil, err
}
}

deposed := &terraform.InstanceState{
ID: flatmap["id"],
Attributes: flatmap,
Tainted: dep.Status == states.ObjectTainted,
Meta: meta,
}
if dep.SchemaVersion != 0 {
deposed.Meta = map[string]interface{}{
Expand Down
Loading

0 comments on commit e71e3d8

Please sign in to comment.