diff --git a/config/config.go b/config/config.go index fae135dec..67c4432f6 100644 --- a/config/config.go +++ b/config/config.go @@ -201,17 +201,22 @@ func (c *Config) Validate() error { // Check that all count variables are valid. for source, vs := range vars { - for _, v := range vs { - cv, ok := v.(*CountVariable) - if !ok { - continue - } - - if cv.Type == CountValueInvalid { - errs = append(errs, fmt.Errorf( - "%s: invalid count variable: %s", - source, - cv.FullKey())) + for _, rawV := range vs { + switch v := rawV.(type) { + case *CountVariable: + if v.Type == CountValueInvalid { + errs = append(errs, fmt.Errorf( + "%s: invalid count variable: %s", + source, + v.FullKey())) + } + case *PathVariable: + if v.Type == PathValueInvalid { + errs = append(errs, fmt.Errorf( + "%s: invalid path variable: %s", + source, + v.FullKey())) + } } } } diff --git a/config/config_test.go b/config/config_test.go index e4892a277..e36a7c25d 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -137,6 +137,20 @@ func TestConfigValidate_outputBadField(t *testing.T) { } } +func TestConfigValidate_pathVar(t *testing.T) { + c := testConfig(t, "validate-path-var") + if err := c.Validate(); err != nil { + t.Fatal("err: %s", err) + } +} + +func TestConfigValidate_pathVarInvalid(t *testing.T) { + c := testConfig(t, "validate-path-var-invalid") + if err := c.Validate(); err == nil { + t.Fatal("should not be valid") + } +} + func TestConfigValidate_unknownThing(t *testing.T) { c := testConfig(t, "validate-unknownthing") if err := c.Validate(); err == nil { diff --git a/config/interpolate.go b/config/interpolate.go index 4b0b30341..fc8ddea72 100644 --- a/config/interpolate.go +++ b/config/interpolate.go @@ -75,6 +75,20 @@ type ModuleVariable struct { key string } +// A PathVariable is a variable that references path information about the +// module. +type PathVariable struct { + Type PathValueType + key string +} + +type PathValueType byte + +const ( + PathValueInvalid PathValueType = iota + PathValueModule +) + // A ResourceVariable is a variable that is referencing the field // of a resource, such as "${aws_instance.foo.ami}" type ResourceVariable struct { @@ -101,6 +115,8 @@ type UserVariable struct { func NewInterpolatedVariable(v string) (InterpolatedVariable, error) { if strings.HasPrefix(v, "count.") { return NewCountVariable(v) + } else if strings.HasPrefix(v, "path.") { + return NewPathVariable(v) } else if strings.HasPrefix(v, "var.") { return NewUserVariable(v) } else if strings.HasPrefix(v, "module.") { @@ -206,6 +222,24 @@ func (v *ModuleVariable) FullKey() string { return v.key } +func NewPathVariable(key string) (*PathVariable, error) { + var fieldType PathValueType + parts := strings.SplitN(key, ".", 2) + switch parts[1] { + case "module": + fieldType = PathValueModule + } + + return &PathVariable{ + Type: fieldType, + key: key, + }, nil +} + +func (v *PathVariable) FullKey() string { + return v.key +} + func NewResourceVariable(key string) (*ResourceVariable, error) { parts := strings.SplitN(key, ".", 3) if len(parts) < 3 { diff --git a/config/interpolate_test.go b/config/interpolate_test.go index 3c4bf7f9a..9ecbb9a71 100644 --- a/config/interpolate_test.go +++ b/config/interpolate_test.go @@ -45,6 +45,14 @@ func TestNewInterpolatedVariable(t *testing.T) { }, false, }, + { + "path.module", + &PathVariable{ + Type: PathValueModule, + key: "path.module", + }, + false, + }, } for i, tc := range cases { diff --git a/config/test-fixtures/validate-path-var-invalid/main.tf b/config/test-fixtures/validate-path-var-invalid/main.tf new file mode 100644 index 000000000..63c352d98 --- /dev/null +++ b/config/test-fixtures/validate-path-var-invalid/main.tf @@ -0,0 +1,3 @@ +resource "aws_instance" "foo" { + foo = "${path.nope}" +} diff --git a/config/test-fixtures/validate-path-var/main.tf b/config/test-fixtures/validate-path-var/main.tf new file mode 100644 index 000000000..1c723ca18 --- /dev/null +++ b/config/test-fixtures/validate-path-var/main.tf @@ -0,0 +1,3 @@ +resource "aws_instance" "foo" { + foo = "${path.module}" +}