diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform')
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 @@ | |||
1 | package terraform | ||
2 | |||
3 | import ( | ||
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 | ||
16 | func 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. | ||
33 | func 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. |
114 | type EvalValidateProvisioner struct { | 114 | type 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 | ||
122 | func (n *EvalValidateProvisioner) Eval(ctx EvalContext) (interface{}, error) { | 123 | func (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 | |||
571 | func (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. |
123 | func EvalDataForInstanceKey(key addrs.InstanceKey) InstanceKeyEvalData { | 123 | func 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 | ||
180 | func (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 | |||
176 | func (d *evaluationStateData) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { | 211 | func (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 | ||
18 | const ( | ||
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`. |
26 | type Interpolater struct { | 21 | type Interpolater struct { |
@@ -71,7 +66,7 @@ func (i *Interpolater) valueCountVar( | |||
71 | func unknownVariable() ast.Variable { | 66 | func 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 { | |||
101 | func (n *NodeApplyableResourceInstance) EvalTree() EvalNode { | 101 | func (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 | ||
143 | func (n *NodeApplyableResourceInstance) evalTreeDataResource(addr addrs.AbsResourceInstance, stateId string, stateDeps []addrs.Referenceable) EvalNode { | 136 | func (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 | ||
209 | func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsResourceInstance, stateId string, stateDeps []addrs.Referenceable) EvalNode { | 202 | func (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 ( | |||
34 | func (n *NodePlannableResourceInstance) EvalTree() EvalNode { | 34 | func (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 | ||
55 | func (n *NodePlannableResourceInstance) evalTreeDataResource(addr addrs.AbsResourceInstance, stateId string, stateDeps []addrs.Referenceable) EvalNode { | 48 | func (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 | ||
150 | func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsResourceInstance, stateId string, stateDeps []addrs.Referenceable) EvalNode { | 143 | func (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 ( | |||
18 | type OrphanResourceCountTransformer struct { | 19 | type 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 | ||
26 | func (t *OrphanResourceCountTransformer) Transform(g *Graph) error { | 28 | func (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 | ||
52 | func (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 | |||
46 | func (t *OrphanResourceCountTransformer) transformCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error { | 71 | func (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 | ||
24 | func (t *ResourceCountTransformer) Transform(g *Graph) error { | 26 | func (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 | ||
3 | import ( | 3 | import ( |
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 | ||
51 | func 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. |
57 | func strSliceContains(haystack []string, needle string) bool { | 51 | func strSliceContains(haystack []string, needle string) bool { |