diff --git a/config/config.go b/config/config.go index 54ecd4920..ac6749a31 100644 --- a/config/config.go +++ b/config/config.go @@ -586,43 +586,55 @@ func (c *Config) Validate() error { } // Check that all outputs are valid - for _, o := range c.Outputs { - var invalidKeys []string - valueKeyFound := false - for k := range o.RawConfig.Raw { - if k == "value" { - valueKeyFound = true - continue - } - if k == "sensitive" { - if sensitive, ok := o.RawConfig.config[k].(bool); ok { - if sensitive { - o.Sensitive = true - } - continue - } - + { + found := make(map[string]struct{}) + for _, o := range c.Outputs { + // Verify the output is new + if _, ok := found[o.Name]; ok { errs = append(errs, fmt.Errorf( - "%s: value for 'sensitive' must be boolean", + "%s: duplicate output. output names must be unique.", o.Name)) continue } - invalidKeys = append(invalidKeys, k) - } - if len(invalidKeys) > 0 { - errs = append(errs, fmt.Errorf( - "%s: output has invalid keys: %s", - o.Name, strings.Join(invalidKeys, ", "))) - } - if !valueKeyFound { - errs = append(errs, fmt.Errorf( - "%s: output is missing required 'value' key", o.Name)) - } + found[o.Name] = struct{}{} - for _, v := range o.RawConfig.Variables { - if _, ok := v.(*CountVariable); ok { + var invalidKeys []string + valueKeyFound := false + for k := range o.RawConfig.Raw { + if k == "value" { + valueKeyFound = true + continue + } + if k == "sensitive" { + if sensitive, ok := o.RawConfig.config[k].(bool); ok { + if sensitive { + o.Sensitive = true + } + continue + } + + errs = append(errs, fmt.Errorf( + "%s: value for 'sensitive' must be boolean", + o.Name)) + continue + } + invalidKeys = append(invalidKeys, k) + } + if len(invalidKeys) > 0 { errs = append(errs, fmt.Errorf( - "%s: count variables are only valid within resources", o.Name)) + "%s: output has invalid keys: %s", + o.Name, strings.Join(invalidKeys, ", "))) + } + if !valueKeyFound { + errs = append(errs, fmt.Errorf( + "%s: output is missing required 'value' key", o.Name)) + } + + for _, v := range o.RawConfig.Variables { + if _, ok := v.(*CountVariable); ok { + errs = append(errs, fmt.Errorf( + "%s: count variables are only valid within resources", o.Name)) + } } } } diff --git a/config/config_test.go b/config/config_test.go index 41690733d..81bd11b23 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -300,6 +300,13 @@ func TestConfigValidate_outputBadField(t *testing.T) { } } +func TestConfigValidate_outputDuplicate(t *testing.T) { + c := testConfig(t, "validate-output-dup") + if err := c.Validate(); err == nil { + t.Fatal("should not be valid") + } +} + func TestConfigValidate_pathVar(t *testing.T) { c := testConfig(t, "validate-path-var") if err := c.Validate(); err != nil { diff --git a/config/test-fixtures/validate-output-dup/main.tf b/config/test-fixtures/validate-output-dup/main.tf new file mode 100644 index 000000000..10b598f8a --- /dev/null +++ b/config/test-fixtures/validate-output-dup/main.tf @@ -0,0 +1,10 @@ +resource "aws_instance" "web" { +} + +output "ip" { + value = "foo" +} + +output "ip" { + value = "bar" +}