Merge pull request #7865 from hashicorp/b-filter-untargeted-variables

terraform: Filter untargeted variable nodes
This commit is contained in:
Paul Hinze 2016-07-29 17:08:08 -05:00 committed by GitHub
commit 46b78286bc
5 changed files with 82 additions and 4 deletions

View File

@ -2114,6 +2114,43 @@ module.child:
}
}
func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) {
m := testModule(t, "plan-targeted-module-untargeted-variable")
p := testProvider("aws")
p.DiffFn = testDiffFn
ctx := testContext2(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
Targets: []string{"aws_instance.blue", "module.blue_mod"},
})
plan, err := ctx.Plan()
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(plan.String())
expected := strings.TrimSpace(`
DIFF:
CREATE: aws_instance.blue
module.blue_mod:
CREATE: aws_instance.mod
type: "" => "aws_instance"
value: "" => "<computed>"
STATE:
<no state>
`)
if actual != expected {
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
}
}
// https://github.com/hashicorp/terraform/issues/4515
func TestContext2Plan_targetedOverTen(t *testing.T) {
m := testModule(t, "plan-targeted-over-ten")

View File

@ -36,6 +36,14 @@ func (n *GraphNodeConfigVariable) DependableName() []string {
return []string{n.Name()}
}
// RemoveIfNotTargeted implements RemovableIfNotTargeted.
// When targeting is active, variables that are not targeted should be removed
// from the graph, because otherwise module variables trying to interpolate
// their references can fail when they're missing the referent resource node.
func (n *GraphNodeConfigVariable) RemoveIfNotTargeted() bool {
return true
}
func (n *GraphNodeConfigVariable) DependentOn() []string {
// If we don't have any value set, we don't depend on anything
if n.Value == nil {

View File

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

View File

@ -0,0 +1,12 @@
resource "aws_instance" "blue" { }
resource "aws_instance" "green" { }
module "blue_mod" {
source = "./child"
id = "${aws_instance.blue.id}"
}
module "green_mod" {
source = "./child"
id = "${aws_instance.green.id}"
}

View File

@ -37,11 +37,16 @@ func (t *TargetsTransformer) Transform(g *Graph) error {
}
for _, v := range g.Vertices() {
removable := false
if _, ok := v.(GraphNodeAddressable); ok {
if !targetedNodes.Include(v) {
log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
g.Remove(v)
}
removable = true
}
if vr, ok := v.(RemovableIfNotTargeted); ok {
removable = vr.RemoveIfNotTargeted()
}
if removable && !targetedNodes.Include(v) {
log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
g.Remove(v)
}
}
}
@ -110,3 +115,14 @@ func (t *TargetsTransformer) nodeIsTarget(
}
return false
}
// RemovableIfNotTargeted is a special interface for graph nodes that
// aren't directly addressable, but need to be removed from the graph when they
// are not targeted. (Nodes that are not directly targeted end up in the set of
// targeted nodes because something that _is_ targeted depends on them.) The
// initial use case for this interface is GraphNodeConfigVariable, which was
// having trouble interpolating for module variables in targeted scenarios that
// filtered out the resource node being referenced.
type RemovableIfNotTargeted interface {
RemoveIfNotTargeted() bool
}