terraform/terraform/transform_resource.go

182 lines
4.3 KiB
Go
Raw Normal View History

package terraform
import (
"fmt"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/dag"
)
// ResourceCountTransformer is a GraphTransformer that expands the count
// out for a specific resource.
type ResourceCountTransformer struct {
Resource *config.Resource
}
func (t *ResourceCountTransformer) Transform(g *Graph) error {
// Expand the resource count
count, err := t.Resource.Count()
if err != nil {
return err
}
// Don't allow the count to be negative
if count < 0 {
return fmt.Errorf("negative count: %d", count)
}
// For each count, build and add the node
nodes := make([]dag.Vertex, count)
for i := 0; i < count; i++ {
2015-02-12 02:18:16 +01:00
// 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 count == 1 {
index = -1
}
// Save the node for later so we can do connections
nodes[i] = &graphNodeExpandedResource{
2015-02-12 02:18:16 +01:00
Index: index,
Resource: t.Resource,
}
// Add the node now
g.Add(nodes[i])
}
// Make the dependency connections
for _, n := range nodes {
// Connect the dependents. We ignore the return value for missing
// dependents since that should've been caught at a higher level.
g.ConnectDependent(n)
}
return nil
}
type graphNodeExpandedResource struct {
Index int
Resource *config.Resource
}
func (n *graphNodeExpandedResource) Name() string {
if n.Index == -1 {
return n.Resource.Id()
}
return fmt.Sprintf("%s #%d", n.Resource.Id(), n.Index)
}
// GraphNodeDependable impl.
func (n *graphNodeExpandedResource) DependableName() []string {
return []string{
n.Resource.Id(),
2015-02-10 23:12:49 +01:00
n.stateId(),
}
}
// GraphNodeDependent impl.
func (n *graphNodeExpandedResource) DependentOn() []string {
config := &GraphNodeConfigResource{Resource: n.Resource}
return config.DependentOn()
}
// GraphNodeProviderConsumer
2015-02-11 23:14:05 +01:00
func (n *graphNodeExpandedResource) ProvidedBy() []string {
return []string{resourceProvider(n.Resource.Type)}
}
// GraphNodeEvalable impl.
func (n *graphNodeExpandedResource) EvalTree() EvalNode {
resource := &Resource{CountIndex: n.Index}
// Shared node for interpolation of configuration
interpolateNode := &EvalInterpolate{
Config: n.Resource.RawConfig,
Resource: resource,
}
2015-02-09 20:15:54 +01:00
seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
// Validate the resource
vseq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
vseq.Nodes = append(vseq.Nodes, &EvalValidateResource{
2015-02-11 23:14:05 +01:00
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
Config: interpolateNode,
2015-02-09 20:15:54 +01:00
ResourceName: n.Resource.Name,
ResourceType: n.Resource.Type,
})
// Validate all the provisioners
for _, p := range n.Resource.Provisioners {
vseq.Nodes = append(vseq.Nodes, &EvalValidateProvisioner{
2015-02-09 20:15:54 +01:00
Provisioner: &EvalGetProvisioner{Name: p.Type},
Config: &EvalInterpolate{
Config: p.RawConfig, Resource: resource},
2015-02-09 20:15:54 +01:00
})
}
2015-02-09 20:15:54 +01:00
// Add the validation operations
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
Ops: []walkOperation{walkValidate},
Node: vseq,
})
2015-02-11 22:43:07 +01:00
// Build instance info
info := &InstanceInfo{Id: n.stateId(), Type: n.Resource.Type}
seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
2015-02-11 17:48:45 +01:00
// Refresh the resource
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
Ops: []walkOperation{walkRefresh},
Node: &EvalWriteState{
Name: n.stateId(),
ResourceType: n.Resource.Type,
Dependencies: n.DependentOn(),
State: &EvalRefresh{
2015-02-11 22:43:07 +01:00
Info: info,
2015-02-11 23:14:05 +01:00
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
2015-02-11 17:48:45 +01:00
State: &EvalReadState{Name: n.stateId()},
},
},
})
2015-02-12 00:22:03 +01:00
// Diff the resource
var diff InstanceDiff
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
Ops: []walkOperation{walkPlan},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalWriteState{
Name: n.stateId(),
ResourceType: n.Resource.Type,
Dependencies: n.DependentOn(),
State: &EvalDiff{
Info: info,
Config: interpolateNode,
2015-02-12 00:22:03 +01:00
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
State: &EvalReadState{Name: n.stateId()},
Output: &diff,
},
},
&EvalWriteDiff{
Name: n.stateId(),
Diff: &diff,
},
},
},
})
2015-02-09 20:15:54 +01:00
return seq
}
2015-02-10 23:12:49 +01:00
// stateId is the name used for the state key
func (n *graphNodeExpandedResource) stateId() string {
2015-02-12 02:18:16 +01:00
if n.Index == -1 {
2015-02-11 17:48:45 +01:00
return n.Resource.Id()
}
2015-02-10 23:12:49 +01:00
return fmt.Sprintf("%s.%d", n.Resource.Id(), n.Index)
}