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 }