diff --git a/config/config.go b/config/config.go index 0a538449e..7469052a9 100644 --- a/config/config.go +++ b/config/config.go @@ -385,6 +385,40 @@ func (c *Config) Validate() error { n, d)) } } + + // Verify provisioners don't contain any splats + for _, p := range r.Provisioners { + // This validation checks that there are now splat variables + // referencing ourself. This currently is not allowed. + + for _, v := range p.ConnInfo.Variables { + rv, ok := v.(*ResourceVariable) + if !ok { + continue + } + + if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name { + errs = append(errs, fmt.Errorf( + "%s: connection info cannot contain splat variable "+ + "referencing itself", n)) + break + } + } + + for _, v := range p.RawConfig.Variables { + rv, ok := v.(*ResourceVariable) + if !ok { + continue + } + + if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name { + errs = append(errs, fmt.Errorf( + "%s: connection info cannot contain splat variable "+ + "referencing itself", n)) + break + } + } + } } for source, vs := range vars { diff --git a/config/config_test.go b/config/config_test.go index 5586f60f1..d49d9cdac 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -179,6 +179,34 @@ func TestConfigValidate_pathVarInvalid(t *testing.T) { } } +func TestConfigValidate_provConnSplatOther(t *testing.T) { + c := testConfig(t, "validate-prov-conn-splat-other") + if err := c.Validate(); err != nil { + t.Fatalf("should be valid: %s", err) + } +} + +func TestConfigValidate_provConnSplatSelf(t *testing.T) { + c := testConfig(t, "validate-prov-conn-splat-self") + if err := c.Validate(); err == nil { + t.Fatal("should not be valid") + } +} + +func TestConfigValidate_provSplatOther(t *testing.T) { + c := testConfig(t, "validate-prov-splat-other") + if err := c.Validate(); err != nil { + t.Fatalf("should be valid: %s", err) + } +} + +func TestConfigValidate_provSplatSelf(t *testing.T) { + c := testConfig(t, "validate-prov-splat-self") + 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/test-fixtures/validate-prov-conn-splat-other/main.tf b/config/test-fixtures/validate-prov-conn-splat-other/main.tf new file mode 100644 index 000000000..1abb2cc47 --- /dev/null +++ b/config/test-fixtures/validate-prov-conn-splat-other/main.tf @@ -0,0 +1,9 @@ +resource "aws_instance" "foo" {} + +resource "aws_instance" "bar" { + connection { + host = "${element(aws_instance.foo.*.private_ip, 0)}" + } + + provisioner "local-exec" {} +} diff --git a/config/test-fixtures/validate-prov-conn-splat-self/main.tf b/config/test-fixtures/validate-prov-conn-splat-self/main.tf new file mode 100644 index 000000000..9ebb5198a --- /dev/null +++ b/config/test-fixtures/validate-prov-conn-splat-self/main.tf @@ -0,0 +1,7 @@ +resource "aws_instance" "bar" { + connection { + host = "${element(aws_instance.bar.*.private_ip, 0)}" + } + + provisioner "local-exec" {} +} diff --git a/config/test-fixtures/validate-prov-splat-other/main.tf b/config/test-fixtures/validate-prov-splat-other/main.tf new file mode 100644 index 000000000..b24b3284f --- /dev/null +++ b/config/test-fixtures/validate-prov-splat-other/main.tf @@ -0,0 +1,7 @@ +resource "aws_instance" "foo" {} + +resource "aws_instance" "bar" { + provisioner "local-exec" { + command = "${element(aws_instance.foo.*.private_ip, 0)}" + } +} diff --git a/config/test-fixtures/validate-prov-splat-self/main.tf b/config/test-fixtures/validate-prov-splat-self/main.tf new file mode 100644 index 000000000..0f82865e6 --- /dev/null +++ b/config/test-fixtures/validate-prov-splat-self/main.tf @@ -0,0 +1,7 @@ +resource "aws_instance" "foo" {} + +resource "aws_instance" "bar" { + provisioner "local-exec" { + command = "${element(aws_instance.bar.*.private_ip, 0)}" + } +}