mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 01:41:48 -06:00
cf46e1c3e0
This disables the computed value check for `count` during the validation pass. This enables partial support for #3888 or #1497: as long as the value is non-computed during the plan, complex values will work in counts. **Notably, this allows data source values to be present in counts!** The "count" value can be disabled during validation safely because we can treat it as if any field that uses `count.index` is computed for validation. We then validate a single instance (as if `count = 1`) just to make sure all required fields are set.
147 lines
3.3 KiB
Go
147 lines
3.3 KiB
Go
package terraform
|
|
|
|
import (
|
|
"github.com/hashicorp/terraform/dag"
|
|
)
|
|
|
|
// NodeValidatableResource represents a resource that is used for validation
|
|
// only.
|
|
type NodeValidatableResource struct {
|
|
*NodeAbstractCountResource
|
|
}
|
|
|
|
// GraphNodeEvalable
|
|
func (n *NodeValidatableResource) EvalTree() EvalNode {
|
|
// Ensure we're validating
|
|
c := n.NodeAbstractCountResource
|
|
c.Validate = true
|
|
return c.EvalTree()
|
|
}
|
|
|
|
// GraphNodeDynamicExpandable
|
|
func (n *NodeValidatableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|
// Grab the state which we read
|
|
state, lock := ctx.State()
|
|
lock.RLock()
|
|
defer lock.RUnlock()
|
|
|
|
// Expand the resource count which must be available by now from EvalTree
|
|
count := 1
|
|
if n.Config.RawCount.Value() != unknownValue() {
|
|
var err error
|
|
count, err = n.Config.Count()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// The concrete resource factory we'll use
|
|
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
|
|
// Add the config and state since we don't do that via transforms
|
|
a.Config = n.Config
|
|
|
|
return &NodeValidatableResourceInstance{
|
|
NodeAbstractResource: a,
|
|
}
|
|
}
|
|
|
|
// Start creating the steps
|
|
steps := []GraphTransformer{
|
|
// Expand the count.
|
|
&ResourceCountTransformer{
|
|
Concrete: concreteResource,
|
|
Count: count,
|
|
Addr: n.ResourceAddr(),
|
|
},
|
|
|
|
// Attach the state
|
|
&AttachStateTransformer{State: state},
|
|
|
|
// Targeting
|
|
&TargetsTransformer{ParsedTargets: n.Targets},
|
|
|
|
// Connect references so ordering is correct
|
|
&ReferenceTransformer{},
|
|
|
|
// Make sure there is a single root
|
|
&RootTransformer{},
|
|
}
|
|
|
|
// Build the graph
|
|
b := &BasicGraphBuilder{
|
|
Steps: steps,
|
|
Validate: true,
|
|
Name: "NodeValidatableResource",
|
|
}
|
|
|
|
return b.Build(ctx.Path())
|
|
}
|
|
|
|
// This represents a _single_ resource instance to validate.
|
|
type NodeValidatableResourceInstance struct {
|
|
*NodeAbstractResource
|
|
}
|
|
|
|
// GraphNodeEvalable
|
|
func (n *NodeValidatableResourceInstance) EvalTree() EvalNode {
|
|
addr := n.NodeAbstractResource.Addr
|
|
|
|
// Build the resource for eval
|
|
resource := &Resource{
|
|
Name: addr.Name,
|
|
Type: addr.Type,
|
|
CountIndex: addr.Index,
|
|
}
|
|
if resource.CountIndex < 0 {
|
|
resource.CountIndex = 0
|
|
}
|
|
|
|
// Declare a bunch of variables that are used for state during
|
|
// evaluation. Most of this are written to by-address below.
|
|
var config *ResourceConfig
|
|
var provider ResourceProvider
|
|
|
|
seq := &EvalSequence{
|
|
Nodes: []EvalNode{
|
|
&EvalValidateResourceSelfRef{
|
|
Addr: &addr,
|
|
Config: &n.Config.RawConfig,
|
|
},
|
|
&EvalGetProvider{
|
|
Name: n.ProvidedBy()[0],
|
|
Output: &provider,
|
|
},
|
|
&EvalInterpolate{
|
|
Config: n.Config.RawConfig.Copy(),
|
|
Resource: resource,
|
|
Output: &config,
|
|
},
|
|
&EvalValidateResource{
|
|
Provider: &provider,
|
|
Config: &config,
|
|
ResourceName: n.Config.Name,
|
|
ResourceType: n.Config.Type,
|
|
ResourceMode: n.Config.Mode,
|
|
},
|
|
},
|
|
}
|
|
|
|
// Validate all the provisioners
|
|
for _, p := range n.Config.Provisioners {
|
|
var provisioner ResourceProvisioner
|
|
seq.Nodes = append(seq.Nodes, &EvalGetProvisioner{
|
|
Name: p.Type,
|
|
Output: &provisioner,
|
|
}, &EvalInterpolate{
|
|
Config: p.RawConfig.Copy(),
|
|
Resource: resource,
|
|
Output: &config,
|
|
}, &EvalValidateProvisioner{
|
|
Provisioner: &provisioner,
|
|
Config: &config,
|
|
})
|
|
}
|
|
|
|
return seq
|
|
}
|