Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions terraform/context_refresh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1689,3 +1689,56 @@ aws_instance.foo:

checkStateString(t, result, expect)
}

// verify that create_before_destroy is updated in the state during refresh
func TestRefresh_updateLifecycle(t *testing.T) {
state := states.NewState()
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "aws_instance",
Name: "bar",
}.Instance(addrs.NoKey),
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"bar"}`),
},
addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
)

m := testModuleInline(t, map[string]string{
"main.tf": `
resource "aws_instance" "bar" {
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),
},
State: state,
})

state, diags := ctx.Refresh()
if diags.HasErrors() {
t.Fatalf("plan errors: %s", diags.Err())
}

r := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.bar"))
if !r.Current.CreateBeforeDestroy {
t.Fatal("create_before_destroy not updated in instance state")
}
}
33 changes: 33 additions & 0 deletions terraform/eval_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,3 +529,36 @@ func (n *EvalWriteResourceState) Eval(ctx EvalContext) (interface{}, error) {

return nil, nil
}

// EvalRefreshLifecycle is an EvalNode implementation that updates
// the status of the lifecycle options stored in the state.
// This currently only applies to create_before_destroy.
type EvalRefreshLifecycle struct {
Addr addrs.AbsResourceInstance

Config *configs.Resource
// Prior State
State **states.ResourceInstanceObject
// ForceCreateBeforeDestroy indicates a create_before_destroy resource
// depends on this resource.
ForceCreateBeforeDestroy bool
}

func (n *EvalRefreshLifecycle) Eval(ctx EvalContext) (interface{}, error) {
state := *n.State
if state == nil {
// no existing state
return nil, nil
}

// In 0.13 we could be refreshing a resource with no config.
// We should be operating on managed resource, but check here to be certain
if n.Config == nil || n.Config.Managed == nil {
log.Printf("[WARN] EvalRefreshLifecycle: no Managed config value found in instance state for %q", n.Addr)
return nil, nil
}

state.CreateBeforeDestroy = n.Config.Managed.CreateBeforeDestroy || n.ForceCreateBeforeDestroy

return nil, nil
}
6 changes: 6 additions & 0 deletions terraform/node_resource_plan_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe
ProviderSchema: &providerSchema,
Output: &instanceRefreshState,
},
&EvalRefreshLifecycle{
Addr: addr,
Config: n.Config,
State: &instanceRefreshState,
ForceCreateBeforeDestroy: n.ForceCreateBeforeDestroy,
},
&EvalRefresh{
Addr: addr.Resource,
ProviderAddr: n.ResolvedProvider,
Expand Down