github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/eval_local.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2"
     7  	"github.com/zclconf/go-cty/cty"
     8  
     9  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
    10  	"github.com/hashicorp/terraform-plugin-sdk/internal/lang"
    11  	"github.com/hashicorp/terraform-plugin-sdk/internal/tfdiags"
    12  )
    13  
    14  // EvalLocal is an EvalNode implementation that evaluates the
    15  // expression for a local value and writes it into a transient part of
    16  // the state.
    17  type EvalLocal struct {
    18  	Addr addrs.LocalValue
    19  	Expr hcl.Expression
    20  }
    21  
    22  func (n *EvalLocal) Eval(ctx EvalContext) (interface{}, error) {
    23  	var diags tfdiags.Diagnostics
    24  
    25  	// We ignore diags here because any problems we might find will be found
    26  	// again in EvaluateExpr below.
    27  	refs, _ := lang.ReferencesInExpr(n.Expr)
    28  	for _, ref := range refs {
    29  		if ref.Subject == n.Addr {
    30  			diags = diags.Append(&hcl.Diagnostic{
    31  				Severity: hcl.DiagError,
    32  				Summary:  "Self-referencing local value",
    33  				Detail:   fmt.Sprintf("Local value %s cannot use its own result as part of its expression.", n.Addr),
    34  				Subject:  ref.SourceRange.ToHCL().Ptr(),
    35  				Context:  n.Expr.Range().Ptr(),
    36  			})
    37  		}
    38  	}
    39  	if diags.HasErrors() {
    40  		return nil, diags.Err()
    41  	}
    42  
    43  	val, moreDiags := ctx.EvaluateExpr(n.Expr, cty.DynamicPseudoType, nil)
    44  	diags = diags.Append(moreDiags)
    45  	if moreDiags.HasErrors() {
    46  		return nil, diags.Err()
    47  	}
    48  
    49  	state := ctx.State()
    50  	if state == nil {
    51  		return nil, fmt.Errorf("cannot write local value to nil state")
    52  	}
    53  
    54  	state.SetLocalValue(n.Addr.Absolute(ctx.Path()), val)
    55  
    56  	return nil, nil
    57  }
    58  
    59  // EvalDeleteLocal is an EvalNode implementation that deletes a Local value
    60  // from the state. Locals aren't persisted, but we don't need to evaluate them
    61  // during destroy.
    62  type EvalDeleteLocal struct {
    63  	Addr addrs.LocalValue
    64  }
    65  
    66  func (n *EvalDeleteLocal) Eval(ctx EvalContext) (interface{}, error) {
    67  	state := ctx.State()
    68  	if state == nil {
    69  		return nil, nil
    70  	}
    71  
    72  	state.RemoveLocalValue(n.Addr.Absolute(ctx.Path()))
    73  	return nil, nil
    74  }