Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update create_before_destroy in state during refresh #26343

Merged
merged 3 commits into from
Sep 24, 2020
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