From 64c3a8f55091f52fc2eb043fb5fca39ac1f43557 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 2 Oct 2020 11:25:21 -0400 Subject: [PATCH] lang.Scope.EvalSelfBlock In order to properly evaluate a destroy provisioner, we cannot rely on the usual evaluation context, because the resource has already been removed from the state. EvalSelfBlock evaluates an hcl.Body in the limited scope of a single object as "self", with the added values of "count.index" and "each.key". --- lang/eval.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lang/eval.go b/lang/eval.go index db5a15a24..381ec4288 100644 --- a/lang/eval.go +++ b/lang/eval.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/instances" "github.com/hashicorp/terraform/lang/blocktoattr" "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" @@ -69,6 +70,35 @@ func (s *Scope) EvalBlock(body hcl.Body, schema *configschema.Block) (cty.Value, return val, diags } +// EvalSelfBlock evaluates the given body only within the scope of the provided +// object and instance key data. References to the object must use self, and the +// key data will only contain count.index or each.key. +func (s *Scope) EvalSelfBlock(body hcl.Body, self cty.Value, schema *configschema.Block, keyData instances.RepetitionData) (cty.Value, tfdiags.Diagnostics) { + vals := make(map[string]cty.Value) + vals["self"] = self + + if !keyData.CountIndex.IsNull() { + vals["count"] = cty.ObjectVal(map[string]cty.Value{ + "index": keyData.CountIndex, + }) + } + if !keyData.EachKey.IsNull() { + vals["each"] = cty.ObjectVal(map[string]cty.Value{ + "key": keyData.EachKey, + }) + } + + ctx := &hcl.EvalContext{ + Variables: vals, + Functions: s.Functions(), + } + + var diags tfdiags.Diagnostics + val, decDiags := hcldec.Decode(body, schema.DecoderSpec(), ctx) + diags = diags.Append(decDiags) + return val, diags +} + // EvalExpr evaluates a single expression in the receiving context and returns // the resulting value. The value will be converted to the given type before // it is returned if possible, or else an error diagnostic will be produced