diff --git a/config/config.go b/config/config.go index e0733081f5..b4b405107e 100644 --- a/config/config.go +++ b/config/config.go @@ -127,7 +127,7 @@ func (c *Config) Validate() error { "Unknown root level key: %s", k)) } - vars := c.allVariables() + vars := c.InterpolatedVariables() varMap := make(map[string]*Variable) for _, v := range c.Variables { varMap[v.Name] = v @@ -302,10 +302,10 @@ func (c *Config) Validate() error { return nil } -// allVariables is a helper that returns a mapping of all the interpolated +// InterpolatedVariables is a helper that returns a mapping of all the interpolated // variables within the configuration. This is used to verify references // are valid in the Validate step. -func (c *Config) allVariables() map[string][]InterpolatedVariable { +func (c *Config) InterpolatedVariables() map[string][]InterpolatedVariable { result := make(map[string][]InterpolatedVariable) for _, pc := range c.ProviderConfigs { source := fmt.Sprintf("provider config '%s'", pc.Name) diff --git a/config/module/test-fixtures/validate-bad-output/child/main.tf b/config/module/test-fixtures/validate-bad-output/child/main.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/config/module/test-fixtures/validate-bad-output/main.tf b/config/module/test-fixtures/validate-bad-output/main.tf new file mode 100644 index 0000000000..a19233e12d --- /dev/null +++ b/config/module/test-fixtures/validate-bad-output/main.tf @@ -0,0 +1,7 @@ +module "child" { + source = "./child" +} + +resource "aws_instance" "foo" { + memory = "${module.child.memory}" +} diff --git a/config/module/test-fixtures/validate-child-good/child/main.tf b/config/module/test-fixtures/validate-child-good/child/main.tf index 618ae3c42e..2cfd2a80f5 100644 --- a/config/module/test-fixtures/validate-child-good/child/main.tf +++ b/config/module/test-fixtures/validate-child-good/child/main.tf @@ -1 +1,3 @@ variable "memory" {} + +output "result" {} diff --git a/config/module/test-fixtures/validate-child-good/main.tf b/config/module/test-fixtures/validate-child-good/main.tf index 7c70782f1b..5f3ad8da5b 100644 --- a/config/module/test-fixtures/validate-child-good/main.tf +++ b/config/module/test-fixtures/validate-child-good/main.tf @@ -2,3 +2,7 @@ module "child" { source = "./child" memory = "1G" } + +resource "aws_instance" "foo" { + memory = "${module.child.result}" +} diff --git a/config/module/tree.go b/config/module/tree.go index 867f812c84..ed1b2b3dea 100644 --- a/config/module/tree.go +++ b/config/module/tree.go @@ -267,6 +267,37 @@ func (t *Tree) Validate() error { } } + // Go over all the variables used and make sure that any module + // variables represent outputs properly. + for source, vs := range t.config.InterpolatedVariables() { + for _, v := range vs { + mv, ok := v.(*config.ModuleVariable) + if !ok { + continue + } + + tree, ok := children[mv.Name] + if !ok { + // This should never happen because Load watches us + panic("module not found in children: " + mv.Name) + } + + found := false + for _, o := range tree.config.Outputs { + if o.Name == mv.Field { + found = true + break + } + } + if !found { + newErr.Err = fmt.Errorf( + "%s: %s is not a valid output for module %s", + source, mv.Field, mv.Name) + return newErr + } + } + } + return nil } diff --git a/config/module/tree_test.go b/config/module/tree_test.go index 3fbad23d73..d2fc41a5e9 100644 --- a/config/module/tree_test.go +++ b/config/module/tree_test.go @@ -92,6 +92,18 @@ func TestTreeValidate_badChild(t *testing.T) { } } +func TestTreeValidate_badChildOutput(t *testing.T) { + tree := NewTree(testConfig(t, "validate-bad-output")) + + if err := tree.Load(testStorage(t), GetModeGet); err != nil { + t.Fatalf("err: %s", err) + } + + if err := tree.Validate(); err == nil { + t.Fatal("should error") + } +} + func TestTreeValidate_badChildVar(t *testing.T) { tree := NewTree(testConfig(t, "validate-bad-var"))