Merge pull request #10690 from hashicorp/b-x-module-target

terraform: TargetsTransformer should preserve module variables
This commit is contained in:
Mitchell Hashimoto 2016-12-13 08:31:28 -08:00 committed by GitHub
commit 47e756cd97
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) {
m := testModule(t, "apply-multi-provider")
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) {
m := testModule(t, "plan-targeted-orphan")
p := testProvider("aws")

View File

@ -89,6 +89,12 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
// Attach the 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
// have to connect again later for providers and so on.
&ReferenceTransformer{},
@ -103,12 +109,6 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
&ParentProviderTransformer{},
&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,
// etc. This is idempotent.
&ReferenceTransformer{},

View File

@ -37,6 +37,13 @@ func (n *NodeApplyableModuleVariable) Path() []string {
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
func (n *NodeApplyableModuleVariable) ReferenceGlobal() bool {
// 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}"
}