aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/terraform
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform')
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/diff.go13
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_apply.go6
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_diff.go26
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_for_each.go85
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_read_data.go14
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_refresh.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_state.go14
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_validate.go52
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_variable.go3
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/evaluate.go53
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/interpolate.go13
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_data_refresh.go12
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_resource_abstract.go40
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_resource_apply_instance.go15
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_resource_plan.go11
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_resource_plan_instance.go15
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go7
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_resource_validate.go12
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/provider_mock.go3
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/resource_address.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/state.go4
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/transform_orphan_count.go31
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/transform_resource_count.go21
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/util.go6
24 files changed, 357 insertions, 103 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/diff.go b/vendor/github.com/hashicorp/terraform/terraform/diff.go
index 7a6ef3d..323462f 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/diff.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/diff.go
@@ -13,7 +13,6 @@ import (
13 "sync" 13 "sync"
14 14
15 "github.com/hashicorp/terraform/addrs" 15 "github.com/hashicorp/terraform/addrs"
16 "github.com/hashicorp/terraform/config"
17 "github.com/hashicorp/terraform/config/hcl2shim" 16 "github.com/hashicorp/terraform/config/hcl2shim"
18 "github.com/hashicorp/terraform/configs/configschema" 17 "github.com/hashicorp/terraform/configs/configschema"
19 "github.com/zclconf/go-cty/cty" 18 "github.com/zclconf/go-cty/cty"
@@ -665,7 +664,7 @@ func (d *InstanceDiff) applySingleAttrDiff(path []string, attrs map[string]strin
665 old, exists := attrs[currentKey] 664 old, exists := attrs[currentKey]
666 665
667 if diff != nil && diff.NewComputed { 666 if diff != nil && diff.NewComputed {
668 result[attr] = config.UnknownVariableValue 667 result[attr] = hcl2shim.UnknownVariableValue
669 return result, nil 668 return result, nil
670 } 669 }
671 670
@@ -673,7 +672,7 @@ func (d *InstanceDiff) applySingleAttrDiff(path []string, attrs map[string]strin
673 // This only applied to top-level "id" fields. 672 // This only applied to top-level "id" fields.
674 if attr == "id" && len(path) == 1 { 673 if attr == "id" && len(path) == 1 {
675 if old == "" { 674 if old == "" {
676 result[attr] = config.UnknownVariableValue 675 result[attr] = hcl2shim.UnknownVariableValue
677 } else { 676 } else {
678 result[attr] = old 677 result[attr] = old
679 } 678 }
@@ -704,8 +703,8 @@ func (d *InstanceDiff) applySingleAttrDiff(path []string, attrs map[string]strin
704 // check for missmatched diff values 703 // check for missmatched diff values
705 if exists && 704 if exists &&
706 old != diff.Old && 705 old != diff.Old &&
707 old != config.UnknownVariableValue && 706 old != hcl2shim.UnknownVariableValue &&
708 diff.Old != config.UnknownVariableValue { 707 diff.Old != hcl2shim.UnknownVariableValue {
709 return result, fmt.Errorf("diff apply conflict for %s: diff expects %q, but prior value has %q", attr, diff.Old, old) 708 return result, fmt.Errorf("diff apply conflict for %s: diff expects %q, but prior value has %q", attr, diff.Old, old)
710 } 709 }
711 710
@@ -723,7 +722,7 @@ func (d *InstanceDiff) applySingleAttrDiff(path []string, attrs map[string]strin
723 } 722 }
724 723
725 if attrSchema.Computed && diff.NewComputed { 724 if attrSchema.Computed && diff.NewComputed {
726 result[attr] = config.UnknownVariableValue 725 result[attr] = hcl2shim.UnknownVariableValue
727 return result, nil 726 return result, nil
728 } 727 }
729 728
@@ -756,7 +755,7 @@ func (d *InstanceDiff) applyCollectionDiff(path []string, attrs map[string]strin
756 } 755 }
757 756
758 if diff.NewComputed { 757 if diff.NewComputed {
759 result[k[len(prefix):]] = config.UnknownVariableValue 758 result[k[len(prefix):]] = hcl2shim.UnknownVariableValue
760 return result, nil 759 return result, nil
761 } 760 }
762 761
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go b/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go
index 09313f7..422f372 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go
@@ -61,7 +61,8 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
61 configVal := cty.NullVal(cty.DynamicPseudoType) 61 configVal := cty.NullVal(cty.DynamicPseudoType)
62 if n.Config != nil { 62 if n.Config != nil {
63 var configDiags tfdiags.Diagnostics 63 var configDiags tfdiags.Diagnostics
64 keyData := EvalDataForInstanceKey(n.Addr.Key) 64 forEach, _ := evaluateResourceForEachExpression(n.Config.ForEach, ctx)
65 keyData := EvalDataForInstanceKey(n.Addr.Key, forEach)
65 configVal, _, configDiags = ctx.EvaluateBlock(n.Config.Config, schema, nil, keyData) 66 configVal, _, configDiags = ctx.EvaluateBlock(n.Config.Config, schema, nil, keyData)
66 diags = diags.Append(configDiags) 67 diags = diags.Append(configDiags)
67 if configDiags.HasErrors() { 68 if configDiags.HasErrors() {
@@ -548,7 +549,8 @@ func (n *EvalApplyProvisioners) apply(ctx EvalContext, provs []*configs.Provisio
548 provisioner := ctx.Provisioner(prov.Type) 549 provisioner := ctx.Provisioner(prov.Type)
549 schema := ctx.ProvisionerSchema(prov.Type) 550 schema := ctx.ProvisionerSchema(prov.Type)
550 551
551 keyData := EvalDataForInstanceKey(instanceAddr.Key) 552 // TODO the for_each val is not added here, which might causes issues with provisioners
553 keyData := EvalDataForInstanceKey(instanceAddr.Key, nil)
552 554
553 // Evaluate the main provisioner configuration. 555 // Evaluate the main provisioner configuration.
554 config, _, configDiags := ctx.EvaluateBlock(prov.Config, schema, instanceAddr, keyData) 556 config, _, configDiags := ctx.EvaluateBlock(prov.Config, schema, instanceAddr, keyData)
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go b/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go
index b7acfb0..695b5fe 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go
@@ -4,7 +4,6 @@ import (
4 "bytes" 4 "bytes"
5 "fmt" 5 "fmt"
6 "log" 6 "log"
7 "reflect"
8 "strings" 7 "strings"
9 8
10 "github.com/hashicorp/hcl2/hcl" 9 "github.com/hashicorp/hcl2/hcl"
@@ -134,7 +133,8 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
134 // Should be caught during validation, so we don't bother with a pretty error here 133 // Should be caught during validation, so we don't bother with a pretty error here
135 return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type) 134 return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type)
136 } 135 }
137 keyData := EvalDataForInstanceKey(n.Addr.Key) 136 forEach, _ := evaluateResourceForEachExpression(n.Config.ForEach, ctx)
137 keyData := EvalDataForInstanceKey(n.Addr.Key, forEach)
138 configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData) 138 configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
139 diags = diags.Append(configDiags) 139 diags = diags.Append(configDiags)
140 if configDiags.HasErrors() { 140 if configDiags.HasErrors() {
@@ -174,6 +174,20 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
174 } 174 }
175 } 175 }
176 176
177 log.Printf("[TRACE] Re-validating config for %q", n.Addr.Absolute(ctx.Path()))
178 // Allow the provider to validate the final set of values.
179 // The config was statically validated early on, but there may have been
180 // unknown values which the provider could not validate at the time.
181 validateResp := provider.ValidateResourceTypeConfig(
182 providers.ValidateResourceTypeConfigRequest{
183 TypeName: n.Addr.Resource.Type,
184 Config: configVal,
185 },
186 )
187 if validateResp.Diagnostics.HasErrors() {
188 return nil, validateResp.Diagnostics.InConfigBody(config.Config).Err()
189 }
190
177 // The provider gets an opportunity to customize the proposed new value, 191 // The provider gets an opportunity to customize the proposed new value,
178 // which in turn produces the _planned_ new value. 192 // which in turn produces the _planned_ new value.
179 resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{ 193 resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{
@@ -448,8 +462,9 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
448 // must _also_ record the returned change in the active plan, 462 // must _also_ record the returned change in the active plan,
449 // which the expression evaluator will use in preference to this 463 // which the expression evaluator will use in preference to this
450 // incomplete value recorded in the state. 464 // incomplete value recorded in the state.
451 Status: states.ObjectPlanned, 465 Status: states.ObjectPlanned,
452 Value: plannedNewVal, 466 Value: plannedNewVal,
467 Private: plannedPrivate,
453 } 468 }
454 } 469 }
455 470
@@ -517,7 +532,7 @@ func processIgnoreChangesIndividual(prior, proposed cty.Value, ignoreChanges []h
517 // away any deeper values we already produced at that point. 532 // away any deeper values we already produced at that point.
518 var ignoreTraversal hcl.Traversal 533 var ignoreTraversal hcl.Traversal
519 for i, candidate := range ignoreChangesPath { 534 for i, candidate := range ignoreChangesPath {
520 if reflect.DeepEqual(path, candidate) { 535 if path.Equals(candidate) {
521 ignoreTraversal = ignoreChanges[i] 536 ignoreTraversal = ignoreChanges[i]
522 } 537 }
523 } 538 }
@@ -790,6 +805,7 @@ func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) {
790 Before: state.Value, 805 Before: state.Value,
791 After: cty.NullVal(cty.DynamicPseudoType), 806 After: cty.NullVal(cty.DynamicPseudoType),
792 }, 807 },
808 Private: state.Private,
793 ProviderAddr: n.ProviderAddr, 809 ProviderAddr: n.ProviderAddr,
794 } 810 }
795 811
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}
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_read_data.go b/vendor/github.com/hashicorp/terraform/terraform/eval_read_data.go
index 34f2d60..4999480 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/eval_read_data.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_read_data.go
@@ -95,7 +95,8 @@ func (n *EvalReadData) Eval(ctx EvalContext) (interface{}, error) {
95 objTy := schema.ImpliedType() 95 objTy := schema.ImpliedType()
96 priorVal := cty.NullVal(objTy) // for data resources, prior is always null because we start fresh every time 96 priorVal := cty.NullVal(objTy) // for data resources, prior is always null because we start fresh every time
97 97
98 keyData := EvalDataForInstanceKey(n.Addr.Key) 98 forEach, _ := evaluateResourceForEachExpression(n.Config.ForEach, ctx)
99 keyData := EvalDataForInstanceKey(n.Addr.Key, forEach)
99 100
100 var configDiags tfdiags.Diagnostics 101 var configDiags tfdiags.Diagnostics
101 configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, keyData) 102 configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, keyData)
@@ -179,6 +180,17 @@ func (n *EvalReadData) Eval(ctx EvalContext) (interface{}, error) {
179 ) 180 )
180 } 181 }
181 182
183 log.Printf("[TRACE] Re-validating config for %s", absAddr)
184 validateResp := provider.ValidateDataSourceConfig(
185 providers.ValidateDataSourceConfigRequest{
186 TypeName: n.Addr.Resource.Type,
187 Config: configVal,
188 },
189 )
190 if validateResp.Diagnostics.HasErrors() {
191 return nil, validateResp.Diagnostics.InConfigBody(n.Config.Config).Err()
192 }
193
182 // If we get down here then our configuration is complete and we're read 194 // If we get down here then our configuration is complete and we're read
183 // to actually call the provider to read the data. 195 // to actually call the provider to read the data.
184 log.Printf("[TRACE] EvalReadData: %s configuration is complete, so reading from provider", absAddr) 196 log.Printf("[TRACE] EvalReadData: %s configuration is complete, so reading from provider", absAddr)
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_refresh.go b/vendor/github.com/hashicorp/terraform/terraform/eval_refresh.go
index 03bc948..4dfb5b4 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/eval_refresh.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_refresh.go
@@ -55,6 +55,7 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
55 req := providers.ReadResourceRequest{ 55 req := providers.ReadResourceRequest{
56 TypeName: n.Addr.Resource.Type, 56 TypeName: n.Addr.Resource.Type,
57 PriorState: priorVal, 57 PriorState: priorVal,
58 Private: state.Private,
58 } 59 }
59 60
60 provider := *n.Provider 61 provider := *n.Provider
@@ -87,6 +88,7 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
87 88
88 newState := state.DeepCopy() 89 newState := state.DeepCopy()
89 newState.Value = resp.NewState 90 newState.Value = resp.NewState
91 newState.Private = resp.Private
90 92
91 // Call post-refresh hook 93 // Call post-refresh hook
92 err = ctx.Hook(func(h Hook) (HookAction, error) { 94 err = ctx.Hook(func(h Hook) (HookAction, error) {
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_state.go b/vendor/github.com/hashicorp/terraform/terraform/eval_state.go
index d506ce3..b611113 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/eval_state.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_state.go
@@ -424,15 +424,21 @@ func (n *EvalWriteResourceState) Eval(ctx EvalContext) (interface{}, error) {
424 return nil, diags.Err() 424 return nil, diags.Err()
425 } 425 }
426 426
427 // Currently we ony support NoEach and EachList, because for_each support
428 // is not fully wired up across Terraform. Once for_each support is added,
429 // we'll need to handle that here too, setting states.EachMap if the
430 // assigned expression is a map.
431 eachMode := states.NoEach 427 eachMode := states.NoEach
432 if count >= 0 { // -1 signals "count not set" 428 if count >= 0 { // -1 signals "count not set"
433 eachMode = states.EachList 429 eachMode = states.EachList
434 } 430 }
435 431
432 forEach, forEachDiags := evaluateResourceForEachExpression(n.Config.ForEach, ctx)
433 diags = diags.Append(forEachDiags)
434 if forEachDiags.HasErrors() {
435 return nil, diags.Err()
436 }
437
438 if forEach != nil {
439 eachMode = states.EachMap
440 }
441
436 // This method takes care of all of the business logic of updating this 442 // This method takes care of all of the business logic of updating this
437 // while ensuring that any existing instances are preserved, etc. 443 // while ensuring that any existing instances are preserved, etc.
438 state.SetResourceMeta(absAddr, eachMode, n.ProviderAddr) 444 state.SetResourceMeta(absAddr, eachMode, n.ProviderAddr)
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go b/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go
index 0033e01..6b809a2 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go
@@ -112,11 +112,12 @@ func (n *EvalValidateProvider) Eval(ctx EvalContext) (interface{}, error) {
112// the configuration of a provisioner belonging to a resource. The provisioner 112// the configuration of a provisioner belonging to a resource. The provisioner
113// config is expected to contain the merged connection configurations. 113// config is expected to contain the merged connection configurations.
114type EvalValidateProvisioner struct { 114type EvalValidateProvisioner struct {
115 ResourceAddr addrs.Resource 115 ResourceAddr addrs.Resource
116 Provisioner *provisioners.Interface 116 Provisioner *provisioners.Interface
117 Schema **configschema.Block 117 Schema **configschema.Block
118 Config *configs.Provisioner 118 Config *configs.Provisioner
119 ResourceHasCount bool 119 ResourceHasCount bool
120 ResourceHasForEach bool
120} 121}
121 122
122func (n *EvalValidateProvisioner) Eval(ctx EvalContext) (interface{}, error) { 123func (n *EvalValidateProvisioner) Eval(ctx EvalContext) (interface{}, error) {
@@ -198,6 +199,19 @@ func (n *EvalValidateProvisioner) evaluateBlock(ctx EvalContext, body hcl.Body,
198 // expected type since none of these elements are known at this 199 // expected type since none of these elements are known at this
199 // point anyway. 200 // point anyway.
200 selfAddr = n.ResourceAddr.Instance(addrs.IntKey(0)) 201 selfAddr = n.ResourceAddr.Instance(addrs.IntKey(0))
202 } else if n.ResourceHasForEach {
203 // For a resource that has for_each, we allow each.value and each.key
204 // but don't know at this stage what it will return.
205 keyData = InstanceKeyEvalData{
206 EachKey: cty.UnknownVal(cty.String),
207 EachValue: cty.DynamicVal,
208 }
209
210 // "self" can't point to an unknown key, but we'll force it to be
211 // key "" here, which should return an unknown value of the
212 // expected type since none of these elements are known at
213 // this point anyway.
214 selfAddr = n.ResourceAddr.Instance(addrs.StringKey(""))
201 } 215 }
202 216
203 return ctx.EvaluateBlock(body, schema, selfAddr, keyData) 217 return ctx.EvaluateBlock(body, schema, selfAddr, keyData)
@@ -370,10 +384,21 @@ func (n *EvalValidateResource) Eval(ctx EvalContext) (interface{}, error) {
370 diags = diags.Append(countDiags) 384 diags = diags.Append(countDiags)
371 } 385 }
372 386
387 if n.Config.ForEach != nil {
388 keyData = InstanceKeyEvalData{
389 EachKey: cty.UnknownVal(cty.String),
390 EachValue: cty.UnknownVal(cty.DynamicPseudoType),
391 }
392
393 // Evaluate the for_each expression here so we can expose the diagnostics
394 forEachDiags := n.validateForEach(ctx, n.Config.ForEach)
395 diags = diags.Append(forEachDiags)
396 }
397
373 for _, traversal := range n.Config.DependsOn { 398 for _, traversal := range n.Config.DependsOn {
374 ref, refDiags := addrs.ParseRef(traversal) 399 ref, refDiags := addrs.ParseRef(traversal)
375 diags = diags.Append(refDiags) 400 diags = diags.Append(refDiags)
376 if len(ref.Remaining) != 0 { 401 if !refDiags.HasErrors() && len(ref.Remaining) != 0 {
377 diags = diags.Append(&hcl.Diagnostic{ 402 diags = diags.Append(&hcl.Diagnostic{
378 Severity: hcl.DiagError, 403 Severity: hcl.DiagError,
379 Summary: "Invalid depends_on reference", 404 Summary: "Invalid depends_on reference",
@@ -542,3 +567,18 @@ func (n *EvalValidateResource) validateCount(ctx EvalContext, expr hcl.Expressio
542 567
543 return diags 568 return diags
544} 569}
570
571func (n *EvalValidateResource) validateForEach(ctx EvalContext, expr hcl.Expression) (diags tfdiags.Diagnostics) {
572 _, known, forEachDiags := evaluateResourceForEachExpressionKnown(expr, ctx)
573 // If the value isn't known then that's the best we can do for now, but
574 // we'll check more thoroughly during the plan walk
575 if !known {
576 return diags
577 }
578
579 if forEachDiags.HasErrors() {
580 diags = diags.Append(forEachDiags)
581 }
582
583 return diags
584}
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_variable.go b/vendor/github.com/hashicorp/terraform/terraform/eval_variable.go
index 68adf76..ea46973 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/eval_variable.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_variable.go
@@ -12,6 +12,7 @@ import (
12 "github.com/hashicorp/terraform/addrs" 12 "github.com/hashicorp/terraform/addrs"
13 13
14 "github.com/hashicorp/terraform/config" 14 "github.com/hashicorp/terraform/config"
15 "github.com/hashicorp/terraform/config/hcl2shim"
15 "github.com/hashicorp/terraform/config/module" 16 "github.com/hashicorp/terraform/config/module"
16 "github.com/zclconf/go-cty/cty" 17 "github.com/zclconf/go-cty/cty"
17 "github.com/zclconf/go-cty/cty/convert" 18 "github.com/zclconf/go-cty/cty/convert"
@@ -60,7 +61,7 @@ func (n *EvalTypeCheckVariable) Eval(ctx EvalContext) (interface{}, error) {
60 continue 61 continue
61 } 62 }
62 63
63 if proposedValue == config.UnknownVariableValue { 64 if proposedValue == hcl2shim.UnknownVariableValue {
64 continue 65 continue
65 } 66 }
66 67
diff --git a/vendor/github.com/hashicorp/terraform/terraform/evaluate.go b/vendor/github.com/hashicorp/terraform/terraform/evaluate.go
index ab65d47..9bb6009 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/evaluate.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/evaluate.go
@@ -120,20 +120,24 @@ type InstanceKeyEvalData struct {
120 120
121// EvalDataForInstanceKey constructs a suitable InstanceKeyEvalData for 121// EvalDataForInstanceKey constructs a suitable InstanceKeyEvalData for
122// evaluating in a context that has the given instance key. 122// evaluating in a context that has the given instance key.
123func EvalDataForInstanceKey(key addrs.InstanceKey) InstanceKeyEvalData { 123func EvalDataForInstanceKey(key addrs.InstanceKey, forEachMap map[string]cty.Value) InstanceKeyEvalData {
124 // At the moment we don't actually implement for_each, so we only
125 // ever populate CountIndex.
126 // (When we implement for_each later we may need to reorganize this some,
127 // so that we can resolve the ambiguity that an int key may either be
128 // a count.index or an each.key where for_each is over a list.)
129
130 var countIdx cty.Value 124 var countIdx cty.Value
125 var eachKey cty.Value
126 var eachVal cty.Value
127
131 if intKey, ok := key.(addrs.IntKey); ok { 128 if intKey, ok := key.(addrs.IntKey); ok {
132 countIdx = cty.NumberIntVal(int64(intKey)) 129 countIdx = cty.NumberIntVal(int64(intKey))
133 } 130 }
134 131
132 if stringKey, ok := key.(addrs.StringKey); ok {
133 eachKey = cty.StringVal(string(stringKey))
134 eachVal = forEachMap[string(stringKey)]
135 }
136
135 return InstanceKeyEvalData{ 137 return InstanceKeyEvalData{
136 CountIndex: countIdx, 138 CountIndex: countIdx,
139 EachKey: eachKey,
140 EachValue: eachVal,
137 } 141 }
138} 142}
139 143
@@ -173,6 +177,37 @@ func (d *evaluationStateData) GetCountAttr(addr addrs.CountAttr, rng tfdiags.Sou
173 } 177 }
174} 178}
175 179
180func (d *evaluationStateData) GetForEachAttr(addr addrs.ForEachAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
181 var diags tfdiags.Diagnostics
182 var returnVal cty.Value
183 switch addr.Name {
184
185 case "key":
186 returnVal = d.InstanceKeyData.EachKey
187 case "value":
188 returnVal = d.InstanceKeyData.EachValue
189 default:
190 diags = diags.Append(&hcl.Diagnostic{
191 Severity: hcl.DiagError,
192 Summary: `Invalid "each" attribute`,
193 Detail: fmt.Sprintf(`The "each" object does not have an attribute named %q. The supported attributes are each.key and each.value, the current key and value pair of the "for_each" attribute set.`, addr.Name),
194 Subject: rng.ToHCL().Ptr(),
195 })
196 return cty.DynamicVal, diags
197 }
198
199 if returnVal == cty.NilVal {
200 diags = diags.Append(&hcl.Diagnostic{
201 Severity: hcl.DiagError,
202 Summary: `Reference to "each" in context without for_each`,
203 Detail: fmt.Sprintf(`The "each" object can be used only in "resource" blocks, and only when the "for_each" argument is set.`),
204 Subject: rng.ToHCL().Ptr(),
205 })
206 return cty.UnknownVal(cty.DynamicPseudoType), diags
207 }
208 return returnVal, diags
209}
210
176func (d *evaluationStateData) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { 211func (d *evaluationStateData) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
177 var diags tfdiags.Diagnostics 212 var diags tfdiags.Diagnostics
178 213
@@ -569,7 +604,7 @@ func (d *evaluationStateData) GetResourceInstance(addr addrs.ResourceInstance, r
569 } 604 }
570 case states.EachMap: 605 case states.EachMap:
571 multi = key == addrs.NoKey 606 multi = key == addrs.NoKey
572 if _, ok := addr.Key.(addrs.IntKey); !multi && !ok { 607 if _, ok := addr.Key.(addrs.StringKey); !multi && !ok {
573 diags = diags.Append(&hcl.Diagnostic{ 608 diags = diags.Append(&hcl.Diagnostic{
574 Severity: hcl.DiagError, 609 Severity: hcl.DiagError,
575 Summary: "Invalid resource index", 610 Summary: "Invalid resource index",
@@ -696,7 +731,7 @@ func (d *evaluationStateData) getResourceInstancesAll(addr addrs.Resource, rng t
696 ty := schema.ImpliedType() 731 ty := schema.ImpliedType()
697 key := addrs.IntKey(i) 732 key := addrs.IntKey(i)
698 is, exists := rs.Instances[key] 733 is, exists := rs.Instances[key]
699 if exists { 734 if exists && is.Current != nil {
700 instAddr := addr.Instance(key).Absolute(d.ModulePath) 735 instAddr := addr.Instance(key).Absolute(d.ModulePath)
701 736
702 // Prefer pending value in plan if present. See getResourceInstanceSingle 737 // Prefer pending value in plan if present. See getResourceInstanceSingle
diff --git a/vendor/github.com/hashicorp/terraform/terraform/interpolate.go b/vendor/github.com/hashicorp/terraform/terraform/interpolate.go
index 26c1857..97bb1f6 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/interpolate.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/interpolate.go
@@ -11,16 +11,11 @@ import (
11 "github.com/hashicorp/hil" 11 "github.com/hashicorp/hil"
12 "github.com/hashicorp/hil/ast" 12 "github.com/hashicorp/hil/ast"
13 "github.com/hashicorp/terraform/config" 13 "github.com/hashicorp/terraform/config"
14 "github.com/hashicorp/terraform/config/hcl2shim"
14 "github.com/hashicorp/terraform/config/module" 15 "github.com/hashicorp/terraform/config/module"
15 "github.com/hashicorp/terraform/flatmap" 16 "github.com/hashicorp/terraform/flatmap"
16) 17)
17 18
18const (
19 // VarEnvPrefix is the prefix of variables that are read from
20 // the environment to set variables here.
21 VarEnvPrefix = "TF_VAR_"
22)
23
24// Interpolater is the structure responsible for determining the values 19// Interpolater is the structure responsible for determining the values
25// for interpolations such as `aws_instance.foo.bar`. 20// for interpolations such as `aws_instance.foo.bar`.
26type Interpolater struct { 21type Interpolater struct {
@@ -71,7 +66,7 @@ func (i *Interpolater) valueCountVar(
71func unknownVariable() ast.Variable { 66func unknownVariable() ast.Variable {
72 return ast.Variable{ 67 return ast.Variable{
73 Type: ast.TypeUnknown, 68 Type: ast.TypeUnknown,
74 Value: config.UnknownVariableValue, 69 Value: hcl2shim.UnknownVariableValue,
75 } 70 }
76} 71}
77 72
@@ -659,7 +654,7 @@ func (i *Interpolater) interpolateComplexTypeAttribute(
659 // ".#" count field is marked as unknown to indicate "this whole list is 654 // ".#" count field is marked as unknown to indicate "this whole list is
660 // unknown". We must honor that meaning here so computed references can be 655 // unknown". We must honor that meaning here so computed references can be
661 // treated properly during the plan phase. 656 // treated properly during the plan phase.
662 if lengthAttr == config.UnknownVariableValue { 657 if lengthAttr == hcl2shim.UnknownVariableValue {
663 return unknownVariable(), nil 658 return unknownVariable(), nil
664 } 659 }
665 660
@@ -675,7 +670,7 @@ func (i *Interpolater) interpolateComplexTypeAttribute(
675 // ".%" count field is marked as unknown to indicate "this whole list is 670 // ".%" count field is marked as unknown to indicate "this whole list is
676 // unknown". We must honor that meaning here so computed references can be 671 // unknown". We must honor that meaning here so computed references can be
677 // treated properly during the plan phase. 672 // treated properly during the plan phase.
678 if lengthAttr == config.UnknownVariableValue { 673 if lengthAttr == hcl2shim.UnknownVariableValue {
679 return unknownVariable(), nil 674 return unknownVariable(), nil
680 } 675 }
681 676
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_data_refresh.go b/vendor/github.com/hashicorp/terraform/terraform/node_data_refresh.go
index ab82163..dd92866 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/node_data_refresh.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_data_refresh.go
@@ -38,6 +38,16 @@ func (n *NodeRefreshableDataResource) DynamicExpand(ctx EvalContext) (*Graph, er
38 return nil, nil 38 return nil, nil
39 } 39 }
40 40
41 forEachMap, forEachKnown, forEachDiags := evaluateResourceForEachExpressionKnown(n.Config.ForEach, ctx)
42 if forEachDiags.HasErrors() {
43 return nil, diags.Err()
44 }
45 if !forEachKnown {
46 // If the for_each isn't known yet, we'll skip refreshing and try expansion
47 // again during the plan walk.
48 return nil, nil
49 }
50
41 // Next we need to potentially rename an instance address in the state 51 // Next we need to potentially rename an instance address in the state
42 // if we're transitioning whether "count" is set at all. 52 // if we're transitioning whether "count" is set at all.
43 fixResourceCountSetTransition(ctx, n.ResourceAddr(), count != -1) 53 fixResourceCountSetTransition(ctx, n.ResourceAddr(), count != -1)
@@ -77,6 +87,7 @@ func (n *NodeRefreshableDataResource) DynamicExpand(ctx EvalContext) (*Graph, er
77 Concrete: concreteResource, 87 Concrete: concreteResource,
78 Schema: n.Schema, 88 Schema: n.Schema,
79 Count: count, 89 Count: count,
90 ForEach: forEachMap,
80 Addr: n.ResourceAddr(), 91 Addr: n.ResourceAddr(),
81 }, 92 },
82 93
@@ -85,6 +96,7 @@ func (n *NodeRefreshableDataResource) DynamicExpand(ctx EvalContext) (*Graph, er
85 &OrphanResourceCountTransformer{ 96 &OrphanResourceCountTransformer{
86 Concrete: concreteResourceDestroyable, 97 Concrete: concreteResourceDestroyable,
87 Count: count, 98 Count: count,
99 ForEach: forEachMap,
88 Addr: n.ResourceAddr(), 100 Addr: n.ResourceAddr(),
89 State: state, 101 State: state,
90 }, 102 },
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_abstract.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_abstract.go
index 3a0570c..d147b42 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_abstract.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_abstract.go
@@ -187,6 +187,8 @@ func (n *NodeAbstractResource) References() []*addrs.Reference {
187 187
188 refs, _ := lang.ReferencesInExpr(c.Count) 188 refs, _ := lang.ReferencesInExpr(c.Count)
189 result = append(result, refs...) 189 result = append(result, refs...)
190 refs, _ = lang.ReferencesInExpr(c.ForEach)
191 result = append(result, refs...)
190 refs, _ = lang.ReferencesInBlock(c.Config, n.Schema) 192 refs, _ = lang.ReferencesInBlock(c.Config, n.Schema)
191 result = append(result, refs...) 193 result = append(result, refs...)
192 if c.Managed != nil { 194 if c.Managed != nil {
@@ -238,21 +240,31 @@ func (n *NodeAbstractResourceInstance) References() []*addrs.Reference {
238 // need to do a little work here to massage this to the form we now 240 // need to do a little work here to massage this to the form we now
239 // want. 241 // want.
240 var result []*addrs.Reference 242 var result []*addrs.Reference
241 for _, addr := range s.Current.Dependencies {
242 if addr == nil {
243 // Should never happen; indicates a bug in the state loader
244 panic(fmt.Sprintf("dependencies for current object on %s contains nil address", n.ResourceInstanceAddr()))
245 }
246 243
247 // This is a little weird: we need to manufacture an addrs.Reference 244 // It is (apparently) possible for s.Current to be nil. This proved
248 // with a fake range here because the state isn't something we can 245 // difficult to reproduce, so we will fix the symptom here and hope
249 // make source references into. 246 // to find the root cause another time.
250 result = append(result, &addrs.Reference{ 247 //
251 Subject: addr, 248 // https://github.com/hashicorp/terraform/issues/21407
252 SourceRange: tfdiags.SourceRange{ 249 if s.Current == nil {
253 Filename: "(state file)", 250 log.Printf("[WARN] no current state found for %s", n.Name())
254 }, 251 } else {
255 }) 252 for _, addr := range s.Current.Dependencies {
253 if addr == nil {
254 // Should never happen; indicates a bug in the state loader
255 panic(fmt.Sprintf("dependencies for current object on %s contains nil address", n.ResourceInstanceAddr()))
256 }
257
258 // This is a little weird: we need to manufacture an addrs.Reference
259 // with a fake range here because the state isn't something we can
260 // make source references into.
261 result = append(result, &addrs.Reference{
262 Subject: addr,
263 SourceRange: tfdiags.SourceRange{
264 Filename: "(state file)",
265 },
266 })
267 }
256 } 268 }
257 return result 269 return result
258 } 270 }
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply_instance.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply_instance.go
index dad7bfc..d795324 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply_instance.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply_instance.go
@@ -101,13 +101,6 @@ func (n *NodeApplyableResourceInstance) References() []*addrs.Reference {
101func (n *NodeApplyableResourceInstance) EvalTree() EvalNode { 101func (n *NodeApplyableResourceInstance) EvalTree() EvalNode {
102 addr := n.ResourceInstanceAddr() 102 addr := n.ResourceInstanceAddr()
103 103
104 // State still uses legacy-style internal ids, so we need to shim to get
105 // a suitable key to use.
106 stateId := NewLegacyResourceInstanceAddress(addr).stateId()
107
108 // Determine the dependencies for the state.
109 stateDeps := n.StateReferences()
110
111 if n.Config == nil { 104 if n.Config == nil {
112 // This should not be possible, but we've got here in at least one 105 // This should not be possible, but we've got here in at least one
113 // case as discussed in the following issue: 106 // case as discussed in the following issue:
@@ -132,15 +125,15 @@ func (n *NodeApplyableResourceInstance) EvalTree() EvalNode {
132 // Eval info is different depending on what kind of resource this is 125 // Eval info is different depending on what kind of resource this is
133 switch n.Config.Mode { 126 switch n.Config.Mode {
134 case addrs.ManagedResourceMode: 127 case addrs.ManagedResourceMode:
135 return n.evalTreeManagedResource(addr, stateId, stateDeps) 128 return n.evalTreeManagedResource(addr)
136 case addrs.DataResourceMode: 129 case addrs.DataResourceMode:
137 return n.evalTreeDataResource(addr, stateId, stateDeps) 130 return n.evalTreeDataResource(addr)
138 default: 131 default:
139 panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) 132 panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
140 } 133 }
141} 134}
142 135
143func (n *NodeApplyableResourceInstance) evalTreeDataResource(addr addrs.AbsResourceInstance, stateId string, stateDeps []addrs.Referenceable) EvalNode { 136func (n *NodeApplyableResourceInstance) evalTreeDataResource(addr addrs.AbsResourceInstance) EvalNode {
144 var provider providers.Interface 137 var provider providers.Interface
145 var providerSchema *ProviderSchema 138 var providerSchema *ProviderSchema
146 var change *plans.ResourceInstanceChange 139 var change *plans.ResourceInstanceChange
@@ -206,7 +199,7 @@ func (n *NodeApplyableResourceInstance) evalTreeDataResource(addr addrs.AbsResou
206 } 199 }
207} 200}
208 201
209func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsResourceInstance, stateId string, stateDeps []addrs.Referenceable) EvalNode { 202func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsResourceInstance) EvalNode {
210 // Declare a bunch of variables that are used for state during 203 // Declare a bunch of variables that are used for state during
211 // evaluation. Most of this are written to by-address below. 204 // evaluation. Most of this are written to by-address below.
212 var provider providers.Interface 205 var provider providers.Interface
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_plan.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_plan.go
index 633c1c4..ec4aa93 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_plan.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_plan.go
@@ -77,6 +77,11 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
77 return nil, diags.Err() 77 return nil, diags.Err()
78 } 78 }
79 79
80 forEachMap, forEachDiags := evaluateResourceForEachExpression(n.Config.ForEach, ctx)
81 if forEachDiags.HasErrors() {
82 return nil, diags.Err()
83 }
84
80 // Next we need to potentially rename an instance address in the state 85 // Next we need to potentially rename an instance address in the state
81 // if we're transitioning whether "count" is set at all. 86 // if we're transitioning whether "count" is set at all.
82 fixResourceCountSetTransition(ctx, n.ResourceAddr(), count != -1) 87 fixResourceCountSetTransition(ctx, n.ResourceAddr(), count != -1)
@@ -119,18 +124,20 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
119 124
120 // Start creating the steps 125 // Start creating the steps
121 steps := []GraphTransformer{ 126 steps := []GraphTransformer{
122 // Expand the count. 127 // Expand the count or for_each (if present)
123 &ResourceCountTransformer{ 128 &ResourceCountTransformer{
124 Concrete: concreteResource, 129 Concrete: concreteResource,
125 Schema: n.Schema, 130 Schema: n.Schema,
126 Count: count, 131 Count: count,
132 ForEach: forEachMap,
127 Addr: n.ResourceAddr(), 133 Addr: n.ResourceAddr(),
128 }, 134 },
129 135
130 // Add the count orphans 136 // Add the count/for_each orphans
131 &OrphanResourceCountTransformer{ 137 &OrphanResourceCountTransformer{
132 Concrete: concreteResourceOrphan, 138 Concrete: concreteResourceOrphan,
133 Count: count, 139 Count: count,
140 ForEach: forEachMap,
134 Addr: n.ResourceAddr(), 141 Addr: n.ResourceAddr(),
135 State: state, 142 State: state,
136 }, 143 },
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_plan_instance.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_plan_instance.go
index 75e0bcd..0f74bbe 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_plan_instance.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_plan_instance.go
@@ -34,25 +34,18 @@ var (
34func (n *NodePlannableResourceInstance) EvalTree() EvalNode { 34func (n *NodePlannableResourceInstance) EvalTree() EvalNode {
35 addr := n.ResourceInstanceAddr() 35 addr := n.ResourceInstanceAddr()
36 36
37 // State still uses legacy-style internal ids, so we need to shim to get
38 // a suitable key to use.
39 stateId := NewLegacyResourceInstanceAddress(addr).stateId()
40
41 // Determine the dependencies for the state.
42 stateDeps := n.StateReferences()
43
44 // Eval info is different depending on what kind of resource this is 37 // Eval info is different depending on what kind of resource this is
45 switch addr.Resource.Resource.Mode { 38 switch addr.Resource.Resource.Mode {
46 case addrs.ManagedResourceMode: 39 case addrs.ManagedResourceMode:
47 return n.evalTreeManagedResource(addr, stateId, stateDeps) 40 return n.evalTreeManagedResource(addr)
48 case addrs.DataResourceMode: 41 case addrs.DataResourceMode:
49 return n.evalTreeDataResource(addr, stateId, stateDeps) 42 return n.evalTreeDataResource(addr)
50 default: 43 default:
51 panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) 44 panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
52 } 45 }
53} 46}
54 47
55func (n *NodePlannableResourceInstance) evalTreeDataResource(addr addrs.AbsResourceInstance, stateId string, stateDeps []addrs.Referenceable) EvalNode { 48func (n *NodePlannableResourceInstance) evalTreeDataResource(addr addrs.AbsResourceInstance) EvalNode {
56 config := n.Config 49 config := n.Config
57 var provider providers.Interface 50 var provider providers.Interface
58 var providerSchema *ProviderSchema 51 var providerSchema *ProviderSchema
@@ -147,7 +140,7 @@ func (n *NodePlannableResourceInstance) evalTreeDataResource(addr addrs.AbsResou
147 } 140 }
148} 141}
149 142
150func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsResourceInstance, stateId string, stateDeps []addrs.Referenceable) EvalNode { 143func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsResourceInstance) EvalNode {
151 config := n.Config 144 config := n.Config
152 var provider providers.Interface 145 var provider providers.Interface
153 var providerSchema *ProviderSchema 146 var providerSchema *ProviderSchema
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go
index 9506023..9daeabf 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go
@@ -39,6 +39,11 @@ func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph,
39 return nil, diags.Err() 39 return nil, diags.Err()
40 } 40 }
41 41
42 forEachMap, forEachDiags := evaluateResourceForEachExpression(n.Config.ForEach, ctx)
43 if forEachDiags.HasErrors() {
44 return nil, diags.Err()
45 }
46
42 // Next we need to potentially rename an instance address in the state 47 // Next we need to potentially rename an instance address in the state
43 // if we're transitioning whether "count" is set at all. 48 // if we're transitioning whether "count" is set at all.
44 fixResourceCountSetTransition(ctx, n.ResourceAddr(), count != -1) 49 fixResourceCountSetTransition(ctx, n.ResourceAddr(), count != -1)
@@ -66,6 +71,7 @@ func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph,
66 Concrete: concreteResource, 71 Concrete: concreteResource,
67 Schema: n.Schema, 72 Schema: n.Schema,
68 Count: count, 73 Count: count,
74 ForEach: forEachMap,
69 Addr: n.ResourceAddr(), 75 Addr: n.ResourceAddr(),
70 }, 76 },
71 77
@@ -74,6 +80,7 @@ func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph,
74 &OrphanResourceCountTransformer{ 80 &OrphanResourceCountTransformer{
75 Concrete: concreteResource, 81 Concrete: concreteResource,
76 Count: count, 82 Count: count,
83 ForEach: forEachMap,
77 Addr: n.ResourceAddr(), 84 Addr: n.ResourceAddr(),
78 State: state, 85 State: state,
79 }, 86 },
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_validate.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_validate.go
index 734ec9e..efa657b 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_validate.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_validate.go
@@ -54,6 +54,7 @@ func (n *NodeValidatableResource) EvalTree() EvalNode {
54 54
55 if managed := n.Config.Managed; managed != nil { 55 if managed := n.Config.Managed; managed != nil {
56 hasCount := n.Config.Count != nil 56 hasCount := n.Config.Count != nil
57 hasForEach := n.Config.ForEach != nil
57 58
58 // Validate all the provisioners 59 // Validate all the provisioners
59 for _, p := range managed.Provisioners { 60 for _, p := range managed.Provisioners {
@@ -74,11 +75,12 @@ func (n *NodeValidatableResource) EvalTree() EvalNode {
74 Schema: &provisionerSchema, 75 Schema: &provisionerSchema,
75 }, 76 },
76 &EvalValidateProvisioner{ 77 &EvalValidateProvisioner{
77 ResourceAddr: addr.Resource, 78 ResourceAddr: addr.Resource,
78 Provisioner: &provisioner, 79 Provisioner: &provisioner,
79 Schema: &provisionerSchema, 80 Schema: &provisionerSchema,
80 Config: p, 81 Config: p,
81 ResourceHasCount: hasCount, 82 ResourceHasCount: hasCount,
83 ResourceHasForEach: hasForEach,
82 }, 84 },
83 ) 85 )
84 } 86 }
diff --git a/vendor/github.com/hashicorp/terraform/terraform/provider_mock.go b/vendor/github.com/hashicorp/terraform/terraform/provider_mock.go
index 4ae346d..8eede48 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/provider_mock.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/provider_mock.go
@@ -8,7 +8,6 @@ import (
8 "github.com/zclconf/go-cty/cty" 8 "github.com/zclconf/go-cty/cty"
9 ctyjson "github.com/zclconf/go-cty/cty/json" 9 ctyjson "github.com/zclconf/go-cty/cty/json"
10 10
11 "github.com/hashicorp/terraform/config"
12 "github.com/hashicorp/terraform/config/hcl2shim" 11 "github.com/hashicorp/terraform/config/hcl2shim"
13 "github.com/hashicorp/terraform/providers" 12 "github.com/hashicorp/terraform/providers"
14 "github.com/hashicorp/terraform/tfdiags" 13 "github.com/hashicorp/terraform/tfdiags"
@@ -391,7 +390,7 @@ func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeReques
391 for k, new := range plannedMap { 390 for k, new := range plannedMap {
392 old := priorMap[k] 391 old := priorMap[k]
393 newComputed := false 392 newComputed := false
394 if new == config.UnknownVariableValue { 393 if new == hcl2shim.UnknownVariableValue {
395 new = "" 394 new = ""
396 newComputed = true 395 newComputed = true
397 } 396 }
diff --git a/vendor/github.com/hashicorp/terraform/terraform/resource_address.go b/vendor/github.com/hashicorp/terraform/terraform/resource_address.go
index 156ecf5..5d8261a 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/resource_address.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/resource_address.go
@@ -365,6 +365,8 @@ func NewLegacyResourceInstanceAddress(addr addrs.AbsResourceInstance) *ResourceA
365 ret.Index = -1 365 ret.Index = -1
366 } else if ik, ok := addr.Resource.Key.(addrs.IntKey); ok { 366 } else if ik, ok := addr.Resource.Key.(addrs.IntKey); ok {
367 ret.Index = int(ik) 367 ret.Index = int(ik)
368 } else if _, ok := addr.Resource.Key.(addrs.StringKey); ok {
369 ret.Index = -1
368 } else { 370 } else {
369 panic(fmt.Errorf("cannot shim resource instance with key %#v to legacy ResourceAddress.Index", addr.Resource.Key)) 371 panic(fmt.Errorf("cannot shim resource instance with key %#v to legacy ResourceAddress.Index", addr.Resource.Key))
370 } 372 }
diff --git a/vendor/github.com/hashicorp/terraform/terraform/state.go b/vendor/github.com/hashicorp/terraform/terraform/state.go
index 092b690..6280fb0 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/state.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/state.go
@@ -1201,7 +1201,7 @@ func (m *ModuleState) prune() {
1201 } 1201 }
1202 1202
1203 for k, v := range m.Outputs { 1203 for k, v := range m.Outputs {
1204 if v.Value == config.UnknownVariableValue { 1204 if v.Value == hcl2shim.UnknownVariableValue {
1205 delete(m.Outputs, k) 1205 delete(m.Outputs, k)
1206 } 1206 }
1207 } 1207 }
@@ -1827,7 +1827,7 @@ func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState {
1827 continue 1827 continue
1828 } 1828 }
1829 if diff.NewComputed { 1829 if diff.NewComputed {
1830 result.Attributes[k] = config.UnknownVariableValue 1830 result.Attributes[k] = hcl2shim.UnknownVariableValue
1831 continue 1831 continue
1832 } 1832 }
1833 1833
diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_orphan_count.go b/vendor/github.com/hashicorp/terraform/terraform/transform_orphan_count.go
index eec762e..4f323a7 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/transform_orphan_count.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/transform_orphan_count.go
@@ -6,6 +6,7 @@ import (
6 "github.com/hashicorp/terraform/addrs" 6 "github.com/hashicorp/terraform/addrs"
7 "github.com/hashicorp/terraform/dag" 7 "github.com/hashicorp/terraform/dag"
8 "github.com/hashicorp/terraform/states" 8 "github.com/hashicorp/terraform/states"
9 "github.com/zclconf/go-cty/cty"
9) 10)
10 11
11// OrphanResourceCountTransformer is a GraphTransformer that adds orphans 12// OrphanResourceCountTransformer is a GraphTransformer that adds orphans
@@ -18,9 +19,10 @@ import (
18type OrphanResourceCountTransformer struct { 19type OrphanResourceCountTransformer struct {
19 Concrete ConcreteResourceInstanceNodeFunc 20 Concrete ConcreteResourceInstanceNodeFunc
20 21
21 Count int // Actual count of the resource, or -1 if count is not set at all 22 Count int // Actual count of the resource, or -1 if count is not set at all
22 Addr addrs.AbsResource // Addr of the resource to look for orphans 23 ForEach map[string]cty.Value // The ForEach map on the resource
23 State *states.State // Full global state 24 Addr addrs.AbsResource // Addr of the resource to look for orphans
25 State *states.State // Full global state
24} 26}
25 27
26func (t *OrphanResourceCountTransformer) Transform(g *Graph) error { 28func (t *OrphanResourceCountTransformer) Transform(g *Graph) error {
@@ -34,6 +36,10 @@ func (t *OrphanResourceCountTransformer) Transform(g *Graph) error {
34 haveKeys[key] = struct{}{} 36 haveKeys[key] = struct{}{}
35 } 37 }
36 38
39 // if for_each is set, use that transformer
40 if t.ForEach != nil {
41 return t.transformForEach(haveKeys, g)
42 }
37 if t.Count < 0 { 43 if t.Count < 0 {
38 return t.transformNoCount(haveKeys, g) 44 return t.transformNoCount(haveKeys, g)
39 } 45 }
@@ -43,6 +49,25 @@ func (t *OrphanResourceCountTransformer) Transform(g *Graph) error {
43 return t.transformCount(haveKeys, g) 49 return t.transformCount(haveKeys, g)
44} 50}
45 51
52func (t *OrphanResourceCountTransformer) transformForEach(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
53 for key := range haveKeys {
54 s, _ := key.(addrs.StringKey)
55 // If the key is present in our current for_each, carry on
56 if _, ok := t.ForEach[string(s)]; ok {
57 continue
58 }
59
60 abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
61 var node dag.Vertex = abstract
62 if f := t.Concrete; f != nil {
63 node = f(abstract)
64 }
65 log.Printf("[TRACE] OrphanResourceCount(non-zero): adding %s as %T", t.Addr, node)
66 g.Add(node)
67 }
68 return nil
69}
70
46func (t *OrphanResourceCountTransformer) transformCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error { 71func (t *OrphanResourceCountTransformer) transformCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
47 // Due to the logic in Transform, we only get in here if our count is 72 // Due to the logic in Transform, we only get in here if our count is
48 // at least one. 73 // at least one.
diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_resource_count.go b/vendor/github.com/hashicorp/terraform/terraform/transform_resource_count.go
index 1123790..c70a3c1 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/transform_resource_count.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/transform_resource_count.go
@@ -4,6 +4,7 @@ import (
4 "github.com/hashicorp/terraform/addrs" 4 "github.com/hashicorp/terraform/addrs"
5 "github.com/hashicorp/terraform/configs/configschema" 5 "github.com/hashicorp/terraform/configs/configschema"
6 "github.com/hashicorp/terraform/dag" 6 "github.com/hashicorp/terraform/dag"
7 "github.com/zclconf/go-cty/cty"
7) 8)
8 9
9// ResourceCountTransformer is a GraphTransformer that expands the count 10// ResourceCountTransformer is a GraphTransformer that expands the count
@@ -17,12 +18,13 @@ type ResourceCountTransformer struct {
17 // Count is either the number of indexed instances to create, or -1 to 18 // Count is either the number of indexed instances to create, or -1 to
18 // indicate that count is not set at all and thus a no-key instance should 19 // indicate that count is not set at all and thus a no-key instance should
19 // be created. 20 // be created.
20 Count int 21 Count int
21 Addr addrs.AbsResource 22 ForEach map[string]cty.Value
23 Addr addrs.AbsResource
22} 24}
23 25
24func (t *ResourceCountTransformer) Transform(g *Graph) error { 26func (t *ResourceCountTransformer) Transform(g *Graph) error {
25 if t.Count < 0 { 27 if t.Count < 0 && t.ForEach == nil {
26 // Negative count indicates that count is not set at all. 28 // Negative count indicates that count is not set at all.
27 addr := t.Addr.Instance(addrs.NoKey) 29 addr := t.Addr.Instance(addrs.NoKey)
28 30
@@ -37,6 +39,19 @@ func (t *ResourceCountTransformer) Transform(g *Graph) error {
37 return nil 39 return nil
38 } 40 }
39 41
42 // Add nodes related to the for_each expression
43 for key := range t.ForEach {
44 addr := t.Addr.Instance(addrs.StringKey(key))
45 abstract := NewNodeAbstractResourceInstance(addr)
46 abstract.Schema = t.Schema
47 var node dag.Vertex = abstract
48 if f := t.Concrete; f != nil {
49 node = f(abstract)
50 }
51
52 g.Add(node)
53 }
54
40 // For each count, build and add the node 55 // For each count, build and add the node
41 for i := 0; i < t.Count; i++ { 56 for i := 0; i < t.Count; i++ {
42 key := addrs.IntKey(i) 57 key := addrs.IntKey(i)
diff --git a/vendor/github.com/hashicorp/terraform/terraform/util.go b/vendor/github.com/hashicorp/terraform/terraform/util.go
index 752241a..5428cd5 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/util.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/util.go
@@ -2,8 +2,6 @@ package terraform
2 2
3import ( 3import (
4 "sort" 4 "sort"
5
6 "github.com/hashicorp/terraform/config"
7) 5)
8 6
9// Semaphore is a wrapper around a channel to provide 7// Semaphore is a wrapper around a channel to provide
@@ -48,10 +46,6 @@ func (s Semaphore) Release() {
48 } 46 }
49} 47}
50 48
51func resourceProvider(resourceType, explicitProvider string) string {
52 return config.ResourceProviderFullName(resourceType, explicitProvider)
53}
54
55// strSliceContains checks if a given string is contained in a slice 49// strSliceContains checks if a given string is contained in a slice
56// When anybody asks why Go needs generics, here you go. 50// When anybody asks why Go needs generics, here you go.
57func strSliceContains(haystack []string, needle string) bool { 51func strSliceContains(haystack []string, needle string) bool {