diff --git a/command/command_test.go b/command/command_test.go index 5679fb5db..7c87f9d6a 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -265,7 +265,6 @@ func testState() *states.State { AttrsJSON: []byte("{\n \"id\": \"bar\"\n }"), Status: states.ObjectReady, Dependencies: []addrs.ConfigResource{}, - DependsOn: []addrs.Referenceable{}, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), diff --git a/command/refresh_test.go b/command/refresh_test.go index 4e5e2ae7d..3dc721c0d 100644 --- a/command/refresh_test.go +++ b/command/refresh_test.go @@ -278,7 +278,6 @@ func TestRefresh_defaultState(t *testing.T) { Status: states.ObjectReady, AttrsJSON: []byte("{\n \"ami\": null,\n \"id\": \"yes\"\n }"), Dependencies: []addrs.ConfigResource{}, - DependsOn: []addrs.Referenceable{}, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("wrong new object\ngot: %swant: %s", spew.Sdump(actual), spew.Sdump(expected)) @@ -343,7 +342,6 @@ func TestRefresh_outPath(t *testing.T) { Status: states.ObjectReady, AttrsJSON: []byte("{\n \"ami\": null,\n \"id\": \"yes\"\n }"), Dependencies: []addrs.ConfigResource{}, - DependsOn: []addrs.Referenceable{}, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("wrong new object\ngot: %swant: %s", spew.Sdump(actual), spew.Sdump(expected)) @@ -573,7 +571,6 @@ func TestRefresh_backup(t *testing.T) { Status: states.ObjectReady, AttrsJSON: []byte("{\n \"ami\": null,\n \"id\": \"changed\"\n }"), Dependencies: []addrs.ConfigResource{}, - DependsOn: []addrs.Referenceable{}, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("wrong new object\ngot: %swant: %s", spew.Sdump(actual), spew.Sdump(expected)) @@ -640,7 +637,6 @@ func TestRefresh_disableBackup(t *testing.T) { Status: states.ObjectReady, AttrsJSON: []byte("{\n \"ami\": null,\n \"id\": \"yes\"\n }"), Dependencies: []addrs.ConfigResource{}, - DependsOn: []addrs.Referenceable{}, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("wrong new object\ngot: %swant: %s", spew.Sdump(actual), spew.Sdump(expected)) diff --git a/command/show_test.go b/command/show_test.go index de3a7a6a7..bc2f36bfa 100644 --- a/command/show_test.go +++ b/command/show_test.go @@ -83,7 +83,6 @@ func TestShow_aliasedProvider(t *testing.T) { AttrsJSON: []byte("{\n \"id\": \"bar\"\n }"), Status: states.ObjectReady, Dependencies: []addrs.ConfigResource{}, - DependsOn: []addrs.Referenceable{}, }, addrs.RootModuleInstance.ProviderConfigAliased(addrs.NewDefaultProvider("test"), "alias"), ) diff --git a/helper/resource/state_shim.go b/helper/resource/state_shim.go index 1a98c3661..aa2231b28 100644 --- a/helper/resource/state_shim.go +++ b/helper/resource/state_shim.go @@ -87,10 +87,6 @@ func shimNewState(newState *states.State, providers map[string]terraform.Resourc resState.Primary.Meta["schema_version"] = i.Current.SchemaVersion } - for _, dep := range i.Current.DependsOn { - resState.Dependencies = append(resState.Dependencies, dep.String()) - } - // convert the indexes to the old style flapmap indexes idx := "" switch key.(type) { diff --git a/helper/resource/state_shim_test.go b/helper/resource/state_shim_test.go index 2e9bc58fd..789e1295f 100644 --- a/helper/resource/state_shim_test.go +++ b/helper/resource/state_shim_test.go @@ -31,15 +31,6 @@ func TestStateShim(t *testing.T) { Status: states.ObjectReady, AttrsFlat: map[string]string{"id": "foo", "bazzle": "dazzle"}, SchemaVersion: 7, - DependsOn: []addrs.Referenceable{ - addrs.ResourceInstance{ - Resource: addrs.Resource{ - Mode: 'M', - Type: "test_thing", - Name: "baz", - }, - }, - }, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), @@ -55,7 +46,6 @@ func TestStateShim(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsFlat: map[string]string{"id": "baz", "bazzle": "dazzle"}, - DependsOn: []addrs.Referenceable{}, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), @@ -74,7 +64,6 @@ func TestStateShim(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{"id": "bar", "fuzzle":"wuzzle"}`), - DependsOn: []addrs.Referenceable{}, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), @@ -90,15 +79,6 @@ func TestStateShim(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{"id": "bar", "fizzle":"wizzle"}`), - DependsOn: []addrs.Referenceable{ - addrs.ResourceInstance{ - Resource: addrs.Resource{ - Mode: 'D', - Type: "test_data_thing", - Name: "foo", - }, - }, - }, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), @@ -116,15 +96,6 @@ func TestStateShim(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsFlat: map[string]string{"id": "old", "fizzle": "wizzle"}, - DependsOn: []addrs.Referenceable{ - addrs.ResourceInstance{ - Resource: addrs.Resource{ - Mode: 'D', - Type: "test_data_thing", - Name: "foo", - }, - }, - }, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), @@ -141,7 +112,6 @@ func TestStateShim(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsFlat: map[string]string{"id": "0", "bazzle": "dazzle"}, - DependsOn: []addrs.Referenceable{}, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), @@ -157,7 +127,6 @@ func TestStateShim(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectTainted, AttrsFlat: map[string]string{"id": "1", "bazzle": "dazzle"}, - DependsOn: []addrs.Referenceable{}, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), @@ -174,7 +143,6 @@ func TestStateShim(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{"id": "single", "bazzle":"dazzle"}`), - DependsOn: []addrs.Referenceable{}, }, addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), @@ -223,7 +191,6 @@ func TestStateShim(t *testing.T) { "schema_version": 7, }, }, - Dependencies: []string{"test_thing.baz"}, }, }, }, @@ -249,7 +216,6 @@ func TestStateShim(t *testing.T) { }, }, }, - Dependencies: []string{"data.test_data_thing.foo"}, }, "data.test_data_thing.foo": &terraform.ResourceState{ Type: "test_data_thing", @@ -386,7 +352,6 @@ func TestShimLegacyState(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsFlat: map[string]string{"id": "baz", "bazzle": "dazzle"}, - DependsOn: []addrs.Referenceable{}, Dependencies: []addrs.ConfigResource{}, }, addrs.AbsProviderConfig{ @@ -404,7 +369,6 @@ func TestShimLegacyState(t *testing.T) { &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsFlat: map[string]string{"id": "bar", "fizzle": "wizzle"}, - DependsOn: []addrs.Referenceable{}, Dependencies: []addrs.ConfigResource{}, }, addrs.AbsProviderConfig{ diff --git a/states/instance_object.go b/states/instance_object.go index 0a6454990..d1b53e292 100644 --- a/states/instance_object.go +++ b/states/instance_object.go @@ -42,11 +42,6 @@ type ResourceInstanceObject struct { // destroy operations, we need to record the status to ensure a resource // removed from the config will still be destroyed in the same manner. CreateBeforeDestroy bool - - // DependsOn corresponds to the deprecated `depends_on` field in the state. - // This field contained the configuration `depends_on` values, and some of - // the references from within a single module. - DependsOn []addrs.Referenceable } // ObjectStatus represents the status of a RemoteObject. @@ -109,11 +104,12 @@ func (o *ResourceInstanceObject) Encode(ty cty.Type, schemaVersion uint64) (*Res } return &ResourceInstanceObjectSrc{ - SchemaVersion: schemaVersion, - AttrsJSON: src, - Private: o.Private, - Status: o.Status, - Dependencies: o.Dependencies, + SchemaVersion: schemaVersion, + AttrsJSON: src, + Private: o.Private, + Status: o.Status, + Dependencies: o.Dependencies, + CreateBeforeDestroy: o.CreateBeforeDestroy, }, nil } diff --git a/states/instance_object_src.go b/states/instance_object_src.go index c8f92bd0e..bf790db04 100644 --- a/states/instance_object_src.go +++ b/states/instance_object_src.go @@ -55,8 +55,6 @@ type ResourceInstanceObjectSrc struct { Status ObjectStatus Dependencies []addrs.ConfigResource CreateBeforeDestroy bool - // deprecated - DependsOn []addrs.Referenceable } // Decode unmarshals the raw representation of the object attributes. Pass the @@ -89,7 +87,6 @@ func (os *ResourceInstanceObjectSrc) Decode(ty cty.Type) (*ResourceInstanceObjec Value: val, Status: os.Status, Dependencies: os.Dependencies, - DependsOn: os.DependsOn, Private: os.Private, CreateBeforeDestroy: os.CreateBeforeDestroy, }, nil diff --git a/states/state_deepcopy.go b/states/state_deepcopy.go index 5cd7708e1..f6a3919c3 100644 --- a/states/state_deepcopy.go +++ b/states/state_deepcopy.go @@ -158,12 +158,6 @@ func (obj *ResourceInstanceObjectSrc) DeepCopy() *ResourceInstanceObjectSrc { copy(dependencies, obj.Dependencies) } - var dependsOn []addrs.Referenceable - if obj.DependsOn != nil { - dependsOn = make([]addrs.Referenceable, len(obj.DependsOn)) - copy(dependsOn, obj.DependsOn) - } - return &ResourceInstanceObjectSrc{ Status: obj.Status, SchemaVersion: obj.SchemaVersion, @@ -171,7 +165,6 @@ func (obj *ResourceInstanceObjectSrc) DeepCopy() *ResourceInstanceObjectSrc { AttrsFlat: attrsFlat, AttrsJSON: attrsJSON, Dependencies: dependencies, - DependsOn: dependsOn, CreateBeforeDestroy: obj.CreateBeforeDestroy, } } diff --git a/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate b/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate new file mode 100644 index 000000000..35186cdd2 --- /dev/null +++ b/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate @@ -0,0 +1,34 @@ +{ + "version": 4, + "serial": 0, + "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04", + "terraform_version": "0.12.0", + "outputs": { + "numbers": { + "type": "string", + "value": "0,1" + } + }, + "resources": [ + { + "module": "module.modA", + "mode": "managed", + "type": "null_resource", + "name": "resource", + "provider": "provider[\"registry.terraform.io/-/null\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "4639265839606265182", + "triggers": { + "input": "test" + } + }, + "create_before_destroy": true, + "private": "bnVsbA==" + } + ] + } + ] +} diff --git a/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate b/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate new file mode 120000 index 000000000..3831d381a --- /dev/null +++ b/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate @@ -0,0 +1 @@ +v4-cbd.in.tfstate \ No newline at end of file diff --git a/states/statefile/version3_upgrade.go b/states/statefile/version3_upgrade.go index 0b97da080..e54a08ccd 100644 --- a/states/statefile/version3_upgrade.go +++ b/states/statefile/version3_upgrade.go @@ -370,7 +370,6 @@ func upgradeInstanceObjectV3ToV4(rsOld *resourceStateV2, isOld *instanceStateV2, Status: status, Deposed: string(deposedKey), AttributesFlat: attributes, - DependsOn: dependencies, SchemaVersion: schemaVersion, PrivateRaw: privateJSON, }, nil diff --git a/states/statefile/version4.go b/states/statefile/version4.go index b98f90f6d..04701f49d 100644 --- a/states/statefile/version4.go +++ b/states/statefile/version4.go @@ -130,7 +130,8 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) { instAddr := rAddr.Instance(key) obj := &states.ResourceInstanceObjectSrc{ - SchemaVersion: isV4.SchemaVersion, + SchemaVersion: isV4.SchemaVersion, + CreateBeforeDestroy: isV4.CreateBeforeDestroy, } { @@ -171,34 +172,6 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) { obj.Private = raw } - { - // Allow both the deprecated `depends_on` and new - // `dependencies` to coexist for now so resources can be - // upgraded as they are refreshed. - depsRaw := isV4.DependsOn - deps := make([]addrs.Referenceable, 0, len(depsRaw)) - for _, depRaw := range depsRaw { - ref, refDiags := addrs.ParseRefStr(depRaw) - diags = diags.Append(refDiags) - if refDiags.HasErrors() { - continue - } - if len(ref.Remaining) != 0 { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid resource instance metadata in state", - fmt.Sprintf("Instance %s declares dependency on %q, which is not a reference to a dependable object.", instAddr.Absolute(moduleAddr), depRaw), - )) - } - if ref.Subject == nil { - // Should never happen - panic(fmt.Sprintf("parsing dependency %q for instance %s returned a nil address", depRaw, instAddr.Absolute(moduleAddr))) - } - deps = append(deps, ref.Subject) - } - obj.DependsOn = deps - } - { depsRaw := isV4.Dependencies deps := make([]addrs.ConfigResource, 0, len(depsRaw)) @@ -462,11 +435,6 @@ func appendInstanceObjectStateV4(rs *states.Resource, is *states.ResourceInstanc deps[i] = depAddr.String() } - depOn := make([]string, len(obj.DependsOn)) - for i, depAddr := range obj.DependsOn { - depOn[i] = depAddr.String() - } - var rawKey interface{} switch tk := key.(type) { case addrs.IntKey: @@ -484,15 +452,15 @@ func appendInstanceObjectStateV4(rs *states.Resource, is *states.ResourceInstanc } return append(isV4s, instanceObjectStateV4{ - IndexKey: rawKey, - Deposed: string(deposed), - Status: status, - SchemaVersion: obj.SchemaVersion, - AttributesFlat: obj.AttrsFlat, - AttributesRaw: obj.AttrsJSON, - PrivateRaw: privateRaw, - Dependencies: deps, - DependsOn: depOn, + IndexKey: rawKey, + Deposed: string(deposed), + Status: status, + SchemaVersion: obj.SchemaVersion, + AttributesFlat: obj.AttrsFlat, + AttributesRaw: obj.AttrsJSON, + PrivateRaw: privateRaw, + Dependencies: deps, + CreateBeforeDestroy: obj.CreateBeforeDestroy, }), diags } @@ -543,7 +511,8 @@ type instanceObjectStateV4 struct { PrivateRaw []byte `json:"private,omitempty"` Dependencies []string `json:"dependencies,omitempty"` - DependsOn []string `json:"depends_on,omitempty"` + + CreateBeforeDestroy bool `json:"create_before_destroy,omitempty"` } // stateVersionV4 is a weird special type we use to produce our hard-coded diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index f87bb720c..cc92b6c97 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -11011,3 +11011,44 @@ module.mod2: t.Fatalf("expected:\n%s\ngot:\n%s\n", expected, state) } } + +func TestContext2Apply_inheritAndStoreCBD(t *testing.T) { + m := testModuleInline(t, map[string]string{ + "main.tf": ` +resource "aws_instance" "foo" { +} + +resource "aws_instance" "cbd" { + foo = aws_instance.foo.id + lifecycle { + create_before_destroy = true + } +} +`, + }) + + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + ctx := testContext2(t, &ContextOpts{ + Config: m, + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), + }, + }) + + _, diags := ctx.Plan() + if diags.HasErrors() { + t.Fatal(diags.ErrWithWarnings()) + } + + state, diags := ctx.Apply() + if diags.HasErrors() { + t.Fatal(diags.ErrWithWarnings()) + } + + foo := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo")) + if !foo.Current.CreateBeforeDestroy { + t.Fatal("aws_instance.foo should also be create_before_destroy") + } +} diff --git a/terraform/eval_apply.go b/terraform/eval_apply.go index ed8e7bc10..6c9ed41ba 100644 --- a/terraform/eval_apply.go +++ b/terraform/eval_apply.go @@ -22,17 +22,18 @@ import ( // EvalApply is an EvalNode implementation that writes the diff to // the full diff. type EvalApply struct { - Addr addrs.ResourceInstance - Config *configs.Resource - State **states.ResourceInstanceObject - Change **plans.ResourceInstanceChange - ProviderAddr addrs.AbsProviderConfig - Provider *providers.Interface - ProviderMetas map[addrs.Provider]*configs.ProviderMeta - ProviderSchema **ProviderSchema - Output **states.ResourceInstanceObject - CreateNew *bool - Error *error + Addr addrs.ResourceInstance + Config *configs.Resource + State **states.ResourceInstanceObject + Change **plans.ResourceInstanceChange + ProviderAddr addrs.AbsProviderConfig + Provider *providers.Interface + ProviderMetas map[addrs.Provider]*configs.ProviderMeta + ProviderSchema **ProviderSchema + Output **states.ResourceInstanceObject + CreateNew *bool + Error *error + CreateBeforeDestroy bool } // TODO: test @@ -305,9 +306,10 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) { var newState *states.ResourceInstanceObject if !newVal.IsNull() { // null value indicates that the object is deleted, so we won't set a new state in that case newState = &states.ResourceInstanceObject{ - Status: newStatus, - Value: newVal, - Private: resp.Private, + Status: newStatus, + Value: newVal, + Private: resp.Private, + CreateBeforeDestroy: n.CreateBeforeDestroy, } } diff --git a/terraform/eval_refresh.go b/terraform/eval_refresh.go index 4162331df..d56291c19 100644 --- a/terraform/eval_refresh.go +++ b/terraform/eval_refresh.go @@ -119,6 +119,7 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) { newState.Value = resp.NewState newState.Private = resp.Private newState.Dependencies = state.Dependencies + newState.CreateBeforeDestroy = state.CreateBeforeDestroy // Call post-refresh hook err = ctx.Hook(func(h Hook) (HookAction, error) { diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index fba7eff50..86ea86e05 100644 --- a/terraform/graph_builder_apply.go +++ b/terraform/graph_builder_apply.go @@ -143,6 +143,10 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { &ReferenceTransformer{}, &AttachDependenciesTransformer{}, + // Detect when create_before_destroy must be forced on for a particular + // node due to dependency edges, to avoid graph cycles during apply. + &ForcedCBDTransformer{}, + // Destruction ordering &DestroyEdgeTransformer{ Config: b.Config, diff --git a/terraform/node_resource_apply_instance.go b/terraform/node_resource_apply_instance.go index 2a55f23a7..93aab7564 100644 --- a/terraform/node_resource_apply_instance.go +++ b/terraform/node_resource_apply_instance.go @@ -25,6 +25,10 @@ type NodeApplyableResourceInstance struct { destroyNode GraphNodeDestroyerCBD graphNodeDeposer // implementation of GraphNodeDeposerConfig + + // If this node is forced to be CreateBeforeDestroy, we need to record that + // in the state to. + ForceCreateBeforeDestroy bool } var ( @@ -42,20 +46,27 @@ func (n *NodeApplyableResourceInstance) AttachDestroyNode(d GraphNodeDestroyerCB n.destroyNode = d } -// createBeforeDestroy checks this nodes config status and the status af any +// CreateBeforeDestroy checks this nodes config status and the status af any // companion destroy node for CreateBeforeDestroy. -func (n *NodeApplyableResourceInstance) createBeforeDestroy() bool { - cbd := false +func (n *NodeApplyableResourceInstance) CreateBeforeDestroy() bool { + if n.ForceCreateBeforeDestroy { + return n.ForceCreateBeforeDestroy + } if n.Config != nil && n.Config.Managed != nil { - cbd = n.Config.Managed.CreateBeforeDestroy + return n.Config.Managed.CreateBeforeDestroy } if n.destroyNode != nil { - cbd = cbd || n.destroyNode.CreateBeforeDestroy() + return n.destroyNode.CreateBeforeDestroy() } - return cbd + return false +} + +func (n *NodeApplyableResourceInstance) ModifyCreateBeforeDestroy(v bool) error { + n.ForceCreateBeforeDestroy = v + return nil } // GraphNodeCreator @@ -78,7 +89,7 @@ func (n *NodeApplyableResourceInstance) References() []*addrs.Reference { // would create a dependency cycle. We make a compromise here of requiring // changes to be updated across two applies in this case, since the first // plan will use the old values. - if !n.createBeforeDestroy() { + if !n.CreateBeforeDestroy() { for _, ref := range ret { switch tr := ref.Subject.(type) { case addrs.ResourceInstance: @@ -254,7 +265,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe if diffApply != nil { destroy = (diffApply.Action == plans.Delete || diffApply.Action.IsReplace()) } - if destroy && n.createBeforeDestroy() { + if destroy && n.CreateBeforeDestroy() { createBeforeDestroyEnabled = true } return createBeforeDestroyEnabled, nil @@ -346,17 +357,18 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe Change: &diffApply, }, &EvalApply{ - Addr: addr.Resource, - Config: n.Config, - State: &state, - Change: &diffApply, - Provider: &provider, - ProviderAddr: n.ResolvedProvider, - ProviderMetas: n.ProviderMetas, - ProviderSchema: &providerSchema, - Output: &state, - Error: &err, - CreateNew: &createNew, + Addr: addr.Resource, + Config: n.Config, + State: &state, + Change: &diffApply, + Provider: &provider, + ProviderAddr: n.ResolvedProvider, + ProviderMetas: n.ProviderMetas, + ProviderSchema: &providerSchema, + Output: &state, + Error: &err, + CreateNew: &createNew, + CreateBeforeDestroy: n.CreateBeforeDestroy(), }, &EvalMaybeTainted{ Addr: addr.Resource, @@ -411,7 +423,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe if !diff.Action.IsReplace() { return true, nil } - if !n.createBeforeDestroy() { + if !n.CreateBeforeDestroy() { return true, nil } return false, nil