opentofu/terraform/node_resource_plan.go
Mitchell Hashimoto f5da7e85c8
terraform: detect compute counts and show a nicer error
This will detect computed counts (which we don't currently support) and
change the error to be more informative that we don't allow computed
counts. Prior to this, the error would instead be something like
`strconv.ParseInt: "${var.foo}" cannot be parsed as int`.
2016-11-11 11:07:17 -08:00

107 lines
2.7 KiB
Go

package terraform
import (
"github.com/hashicorp/terraform/dag"
)
// NodePlannableResource represents a resource that is "plannable":
// it is ready to be planned in order to create a diff.
type NodePlannableResource struct {
*NodeAbstractResource
// Set by GraphNodeTargetable and used during DynamicExpand to
// forward targets downwards.
targets []ResourceAddress
}
// GraphNodeTargetable
func (n *NodePlannableResource) SetTargets(targets []ResourceAddress) {
n.targets = targets
}
// GraphNodeEvalable
func (n *NodePlannableResource) EvalTree() EvalNode {
return &EvalSequence{
Nodes: []EvalNode{
// The EvalTree for a plannable resource primarily involves
// interpolating the count since it can contain variables
// we only just received access to.
//
// With the interpolated count, we can then DynamicExpand
// into the proper number of instances.
&EvalInterpolate{Config: n.Config.RawCount},
&EvalCountCheckComputed{Resource: n.Config},
&EvalCountFixZeroOneBoundary{Resource: n.Config},
},
}
}
// GraphNodeDynamicExpandable
func (n *NodePlannableResource) 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, 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 &NodePlannableResourceInstance{
NodeAbstractResource: a,
}
}
// The concrete resource factory we'll use for oprhans
concreteResourceOrphan := func(a *NodeAbstractResource) dag.Vertex {
// Add the config and state since we don't do that via transforms
a.Config = n.Config
return &NodePlannableResourceOrphan{
NodeAbstractResource: a,
}
}
// Start creating the steps
steps := []GraphTransformer{
// Expand the count.
&ResourceCountTransformer{
Concrete: concreteResource,
Count: count,
Addr: n.ResourceAddr(),
},
// Add the count orphans
&OrphanResourceCountTransformer{
Concrete: concreteResourceOrphan,
Count: count,
Addr: n.ResourceAddr(),
State: state,
},
// 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}
return b.Build(ctx.Path())
}