Merge pull request #5302 from hashicorp/b-5254

terraform: don't prune resource if count has interpolations
This commit is contained in:
James Nugent 2016-02-24 12:17:35 -05:00
commit 242f088309
5 changed files with 121 additions and 0 deletions

View File

@ -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)
}
*/
}

View File

@ -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
} }

View File

@ -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.

View File

@ -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"
}

View File

@ -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
}