terraform: TargetsTransformer should preserve module variables

Fixes #10680

This moves TargetsTransformer to run after the transforms that add
module variables is run. This makes targeting work across modules (test
added).

This is a bug that only exists in the new graph, but was caught by a
shadow error in #10680. Tests were added to protect against regressions.
This commit is contained in:
Mitchell Hashimoto 2016-12-12 20:54:46 -08:00
parent a8c6809ec3
commit 5f1e6ad020
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
7 changed files with 115 additions and 6 deletions

View File

@ -2708,6 +2708,49 @@ func TestContext2Apply_moduleBool(t *testing.T) {
} }
} }
// Tests that a module can be targeted and everything is properly created.
// This adds to the plan test to also just verify that apply works.
func TestContext2Apply_moduleTarget(t *testing.T) {
m := testModule(t, "plan-targeted-cross-module")
p := testProvider("aws")
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
ctx := testContext2(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
Targets: []string{"module.B"},
})
if _, err := ctx.Plan(); err != nil {
t.Fatalf("err: %s", err)
}
state, err := ctx.Apply()
if err != nil {
t.Fatalf("err: %s", err)
}
checkStateString(t, state, `
<no state>
module.A:
aws_instance.foo:
ID = foo
foo = bar
type = aws_instance
Outputs:
value = foo
module.B:
aws_instance.bar:
ID = foo
foo = foo
type = aws_instance
`)
}
func TestContext2Apply_multiProvider(t *testing.T) { func TestContext2Apply_multiProvider(t *testing.T) {
m := testModule(t, "apply-multi-provider") m := testModule(t, "apply-multi-provider")
p := testProvider("aws") p := testProvider("aws")

View File

@ -2341,6 +2341,47 @@ STATE:
} }
} }
// Test that targeting a module properly plans any inputs that depend
// on another module.
func TestContext2Plan_targetedCrossModule(t *testing.T) {
m := testModule(t, "plan-targeted-cross-module")
p := testProvider("aws")
p.DiffFn = testDiffFn
ctx := testContext2(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
Targets: []string{"module.B"},
})
plan, err := ctx.Plan()
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(plan.String())
expected := strings.TrimSpace(`
DIFF:
module.A:
CREATE: aws_instance.foo
foo: "" => "bar"
type: "" => "aws_instance"
module.B:
CREATE: aws_instance.bar
foo: "" => "<computed>"
type: "" => "aws_instance"
STATE:
<no state>
`)
if actual != expected {
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
}
}
func TestContext2Plan_targetedOrphan(t *testing.T) { func TestContext2Plan_targetedOrphan(t *testing.T) {
m := testModule(t, "plan-targeted-orphan") m := testModule(t, "plan-targeted-orphan")
p := testProvider("aws") p := testProvider("aws")

View File

@ -89,6 +89,12 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
// Attach the state // Attach the state
&AttachStateTransformer{State: b.State}, &AttachStateTransformer{State: b.State},
// Add root variables
&RootVariableTransformer{Module: b.Module},
// Add module variables
&ModuleVariableTransformer{Module: b.Module},
// Connect so that the references are ready for targeting. We'll // Connect so that the references are ready for targeting. We'll
// have to connect again later for providers and so on. // have to connect again later for providers and so on.
&ReferenceTransformer{}, &ReferenceTransformer{},
@ -103,12 +109,6 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
&ParentProviderTransformer{}, &ParentProviderTransformer{},
&AttachProviderConfigTransformer{Module: b.Module}, &AttachProviderConfigTransformer{Module: b.Module},
// Add root variables
&RootVariableTransformer{Module: b.Module},
// Add module variables
&ModuleVariableTransformer{Module: b.Module},
// Connect references again to connect the providers, module variables, // Connect references again to connect the providers, module variables,
// etc. This is idempotent. // etc. This is idempotent.
&ReferenceTransformer{}, &ReferenceTransformer{},

View File

@ -37,6 +37,13 @@ func (n *NodeApplyableModuleVariable) Path() []string {
return rootModulePath return rootModulePath
} }
// RemovableIfNotTargeted
func (n *NodeApplyableModuleVariable) RemoveIfNotTargeted() bool {
// We need to add this so that this node will be removed if
// it isn't targeted or a dependency of a target.
return true
}
// GraphNodeReferenceGlobal // GraphNodeReferenceGlobal
func (n *NodeApplyableModuleVariable) ReferenceGlobal() bool { func (n *NodeApplyableModuleVariable) ReferenceGlobal() bool {
// We have to create fully qualified references because we cross // We have to create fully qualified references because we cross

View File

@ -0,0 +1,5 @@
resource "aws_instance" "foo" {
foo = "bar"
}
output "value" { value = "${aws_instance.foo.id}" }

View File

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

View File

@ -0,0 +1,8 @@
module "A" {
source = "./A"
}
module "B" {
source = "./B"
input = "${module.A.value}"
}