]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/terraform/eval_count.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / eval_count.go
CommitLineData
bae9f6d2
JC
1package terraform
2
3import (
107c1cdb
ND
4 "fmt"
5 "log"
6
7 "github.com/hashicorp/hcl2/hcl"
8 "github.com/hashicorp/terraform/addrs"
9 "github.com/hashicorp/terraform/tfdiags"
10 "github.com/zclconf/go-cty/cty"
11 "github.com/zclconf/go-cty/cty/gocty"
bae9f6d2
JC
12)
13
107c1cdb
ND
14// evaluateResourceCountExpression is our standard mechanism for interpreting an
15// expression given for a "count" argument on a resource. This should be called
16// from the DynamicExpand of a node representing a resource in order to
17// determine the final count value.
18//
19// If the result is zero or positive and no error diagnostics are returned, then
20// the result is the literal count value to use.
21//
22// If the result is -1, this indicates that the given expression is nil and so
23// the "count" behavior should not be enabled for this resource at all.
24//
25// If error diagnostics are returned then the result is always the meaningless
26// placeholder value -1.
27func evaluateResourceCountExpression(expr hcl.Expression, ctx EvalContext) (int, tfdiags.Diagnostics) {
28 count, known, diags := evaluateResourceCountExpressionKnown(expr, ctx)
29 if !known {
30 // Currently this is a rather bad outcome from a UX standpoint, since we have
31 // no real mechanism to deal with this situation and all we can do is produce
32 // an error message.
33 // FIXME: In future, implement a built-in mechanism for deferring changes that
34 // can't yet be predicted, and use it to guide the user through several
35 // plan/apply steps until the desired configuration is eventually reached.
36 diags = diags.Append(&hcl.Diagnostic{
37 Severity: hcl.DiagError,
38 Summary: "Invalid count argument",
39 Detail: `The "count" 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 count depends on.`,
40 Subject: expr.Range().Ptr(),
41 })
42 }
43 return count, diags
bae9f6d2
JC
44}
45
107c1cdb
ND
46// evaluateResourceCountExpressionKnown is like evaluateResourceCountExpression
47// except that it handles an unknown result by returning count = 0 and
48// a known = false, rather than by reporting the unknown value as an error
49// diagnostic.
50func evaluateResourceCountExpressionKnown(expr hcl.Expression, ctx EvalContext) (count int, known bool, diags tfdiags.Diagnostics) {
51 if expr == nil {
52 return -1, true, nil
bae9f6d2
JC
53 }
54
107c1cdb
ND
55 countVal, countDiags := ctx.EvaluateExpr(expr, cty.Number, nil)
56 diags = diags.Append(countDiags)
57 if diags.HasErrors() {
58 return -1, true, diags
bae9f6d2
JC
59 }
60
107c1cdb
ND
61 switch {
62 case countVal.IsNull():
63 diags = diags.Append(&hcl.Diagnostic{
64 Severity: hcl.DiagError,
65 Summary: "Invalid count argument",
66 Detail: `The given "count" argument value is null. An integer is required.`,
67 Subject: expr.Range().Ptr(),
68 })
69 return -1, true, diags
70 case !countVal.IsKnown():
71 return 0, false, diags
bae9f6d2
JC
72 }
73
107c1cdb
ND
74 err := gocty.FromCtyValue(countVal, &count)
75 if err != nil {
76 diags = diags.Append(&hcl.Diagnostic{
77 Severity: hcl.DiagError,
78 Summary: "Invalid count argument",
79 Detail: fmt.Sprintf(`The given "count" argument value is unsuitable: %s.`, err),
80 Subject: expr.Range().Ptr(),
81 })
82 return -1, true, diags
bae9f6d2 83 }
107c1cdb
ND
84 if count < 0 {
85 diags = diags.Append(&hcl.Diagnostic{
86 Severity: hcl.DiagError,
87 Summary: "Invalid count argument",
88 Detail: `The given "count" argument value is unsuitable: negative numbers are not supported.`,
89 Subject: expr.Range().Ptr(),
90 })
91 return -1, true, diags
bae9f6d2
JC
92 }
93
107c1cdb
ND
94 return count, true, diags
95}
bae9f6d2 96
107c1cdb
ND
97// fixResourceCountSetTransition is a helper function to fix up the state when a
98// resource transitions its "count" from being set to unset or vice-versa,
99// treating a 0-key and a no-key instance as aliases for one another across
100// the transition.
101//
102// The correct time to call this function is in the DynamicExpand method for
103// a node representing a resource, just after evaluating the count with
104// evaluateResourceCountExpression, and before any other analysis of the
105// state such as orphan detection.
106//
107// This function calls methods on the given EvalContext to update the current
108// state in-place, if necessary. It is a no-op if there is no count transition
109// taking place.
110//
111// Since the state is modified in-place, this function must take a writer lock
112// on the state. The caller must therefore not also be holding a state lock,
113// or this function will block forever awaiting the lock.
114func fixResourceCountSetTransition(ctx EvalContext, addr addrs.AbsResource, countEnabled bool) {
115 state := ctx.State()
116 changed := state.MaybeFixUpResourceInstanceAddressForCount(addr, countEnabled)
117 if changed {
118 log.Printf("[TRACE] renamed first %s instance in transient state due to count argument change", addr)
119 }
bae9f6d2 120}