github.com/opentofu/opentofu@v1.7.1/internal/tofu/node_root_variable.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package tofu
     7  
     8  import (
     9  	"log"
    10  
    11  	"github.com/zclconf/go-cty/cty"
    12  
    13  	"github.com/opentofu/opentofu/internal/addrs"
    14  	"github.com/opentofu/opentofu/internal/configs"
    15  	"github.com/opentofu/opentofu/internal/dag"
    16  	"github.com/opentofu/opentofu/internal/tfdiags"
    17  )
    18  
    19  // NodeRootVariable represents a root variable input.
    20  type NodeRootVariable struct {
    21  	Addr   addrs.InputVariable
    22  	Config *configs.Variable
    23  
    24  	// RawValue is the value for the variable set from outside OpenTofu
    25  	// Core, such as on the command line, or from an environment variable,
    26  	// or similar. This is the raw value that was provided, not yet
    27  	// converted or validated, and can be nil for a variable that isn't
    28  	// set at all.
    29  	RawValue *InputValue
    30  }
    31  
    32  var (
    33  	_ GraphNodeModuleInstance = (*NodeRootVariable)(nil)
    34  	_ GraphNodeReferenceable  = (*NodeRootVariable)(nil)
    35  )
    36  
    37  func (n *NodeRootVariable) Name() string {
    38  	return n.Addr.String()
    39  }
    40  
    41  // GraphNodeModuleInstance
    42  func (n *NodeRootVariable) Path() addrs.ModuleInstance {
    43  	return addrs.RootModuleInstance
    44  }
    45  
    46  func (n *NodeRootVariable) ModulePath() addrs.Module {
    47  	return addrs.RootModule
    48  }
    49  
    50  // GraphNodeReferenceable
    51  func (n *NodeRootVariable) ReferenceableAddrs() []addrs.Referenceable {
    52  	return []addrs.Referenceable{n.Addr}
    53  }
    54  
    55  // GraphNodeExecutable
    56  func (n *NodeRootVariable) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
    57  	// Root module variables are special in that they are provided directly
    58  	// by the caller (usually, the CLI layer) and so we don't really need to
    59  	// evaluate them in the usual sense, but we do need to process the raw
    60  	// values given by the caller to match what the module is expecting, and
    61  	// make sure the values are valid.
    62  	var diags tfdiags.Diagnostics
    63  
    64  	addr := addrs.RootModuleInstance.InputVariable(n.Addr.Name)
    65  	log.Printf("[TRACE] NodeRootVariable: evaluating %s", addr)
    66  
    67  	if n.Config == nil {
    68  		// Because we build NodeRootVariable from configuration in the normal
    69  		// case it's strange to get here, but we tolerate it to allow for
    70  		// tests that might not populate the inputs fully.
    71  		return nil
    72  	}
    73  
    74  	givenVal := n.RawValue
    75  	if givenVal == nil {
    76  		// We'll use cty.NilVal to represent the variable not being set at
    77  		// all, which for historical reasons is unfortunately different than
    78  		// explicitly setting it to null in some cases. In normal code we
    79  		// should never get here because all variables should have raw
    80  		// values, but we can get here in some historical tests that call
    81  		// in directly and don't necessarily obey the rules.
    82  		givenVal = &InputValue{
    83  			Value:      cty.NilVal,
    84  			SourceType: ValueFromUnknown,
    85  		}
    86  	}
    87  
    88  	if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.Addr.InModule(addrs.RootModule)) {
    89  		ctx.Checks().ReportCheckableObjects(
    90  			n.Addr.InModule(addrs.RootModule),
    91  			addrs.MakeSet[addrs.Checkable](n.Addr.Absolute(addrs.RootModuleInstance)))
    92  	}
    93  
    94  	finalVal, moreDiags := prepareFinalInputVariableValue(
    95  		addr,
    96  		givenVal,
    97  		n.Config,
    98  	)
    99  	diags = diags.Append(moreDiags)
   100  	if moreDiags.HasErrors() {
   101  		// No point in proceeding to validations then, because they'll
   102  		// probably fail trying to work with a value of the wrong type.
   103  		return diags
   104  	}
   105  
   106  	ctx.SetRootModuleArgument(addr.Variable, finalVal)
   107  
   108  	moreDiags = evalVariableValidations(
   109  		addrs.RootModuleInstance.InputVariable(n.Addr.Name),
   110  		n.Config,
   111  		nil, // not set for root module variables
   112  		ctx,
   113  	)
   114  	diags = diags.Append(moreDiags)
   115  	return diags
   116  }
   117  
   118  // dag.GraphNodeDotter impl.
   119  func (n *NodeRootVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
   120  	return &dag.DotNode{
   121  		Name: name,
   122  		Attrs: map[string]string{
   123  			"label": n.Name(),
   124  			"shape": "note",
   125  		},
   126  	}
   127  }