// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package graph import ( "fmt" "github.com/hashicorp/hcl/v2" "github.com/zclconf/go-cty/cty" "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/lang/langrefs" "github.com/hashicorp/terraform/internal/moduletest" "github.com/hashicorp/terraform/internal/terraform" "github.com/hashicorp/terraform/internal/tfdiags" ) type TestInputValue struct { Value *terraform.InputValue } var ( _ GraphNodeExecutable = (*NodeVariableDefinition)(nil) _ GraphNodeReferenceable = (*NodeVariableDefinition)(nil) ) type NodeVariableDefinition struct { Address string Config *configs.Variable File *moduletest.File } func (n *NodeVariableDefinition) Name() string { return fmt.Sprintf("var.%s", n.Address) } func (n *NodeVariableDefinition) Referenceable() addrs.Referenceable { return &addrs.InputVariable{Name: n.Address} } func (n *NodeVariableDefinition) Execute(ctx *EvalContext) { if ctx.Stopped() || ctx.Cancelled() { return // don't evaluate anything when stopped or cancelled } input, diags := ctx.EvaluateUnparsedVariable(n.Address, n.Config) if input != nil { n.File.AppendDiagnostics(diags) if diags.HasErrors() { ctx.SetVariableStatus(n.Address, moduletest.Error) return } } else { input = &terraform.InputValue{ Value: cty.NilVal, } } value, diags := terraform.PrepareFinalInputVariableValue(addrs.AbsInputVariableInstance{ Module: addrs.RootModuleInstance, Variable: addrs.InputVariable{ Name: n.Address, }, }, input, n.Config) n.File.AppendDiagnostics(diags) if diags.HasErrors() { ctx.SetVariableStatus(n.Address, moduletest.Error) return } ctx.SetVariable(n.Address, &terraform.InputValue{ Value: value, SourceType: terraform.ValueFromConfig, SourceRange: tfdiags.SourceRangeFromHCL(n.Config.DeclRange), }) } var ( _ GraphNodeExecutable = (*NodeVariableExpression)(nil) _ GraphNodeReferencer = (*NodeVariableExpression)(nil) _ GraphNodeReferenceable = (*NodeVariableExpression)(nil) ) type NodeVariableExpression struct { Address string Expr hcl.Expression File *moduletest.File } func (n *NodeVariableExpression) Name() string { return fmt.Sprintf("var.%s", n.Address) } func (n *NodeVariableExpression) Referenceable() addrs.Referenceable { return &addrs.InputVariable{Name: n.Address} } func (n *NodeVariableExpression) References() []*addrs.Reference { refs, _ := langrefs.ReferencesInExpr(addrs.ParseRefFromTestingScope, n.Expr) return refs } func (n *NodeVariableExpression) Execute(ctx *EvalContext) { refs, refDiags := langrefs.ReferencesInExpr(addrs.ParseRefFromTestingScope, n.Expr) if !ctx.ReferencesCompleted(refs) { // before we do anything with the diags, we're going to check that all // of the references we know about were successfully parsed. If not, // then we'll skip actually assessing this node. ctx.SetVariableStatus(n.Address, moduletest.Skip) return } if ctx.Stopped() || ctx.Cancelled() { return // don't evaluate anything when stopped or cancelled } n.File.AppendDiagnostics(refDiags) if refDiags.HasErrors() { ctx.SetVariableStatus(n.Address, moduletest.Error) return } evalContext, moreDiags := ctx.HclContext(refs) n.File.AppendDiagnostics(moreDiags) if moreDiags.HasErrors() { ctx.SetVariableStatus(n.Address, moduletest.Error) return } var diags tfdiags.Diagnostics value, valueDiags := n.Expr.Value(evalContext) n.File.AppendDiagnostics(diags.Append(valueDiags)) if valueDiags.HasErrors() { ctx.SetVariableStatus(n.Address, moduletest.Error) return } ctx.SetVariable(n.Address, &terraform.InputValue{ Value: value, SourceType: terraform.ValueFromConfig, SourceRange: tfdiags.SourceRangeFromHCL(n.Expr.Range()), }) }