Merge pull request #5302 from hashicorp/b-5254
terraform: don't prune resource if count has interpolations
This commit is contained in:
commit
242f088309
|
@ -1,6 +1,7 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -3929,3 +3930,87 @@ func TestContext2Apply_singleDestroy(t *testing.T) {
|
||||||
t.Fatalf("bad: %d", invokeCount)
|
t.Fatalf("bad: %d", invokeCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GH-5254
|
||||||
|
func TestContext2Apply_issue5254(t *testing.T) {
|
||||||
|
// Create a provider. We use "template" here just to match the repro
|
||||||
|
// we got from the issue itself.
|
||||||
|
p := testProvider("template")
|
||||||
|
p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{
|
||||||
|
Name: "template_file",
|
||||||
|
})
|
||||||
|
|
||||||
|
p.ApplyFn = testApplyFn
|
||||||
|
p.DiffFn = testDiffFn
|
||||||
|
|
||||||
|
// Apply cleanly step 0
|
||||||
|
t.Log("Applying Step 0")
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Module: testModule(t, "issue-5254/step-0"),
|
||||||
|
Providers: map[string]ResourceProviderFactory{
|
||||||
|
"template": testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
plan, err := ctx.Plan()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
t.Logf("Plan for Step 0: %s", plan)
|
||||||
|
|
||||||
|
state, err := ctx.Apply()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Application success. Now make the modification and store a plan
|
||||||
|
println("Planning Step 1")
|
||||||
|
t.Log("Planning Step 1")
|
||||||
|
ctx = testContext2(t, &ContextOpts{
|
||||||
|
Module: testModule(t, "issue-5254/step-1"),
|
||||||
|
State: state,
|
||||||
|
Providers: map[string]ResourceProviderFactory{
|
||||||
|
"template": testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
plan, err = ctx.Plan()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write / Read plan to simulate running it through a Plan file
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := WritePlan(plan, &buf); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
planFromFile, err := ReadPlan(&buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Plan for Step 1: %s", planFromFile)
|
||||||
|
|
||||||
|
// Apply the plan
|
||||||
|
println("Applying Step 1 (from Plan)")
|
||||||
|
t.Log("Applying Step 1 (from plan)")
|
||||||
|
ctx = planFromFile.Context(&ContextOpts{
|
||||||
|
Providers: map[string]ResourceProviderFactory{
|
||||||
|
"template": testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
state, err = ctx.Apply()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
actual := strings.TrimSpace(state.String())
|
||||||
|
expected := strings.TrimSpace(testTerraformApplyProviderAliasStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("bad: \n%s", actual)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
|
@ -52,6 +52,11 @@ func testDiffFn(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore __-prefixed keys since they're used for magic
|
||||||
|
if k[0] == '_' && k[1] == '_' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if k == "nil" {
|
if k == "nil" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -100,6 +105,9 @@ func testDiffFn(
|
||||||
if k == "require_new" {
|
if k == "require_new" {
|
||||||
attrDiff.RequiresNew = true
|
attrDiff.RequiresNew = true
|
||||||
}
|
}
|
||||||
|
if _, ok := c.Raw["__"+k+"_requires_new"]; ok {
|
||||||
|
attrDiff.RequiresNew = true
|
||||||
|
}
|
||||||
diff.Attributes[k] = attrDiff
|
diff.Attributes[k] = attrDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -283,6 +283,13 @@ func (n *GraphNodeConfigResource) Noop(opts *NoopOpts) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the count has any interpolations, we can't prune this node since
|
||||||
|
// we need to be sure to evaluate the count so that splat variables work
|
||||||
|
// later (which need to know the full count).
|
||||||
|
if len(n.Resource.RawCount.Interpolations) > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// If we have no module diff, we're certainly a noop. This is because
|
// If we have no module diff, we're certainly a noop. This is because
|
||||||
// it means there is a diff, and that the module we're in just isn't
|
// it means there is a diff, and that the module we're in just isn't
|
||||||
// in it, meaning we're not doing anything.
|
// in it, meaning we're not doing anything.
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
variable "c" { default = 1 }
|
||||||
|
|
||||||
|
resource "template_file" "parent" {
|
||||||
|
count = "${var.c}"
|
||||||
|
template = "Hi"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "template_file" "child" {
|
||||||
|
template = "${join(",", template_file.parent.*.template)} ok"
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
variable "c" { default = 1 }
|
||||||
|
|
||||||
|
resource "template_file" "parent" {
|
||||||
|
count = "${var.c}"
|
||||||
|
template = "Hi"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "template_file" "child" {
|
||||||
|
template = "${join(",", template_file.parent.*.template)}"
|
||||||
|
__template_requires_new = 1
|
||||||
|
}
|
Loading…
Reference in New Issue