github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/terraform/eval_count.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2"
     7  	"github.com/muratcelep/terraform/not-internal/tfdiags"
     8  	"github.com/zclconf/go-cty/cty"
     9  	"github.com/zclconf/go-cty/cty/gocty"
    10  )
    11  
    12  // evaluateCountExpression is our standard mechanism for interpreting an
    13  // expression given for a "count" argument on a resource or a module. This
    14  // should be called during expansion in order to determine the final count
    15  // value.
    16  //
    17  // evaluateCountExpression differs from evaluateCountExpressionValue by
    18  // returning an error if the count value is not known, and converting the
    19  // cty.Value to an integer.
    20  func evaluateCountExpression(expr hcl.Expression, ctx EvalContext) (int, tfdiags.Diagnostics) {
    21  	countVal, diags := evaluateCountExpressionValue(expr, ctx)
    22  	if !countVal.IsKnown() {
    23  		// Currently this is a rather bad outcome from a UX standpoint, since we have
    24  		// no real mechanism to deal with this situation and all we can do is produce
    25  		// an error message.
    26  		// FIXME: In future, implement a built-in mechanism for deferring changes that
    27  		// can't yet be predicted, and use it to guide the user through several
    28  		// plan/apply steps until the desired configuration is eventually reached.
    29  		diags = diags.Append(&hcl.Diagnostic{
    30  			Severity: hcl.DiagError,
    31  			Summary:  "Invalid count argument",
    32  			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.`,
    33  			Subject:  expr.Range().Ptr(),
    34  		})
    35  	}
    36  
    37  	if countVal.IsNull() || !countVal.IsKnown() {
    38  		return -1, diags
    39  	}
    40  
    41  	count, _ := countVal.AsBigFloat().Int64()
    42  	return int(count), diags
    43  }
    44  
    45  // evaluateCountExpressionValue is like evaluateCountExpression
    46  // except that it returns a cty.Value which must be a cty.Number and can be
    47  // unknown.
    48  func evaluateCountExpressionValue(expr hcl.Expression, ctx EvalContext) (cty.Value, tfdiags.Diagnostics) {
    49  	var diags tfdiags.Diagnostics
    50  	nullCount := cty.NullVal(cty.Number)
    51  	if expr == nil {
    52  		return nullCount, nil
    53  	}
    54  
    55  	countVal, countDiags := ctx.EvaluateExpr(expr, cty.Number, nil)
    56  	diags = diags.Append(countDiags)
    57  	if diags.HasErrors() {
    58  		return nullCount, diags
    59  	}
    60  
    61  	// Unmark the count value, sensitive values are allowed in count but not for_each,
    62  	// as using it here will not disclose the sensitive value
    63  	countVal, _ = countVal.Unmark()
    64  
    65  	switch {
    66  	case countVal.IsNull():
    67  		diags = diags.Append(&hcl.Diagnostic{
    68  			Severity: hcl.DiagError,
    69  			Summary:  "Invalid count argument",
    70  			Detail:   `The given "count" argument value is null. An integer is required.`,
    71  			Subject:  expr.Range().Ptr(),
    72  		})
    73  		return nullCount, diags
    74  
    75  	case !countVal.IsKnown():
    76  		return cty.UnknownVal(cty.Number), diags
    77  	}
    78  
    79  	var count int
    80  	err := gocty.FromCtyValue(countVal, &count)
    81  	if err != nil {
    82  		diags = diags.Append(&hcl.Diagnostic{
    83  			Severity: hcl.DiagError,
    84  			Summary:  "Invalid count argument",
    85  			Detail:   fmt.Sprintf(`The given "count" argument value is unsuitable: %s.`, err),
    86  			Subject:  expr.Range().Ptr(),
    87  		})
    88  		return nullCount, diags
    89  	}
    90  	if count < 0 {
    91  		diags = diags.Append(&hcl.Diagnostic{
    92  			Severity: hcl.DiagError,
    93  			Summary:  "Invalid count argument",
    94  			Detail:   `The given "count" argument value is unsuitable: negative numbers are not supported.`,
    95  			Subject:  expr.Range().Ptr(),
    96  		})
    97  		return nullCount, diags
    98  	}
    99  
   100  	return countVal, diags
   101  }