diff --git a/config/config.go b/config/config.go index 261c9c4ac..d356d9f42 100644 --- a/config/config.go +++ b/config/config.go @@ -239,34 +239,54 @@ func (c *Config) Validate() error { "%s: module repeated multiple times", m.Id())) } - } - if _, ok := modules[m.Id()]; !ok { - // If we haven't seen this module before, check that the - // source has no interpolations. - rc, err := NewRawConfig(map[string]interface{}{ - "root": m.Source, - }) - if err != nil { - errs = append(errs, fmt.Errorf( - "%s: module source error: %s", - m.Id(), err)) - } else if len(rc.Interpolations) > 0 { - errs = append(errs, fmt.Errorf( - "%s: module source cannot contain interpolations", - m.Id())) - } - - // Check that the name matches our regexp - if !NameRegexp.Match([]byte(m.Name)) { - errs = append(errs, fmt.Errorf( - "%s: module name can only contain letters, numbers, "+ - "dashes, and underscores", - m.Id())) - } + // Already seen this module, just skip it + continue } modules[m.Id()] = m + + // Check that the source has no interpolations + rc, err := NewRawConfig(map[string]interface{}{ + "root": m.Source, + }) + if err != nil { + errs = append(errs, fmt.Errorf( + "%s: module source error: %s", + m.Id(), err)) + } else if len(rc.Interpolations) > 0 { + errs = append(errs, fmt.Errorf( + "%s: module source cannot contain interpolations", + m.Id())) + } + + // Check that the name matches our regexp + if !NameRegexp.Match([]byte(m.Name)) { + errs = append(errs, fmt.Errorf( + "%s: module name can only contain letters, numbers, "+ + "dashes, and underscores", + m.Id())) + } + + // Check that the configuration can all be strings + raw := make(map[string]interface{}) + for k, v := range m.RawConfig.Raw { + var strVal string + if err := mapstructure.WeakDecode(v, &strVal); err != nil { + errs = append(errs, fmt.Errorf( + "%s: variable %s must be a string value", + m.Id(), k)) + } + raw[k] = strVal + } + + // Update the raw configuration to only contain the string values + m.RawConfig, err = NewRawConfig(raw) + if err != nil { + errs = append(errs, fmt.Errorf( + "%s: can't initialize configuration: %s", + m.Id(), err)) + } } dupped = nil diff --git a/config/config_test.go b/config/config_test.go index 7b7348fd9..41ca569e3 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -137,6 +137,20 @@ func TestConfigValidate_moduleSourceVar(t *testing.T) { } } +func TestConfigValidate_moduleVarInt(t *testing.T) { + c := testConfig(t, "validate-module-var-int") + if err := c.Validate(); err != nil { + t.Fatalf("should be valid: %s", err) + } +} + +func TestConfigValidate_moduleVarMap(t *testing.T) { + c := testConfig(t, "validate-module-var-map") + if err := c.Validate(); err == nil { + t.Fatal("should be invalid") + } +} + func TestConfigValidate_nil(t *testing.T) { var c Config if err := c.Validate(); err != nil { diff --git a/config/test-fixtures/validate-module-var-int/main.tf b/config/test-fixtures/validate-module-var-int/main.tf new file mode 100644 index 000000000..4ee76d8bc --- /dev/null +++ b/config/test-fixtures/validate-module-var-int/main.tf @@ -0,0 +1,4 @@ +module "foo" { + source = "./foo" + nodes = 3 +} diff --git a/config/test-fixtures/validate-module-var-map/main.tf b/config/test-fixtures/validate-module-var-map/main.tf new file mode 100644 index 000000000..e3a97b7de --- /dev/null +++ b/config/test-fixtures/validate-module-var-map/main.tf @@ -0,0 +1,4 @@ +module "foo" { + source = "./foo" + nodes = [1,2,3] +} diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 5373894b9..cede986f8 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -932,6 +932,19 @@ STATE: ` +const testTerraformPlanModuleVarIntStr = ` +DIFF: + +module.child: + CREATE: aws_instance.foo + num: "" => "2" + type: "" => "aws_instance" + +STATE: + + +` + const testTerraformPlanOrphanStr = ` DIFF: