diff --git a/config/config.go b/config/config.go index 3c8f8826d..79367b6f9 100644 --- a/config/config.go +++ b/config/config.go @@ -508,25 +508,8 @@ func (c *Config) Validate() error { } r.RawCount.init() - // Verify depends on points to resources that all exist - for _, d := range r.DependsOn { - // Check if we contain interpolations - rc, err := NewRawConfig(map[string]interface{}{ - "value": d, - }) - if err == nil && len(rc.Variables) > 0 { - errs = append(errs, fmt.Errorf( - "%s: depends on value cannot contain interpolations: %s", - n, d)) - continue - } - - if _, ok := resources[d]; !ok { - errs = append(errs, fmt.Errorf( - "%s: resource depends on non-existent resource '%s'", - n, d)) - } - } + // Validate DependsOn + errs = append(errs, c.validateDependsOn(n, r.DependsOn, resources, modules)...) // Verify provider points to a provider that is configured if r.Provider != "" { @@ -801,6 +784,48 @@ func (c *Config) validateVarContextFn( } } +func (c *Config) validateDependsOn( + n string, + v []string, + resources map[string]*Resource, + modules map[string]*Module) []error { + // Verify depends on points to resources that all exist + var errs []error + for _, d := range v { + // Check if we contain interpolations + rc, err := NewRawConfig(map[string]interface{}{ + "value": d, + }) + if err == nil && len(rc.Variables) > 0 { + errs = append(errs, fmt.Errorf( + "%s: depends on value cannot contain interpolations: %s", + n, d)) + continue + } + + // If it is a module, verify it is a module + if strings.HasPrefix(d, "module.") { + name := d[len("module."):] + if _, ok := modules[name]; !ok { + errs = append(errs, fmt.Errorf( + "%s: resource depends on non-existent module '%s'", + n, name)) + } + + continue + } + + // Check resources + if _, ok := resources[d]; !ok { + errs = append(errs, fmt.Errorf( + "%s: resource depends on non-existent resource '%s'", + n, d)) + } + } + + return errs +} + func (m *Module) mergerName() string { return m.Id() } diff --git a/config/config_test.go b/config/config_test.go index 7c7776b94..8018739c7 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -2,6 +2,7 @@ package config import ( "flag" + "fmt" "io/ioutil" "log" "os" @@ -130,11 +131,55 @@ func TestConfig_emptyCollections(t *testing.T) { } } -func TestConfigValidate(t *testing.T) { - c := testConfig(t, "validate-good") - if err := c.Validate(); err != nil { - t.Fatalf("err: %s", err) +// This table test is the preferred way to test validation of configuration. +// There are dozens of functions below which do not follow this that are +// there mostly historically. They should be converted at some point. +func TestConfigValidate_table(t *testing.T) { + cases := []struct { + Name string + Fixture string + Err bool + ErrString string + }{ + { + "basic good", + "validate-good", + false, + "", + }, + + { + "depends on module", + "validate-depends-on-module", + false, + "", + }, + + { + "depends on non-existent module", + "validate-depends-on-bad-module", + true, + "non-existent module 'foo'", + }, } + + for i, tc := range cases { + t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) { + c := testConfig(t, tc.Fixture) + err := c.Validate() + if (err != nil) != tc.Err { + t.Fatalf("err: %s", err) + } + if err != nil { + if tc.ErrString != "" && !strings.Contains(err.Error(), tc.ErrString) { + t.Fatalf("expected err to contain: %s\n\ngot: %s", tc.ErrString, err) + } + + return + } + }) + } + } func TestConfigValidate_badDependsOn(t *testing.T) { diff --git a/config/test-fixtures/validate-depends-on-bad-module/main.tf b/config/test-fixtures/validate-depends-on-bad-module/main.tf new file mode 100644 index 000000000..5fbe75ad9 --- /dev/null +++ b/config/test-fixtures/validate-depends-on-bad-module/main.tf @@ -0,0 +1,7 @@ +module "child" { + source = "./child" +} + +resource aws_instance "web" { + depends_on = ["module.foo"] +} diff --git a/config/test-fixtures/validate-depends-on-module/main.tf b/config/test-fixtures/validate-depends-on-module/main.tf new file mode 100644 index 000000000..73f50def8 --- /dev/null +++ b/config/test-fixtures/validate-depends-on-module/main.tf @@ -0,0 +1,7 @@ +module "child" { + source = "./child" +} + +resource aws_instance "web" { + depends_on = ["module.child"] +}