diff --git a/lang/eval.go b/lang/eval.go index 989105f12..bfacd671a 100644 --- a/lang/eval.go +++ b/lang/eval.go @@ -240,15 +240,19 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl // Self is an exception in that it must always resolve to a // particular instance. We will still insert the full resource into // the context below. + var hclDiags hcl.Diagnostics + // We should always have a valid self index by this point, but in + // the case of an error, self may end up as a cty.DynamicValue. switch k := subj.Key.(type) { case addrs.IntKey: - self = val.Index(cty.NumberIntVal(int64(k))) + self, hclDiags = hcl.Index(val, cty.NumberIntVal(int64(k)), ref.SourceRange.ToHCL().Ptr()) + diags.Append(hclDiags) case addrs.StringKey: - self = val.Index(cty.StringVal(string(k))) + self, hclDiags = hcl.Index(val, cty.StringVal(string(k)), ref.SourceRange.ToHCL().Ptr()) + diags.Append(hclDiags) default: self = val } - continue } diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 902e0dd5a..98e60ae26 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -6137,6 +6137,44 @@ func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) { } } +func TestContext2Apply_provisionerForEachSelfRef(t *testing.T) { + m := testModule(t, "apply-provisioner-for-each-self") + p := testProvider("aws") + pr := testProvisioner() + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + + pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { + val, ok := c.Config["command"] + if !ok { + t.Fatalf("bad value for command: %v %#v", val, c) + } + + return nil + } + + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[string]providers.Factory{ + "aws": testProviderFuncFixed(p), + }, + ), + Provisioners: map[string]ProvisionerFactory{ + "shell": testProvisionerFuncFixed(pr), + }, + }) + + if _, diags := ctx.Plan(); diags.HasErrors() { + t.Fatalf("plan errors: %s", diags.Err()) + } + + _, diags := ctx.Apply() + if diags.HasErrors() { + t.Fatalf("diags: %s", diags.Err()) + } +} + // Provisioner should NOT run on a diff, only create func TestContext2Apply_Provisioner_Diff(t *testing.T) { m := testModule(t, "apply-provisioner-diff") diff --git a/terraform/testdata/apply-provisioner-for-each-self/main.tf b/terraform/testdata/apply-provisioner-for-each-self/main.tf new file mode 100644 index 000000000..f3e1d58df --- /dev/null +++ b/terraform/testdata/apply-provisioner-for-each-self/main.tf @@ -0,0 +1,8 @@ +resource "aws_instance" "foo" { + for_each = toset(["a", "b", "c"]) + foo = "number ${each.value}" + + provisioner "shell" { + command = "${self.foo}" + } +}