diff --git a/terraform/node_resource_plan.go b/terraform/node_resource_plan.go index 7950c5595..b53484cf9 100644 --- a/terraform/node_resource_plan.go +++ b/terraform/node_resource_plan.go @@ -1,5 +1,9 @@ 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 { @@ -21,21 +25,33 @@ func (n *NodePlannableResource) EvalTree() EvalNode { } } -/* // GraphNodeDynamicExpandable func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) { - 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 + a.ResourceState = n.ResourceState + + return &NodePlannableResourceInstance{ + NodeAbstractResource: a, + } + } // Start creating the steps steps := make([]GraphTransformer, 0, 5) // Expand counts. steps = append(steps, &ResourceCountTransformer{ - Resource: n.Resource, - Destroy: n.Destroy, - Targets: n.Targets, + Concrete: concreteResource, + Count: count, + Addr: n.ResourceAddr(), }) // Always end with the root being added @@ -45,4 +61,3 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) { b := &BasicGraphBuilder{Steps: steps, Validate: true} return b.Build(ctx.Path()) } -*/ diff --git a/terraform/transform_resource_count.go b/terraform/transform_resource_count.go new file mode 100644 index 000000000..cda35cb7b --- /dev/null +++ b/terraform/transform_resource_count.go @@ -0,0 +1,51 @@ +package terraform + +import ( + "fmt" + + "github.com/hashicorp/terraform/dag" +) + +// ResourceCountTransformer is a GraphTransformer that expands the count +// out for a specific resource. +// +// This assumes that the count is already interpolated. +type ResourceCountTransformer struct { + Concrete ConcreteResourceNodeFunc + + Count int + Addr *ResourceAddress +} + +func (t *ResourceCountTransformer) Transform(g *Graph) error { + // Don't allow the count to be negative + if t.Count < 0 { + return fmt.Errorf("negative count: %d", t.Count) + } + + // For each count, build and add the node + for i := 0; i < t.Count; i++ { + // Set the index. If our count is 1 we special case it so that + // we handle the "resource.0" and "resource" boundary properly. + index := i + if t.Count == 1 { + index = -1 + } + + // Build the resource address + addr := t.Addr.Copy() + addr.Index = index + + // Build the abstract node and the concrete one + abstract := &NodeAbstractResource{Addr: addr} + var node dag.Vertex = abstract + if f := t.Concrete; f != nil { + node = f(abstract) + } + + // Add it to the graph + g.Add(node) + } + + return nil +}