Skip to content

Commit

Permalink
don't evaluate destroy instances
Browse files Browse the repository at this point in the history
Orphaned instances that are create_before_destroy will still be in the
state when their references are evaluated. We need to skip instances
that are planned to be destroyed altogether, as they can't be part of an
evaluation.
  • Loading branch information
jbardin committed Jun 26, 2020
1 parent be34a0e commit 9a49160
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 1 deletion.
82 changes: 82 additions & 0 deletions terraform/context_apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11357,3 +11357,85 @@ output "myoutput" {
t.Fatal("expected empty state, got:", state)
}
}

func TestContext2Apply_scaleInCBD(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_instance" "a" {
count = 1
lifecycle {
create_before_destroy = true
}
}
resource "test_instance" "b" {
foo = join(".", test_instance.a[*].id)
}
output "out" {
value = join(".", test_instance.a[*].id)
}
`})

state := states.NewState()
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.a[0]").Resource,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"a0"}`),
Dependencies: []addrs.ConfigResource{mustResourceAddr("module.child.aws_instance.child")},
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.a[1]").Resource,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"a1"}`),
Dependencies: []addrs.ConfigResource{mustResourceAddr("module.child.aws_instance.child")},
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.b").Resource,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"b", "foo":"old.old"}`),
Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.a")},
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)

p := testProvider("test")
p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
return testApplyFn(info, s, d)
}

p.DiffFn = testDiffFn
ctx := testContext2(t, &ContextOpts{
Config: m,
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
State: state,
})

_, diags := ctx.Plan()
if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}

// if resource b isn't going to apply correctly, we will get an error about
// an invalid plan value
state, diags = ctx.Apply()
if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}

// check the output, as those can't cause an error planning the value
out := state.RootModule().OutputValues["out"].Value.AsString()
if out != "a0" {
t.Fatalf(`expected output "new", got: %q`, out)
}
}
12 changes: 11 additions & 1 deletion terraform/evaluate.go
Original file line number Diff line number Diff line change
Expand Up @@ -655,10 +655,20 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc

instAddr := addr.Instance(key).Absolute(d.ModulePath)

change := d.Evaluator.Changes.GetResourceInstanceChange(instAddr, states.CurrentGen)
if change != nil {
// Don't take any resources that are yet to be deleted into account.
// If the referenced resource is CreateBeforeDestroy, then orphaned
// instances will will be in the state, as they are not destroyed
// until after their dependants are updated.
if change.Action == plans.Delete {
continue
}
}

// Planned resources are temporarily stored in state with empty values,
// and need to be replaced bu the planned value here.
if is.Current.Status == states.ObjectPlanned {
change := d.Evaluator.Changes.GetResourceInstanceChange(instAddr, states.CurrentGen)
if change == nil {
// If the object is in planned status then we should not get
// here, since we should have found a pending value in the plan
Expand Down

0 comments on commit 9a49160

Please sign in to comment.