aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/terraform/eval_for_each.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/eval_for_each.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_for_each.go85
1 files changed, 85 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_for_each.go b/vendor/github.com/hashicorp/terraform/terraform/eval_for_each.go
new file mode 100644
index 0000000..b86bf37
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_for_each.go
@@ -0,0 +1,85 @@
1package terraform
2
3import (
4 "fmt"
5
6 "github.com/hashicorp/hcl2/hcl"
7 "github.com/hashicorp/terraform/tfdiags"
8 "github.com/zclconf/go-cty/cty"
9)
10
11// evaluateResourceForEachExpression interprets a "for_each" argument on a resource.
12//
13// Returns a cty.Value map, and diagnostics if necessary. It will return nil if
14// the expression is nil, and is used to distinguish between an unset for_each and an
15// empty map
16func evaluateResourceForEachExpression(expr hcl.Expression, ctx EvalContext) (forEach map[string]cty.Value, diags tfdiags.Diagnostics) {
17 forEachMap, known, diags := evaluateResourceForEachExpressionKnown(expr, ctx)
18 if !known {
19 // Attach a diag as we do with count, with the same downsides
20 diags = diags.Append(&hcl.Diagnostic{
21 Severity: hcl.DiagError,
22 Summary: "Invalid forEach argument",
23 Detail: `The "for_each" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the for_each depends on.`,
24 })
25 }
26 return forEachMap, diags
27}
28
29// evaluateResourceForEachExpressionKnown is like evaluateResourceForEachExpression
30// except that it handles an unknown result by returning an empty map and
31// a known = false, rather than by reporting the unknown value as an error
32// diagnostic.
33func evaluateResourceForEachExpressionKnown(expr hcl.Expression, ctx EvalContext) (forEach map[string]cty.Value, known bool, diags tfdiags.Diagnostics) {
34 if expr == nil {
35 return nil, true, nil
36 }
37
38 forEachVal, forEachDiags := ctx.EvaluateExpr(expr, cty.DynamicPseudoType, nil)
39 diags = diags.Append(forEachDiags)
40 if diags.HasErrors() {
41 return nil, true, diags
42 }
43
44 switch {
45 case forEachVal.IsNull():
46 diags = diags.Append(&hcl.Diagnostic{
47 Severity: hcl.DiagError,
48 Summary: "Invalid for_each argument",
49 Detail: `The given "for_each" argument value is unsuitable: the given "for_each" argument value is null. A map, or set of strings is allowed.`,
50 Subject: expr.Range().Ptr(),
51 })
52 return nil, true, diags
53 case !forEachVal.IsKnown():
54 return map[string]cty.Value{}, false, diags
55 }
56
57 if !forEachVal.CanIterateElements() || forEachVal.Type().IsListType() {
58 diags = diags.Append(&hcl.Diagnostic{
59 Severity: hcl.DiagError,
60 Summary: "Invalid for_each argument",
61 Detail: fmt.Sprintf(`The given "for_each" argument value is unsuitable: the "for_each" argument must be a map, or set of strings, and you have provided a value of type %s.`, forEachVal.Type().FriendlyName()),
62 Subject: expr.Range().Ptr(),
63 })
64 return nil, true, diags
65 }
66
67 if forEachVal.Type().IsSetType() {
68 if forEachVal.Type().ElementType() != cty.String {
69 diags = diags.Append(&hcl.Diagnostic{
70 Severity: hcl.DiagError,
71 Summary: "Invalid for_each set argument",
72 Detail: fmt.Sprintf(`The given "for_each" argument value is unsuitable: "for_each" supports maps and sets of strings, but you have provided a set containing type %s.`, forEachVal.Type().ElementType().FriendlyName()),
73 Subject: expr.Range().Ptr(),
74 })
75 return nil, true, diags
76 }
77 }
78
79 // If the map is empty ({}), return an empty map, because cty will return nil when representing {} AsValueMap
80 if forEachVal.LengthInt() == 0 {
81 return map[string]cty.Value{}, true, diags
82 }
83
84 return forEachVal.AsValueMap(), true, nil
85}