opentofu/terraform/node_resource_validate.go
James Bardin a14fd0344c WIP reference providers by full name
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.
2017-11-02 15:00:06 -04:00

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
}