Merge pull request #7865 from hashicorp/b-filter-untargeted-variables
terraform: Filter untargeted variable nodes
This commit is contained in:
commit
46b78286bc
|
@ -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")
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
variable "id" {}
|
||||
|
||||
resource "aws_instance" "mod" {
|
||||
value = "${var.id}"
|
||||
}
|
|
@ -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}"
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue