terraform: remove pruning of module vars if they ref non-existing nodes

Fixes a shadow graph error found during usage.

The new apply graph was only adding module variables that referenced
data that existed _in the graph_. This isn't a valid optimization since
the data it is referencing may be in the state with no diff, and
therefore available but not in the graph.

This just removes that optimization logic, which causes no failing
tests. It also adds a test that exposes the bug if we had the pruning
logic.
This commit is contained in:
Mitchell Hashimoto 2016-11-04 17:47:20 -07:00
parent b7bee66df5
commit b7954a42fe
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 78 additions and 18 deletions

View File

@ -1858,6 +1858,60 @@ func TestContext2Apply_moduleProviderCloseNested(t *testing.T) {
}
}
// Tests that variables used as module vars that reference data that
// already exists in the state and requires no diff works properly. This
// fixes an issue faced where module variables were pruned because they were
// accessing "non-existent" resources (they existed, just not in the graph
// cause they weren't in the diff).
func TestContext2Apply_moduleVarRefExisting(t *testing.T) {
m := testModule(t, "apply-ref-existing")
p := testProvider("aws")
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
state := &State{
Modules: []*ModuleState{
&ModuleState{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_instance.foo": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "foo",
Attributes: map[string]string{
"foo": "bar",
},
},
},
},
},
},
}
ctx := testContext2(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
State: state,
})
if _, err := ctx.Plan(); err != nil {
t.Fatalf("err: %s", err)
}
state, err := ctx.Apply()
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContext2Apply_moduleVarResourceCount(t *testing.T) {
m := testModule(t, "apply-module-var-resource-count")
p := testProvider("aws")

View File

@ -494,6 +494,18 @@ module.child:
provider = aws.eu
`
const testTerraformApplyModuleVarRefExistingStr = `
aws_instance.foo:
ID = foo
foo = bar
module.child:
aws_instance.foo:
ID = foo
type = aws_instance
value = bar
`
const testTerraformApplyOutputOrphanStr = `
<no state>
Outputs:

View File

@ -0,0 +1,5 @@
variable "var" {}
resource "aws_instance" "foo" {
value = "${var.var}"
}

View File

@ -0,0 +1,7 @@
resource "aws_instance" "foo" { foo = "bar" }
module "child" {
source = "./child"
var = "${aws_instance.foo.foo}"
}

View File

@ -5,7 +5,6 @@ import (
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/dag"
)
// ModuleVariableTransformer is a GraphTransformer that adds all the variables
@ -68,9 +67,6 @@ func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, m *module.
return nil
}
// Build the reference map so we can determine if we're referencing things.
refMap := NewReferenceMap(g.Vertices())
// Add all variables here
for _, v := range vars {
// Determine the value of the variable. If it isn't in the
@ -100,20 +96,6 @@ func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, m *module.
Module: t.Module,
}
// If the node references something, then we check to make sure
// that the thing it references is in the graph. If it isn't, then
// we don't add it because we may not be able to compute the output.
//
// If the node references nothing, we always include it since there
// is no other clear time to compute it.
matches, missing := refMap.References(node)
if len(missing) > 0 {
log.Printf(
"[INFO] Not including %q in graph, matches: %v, missing: %s",
dag.VertexName(node), matches, missing)
continue
}
// Add it!
g.Add(node)
}