mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
This turned out to be a big messy commit, since the way providers are referenced is tightly coupled throughout the code. That starts to unify how providers are referenced, using the format output node Name method. Add a new field to the internal resource data types called ResolvedProvider. This is set by a new setter method SetProvider when a resource is connected to a provider during graph creation. This allows us to later lookup the provider instance a resource is connected to, without requiring it to have the same module path. The InitProvider context method now takes 2 arguments, one if the provider type and the second is the full name of the provider. While the provider type could still be parsed from the full name, this makes it more explicit and, and changes to the name format won't effect this code.
160 lines
3.5 KiB
Go
160 lines
3.5 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
|
|
a.ResolvedProvider = n.ResolvedProvider
|
|
|
|
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.ResolvedProvider,
|
|
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
|
|
var connConfig *ResourceConfig
|
|
seq.Nodes = append(
|
|
seq.Nodes,
|
|
&EvalGetProvisioner{
|
|
Name: p.Type,
|
|
Output: &provisioner,
|
|
},
|
|
&EvalInterpolate{
|
|
Config: p.RawConfig.Copy(),
|
|
Resource: resource,
|
|
Output: &config,
|
|
},
|
|
&EvalInterpolate{
|
|
Config: p.ConnInfo.Copy(),
|
|
Resource: resource,
|
|
Output: &connConfig,
|
|
},
|
|
&EvalValidateProvisioner{
|
|
Provisioner: &provisioner,
|
|
Config: &config,
|
|
ConnConfig: &connConfig,
|
|
},
|
|
)
|
|
}
|
|
|
|
return seq
|
|
}
|