From 04cbf249aabebead12d85efc5609b66f6445deb0 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sat, 16 Mar 2019 15:36:53 -0700 Subject: [PATCH] core: Don't fail on dynamic attribute values during refresh Our post-refresh safety check had the constraint and real type inverted, so previously any refresh of a resource type with a dynamically-typed attribute would fail this type check. Also includes a small tweak to the error message from this check since the old one was a little awkward to read in practice when the error is a cty.PathError rendered with an attribute path prefix. --- terraform/context_refresh_test.go | 73 +++++++++++++++++++ terraform/eval_refresh.go | 4 +- .../test-fixtures/refresh-dynamic/main.tf | 3 + 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 terraform/test-fixtures/refresh-dynamic/main.tf diff --git a/terraform/context_refresh_test.go b/terraform/context_refresh_test.go index d2a5190aa..6ca940408 100644 --- a/terraform/context_refresh_test.go +++ b/terraform/context_refresh_test.go @@ -89,6 +89,79 @@ func TestContext2Refresh(t *testing.T) { } } +func TestContext2Refresh_dynamicAttr(t *testing.T) { + m := testModule(t, "refresh-dynamic") + + startingState := states.BuildState(func(ss *states.SyncState) { + ss.SetResourceInstanceCurrent( + addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_instance", + Name: "foo", + }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"dynamic":{"type":"string","value":"hello"}}`), + }, + addrs.ProviderConfig{ + Type: "test", + }.Absolute(addrs.RootModuleInstance), + ) + }) + + readStateVal := cty.ObjectVal(map[string]cty.Value{ + "dynamic": cty.EmptyTupleVal, + }) + + p := testProvider("test") + p.GetSchemaReturn = &ProviderSchema{ + ResourceTypes: map[string]*configschema.Block{ + "test_instance": { + Attributes: map[string]*configschema.Attribute{ + "dynamic": {Type: cty.DynamicPseudoType, Optional: true}, + }, + }, + }, + } + p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { + return providers.ReadResourceResponse{ + NewState: readStateVal, + } + } + + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[string]providers.Factory{ + "test": testProviderFuncFixed(p), + }, + ), + State: startingState, + }) + + schema := p.GetSchemaReturn.ResourceTypes["test_instance"] + ty := schema.ImpliedType() + + s, diags := ctx.Refresh() + if diags.HasErrors() { + t.Fatal(diags.Err()) + } + + if !p.ReadResourceCalled { + t.Fatal("ReadResource should be called") + } + + mod := s.RootModule() + newState, err := mod.Resources["test_instance.foo"].Instances[addrs.NoKey].Current.Decode(ty) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(readStateVal, newState.Value, valueComparer) { + t.Error(cmp.Diff(newState.Value, readStateVal, valueComparer, equateEmpty)) + } +} + func TestContext2Refresh_dataComputedModuleVar(t *testing.T) { p := testProvider("aws") m := testModule(t, "refresh-data-module-var") diff --git a/terraform/eval_refresh.go b/terraform/eval_refresh.go index ec3822cec..03bc94811 100644 --- a/terraform/eval_refresh.go +++ b/terraform/eval_refresh.go @@ -71,12 +71,12 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) { panic("new state is cty.NilVal") } - for _, err := range schema.ImpliedType().TestConformance(resp.NewState.Type()) { + for _, err := range resp.NewState.Type().TestConformance(schema.ImpliedType()) { diags = diags.Append(tfdiags.Sourceless( tfdiags.Error, "Provider produced invalid object", fmt.Sprintf( - "Provider %q planned an invalid value for %s: %s during refresh.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", + "Provider %q planned an invalid value for %s during refresh: %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", n.ProviderAddr.ProviderConfig.Type, absAddr, tfdiags.FormatError(err), ), )) diff --git a/terraform/test-fixtures/refresh-dynamic/main.tf b/terraform/test-fixtures/refresh-dynamic/main.tf new file mode 100644 index 000000000..5c857a2f4 --- /dev/null +++ b/terraform/test-fixtures/refresh-dynamic/main.tf @@ -0,0 +1,3 @@ +resource "test_instance" "foo" { + dynamic = {} +}