terraform: abstract resource nodes

This commit is contained in:
Mitchell Hashimoto 2016-09-21 14:30:41 -07:00
parent 046faf247a
commit 6622ca001d
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 147 additions and 109 deletions

View File

@ -2,6 +2,7 @@ package terraform
import (
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/dag"
)
// ApplyGraphBuilder implements GraphBuilder and is responsible for building
@ -46,9 +47,17 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
}
}
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
return &NodeApplyableResource{
NodeAbstractResource: a,
}
}
steps := []GraphTransformer{
// Creates all the nodes represented in the diff.
&DiffTransformer{
Concrete: concreteResource,
Diff: b.Diff,
Module: b.Module,
State: b.State,

View File

@ -0,0 +1,115 @@
package terraform
import (
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/dag"
)
// ConcreteResourceNodeFunc is a callback type used to convert an
// abstract resource to a concrete one of some type.
type ConcreteResourceNodeFunc func(*NodeAbstractResource) dag.Vertex
// NodeAbstractResource represents a resource that has no associated
// operations. It registers all the interfaces for a resource that common
// across multiple operation types.
type NodeAbstractResource struct {
Addr *ResourceAddress // Addr is the address for this resource
// The fields below will be automatically set using the Attach
// interfaces if you're running those transforms, but also be explicitly
// set if you already have that information.
Config *config.Resource // Config is the resource in the config
ResourceState *ResourceState // ResourceState is the ResourceState for this
}
func (n *NodeAbstractResource) Name() string {
return n.Addr.String()
}
// GraphNodeSubPath
func (n *NodeAbstractResource) Path() []string {
return n.Addr.Path
}
// GraphNodeReferenceable
func (n *NodeAbstractResource) ReferenceableName() []string {
if n.Config == nil {
return nil
}
return []string{n.Config.Id()}
}
// GraphNodeReferencer
func (n *NodeAbstractResource) References() []string {
// If we have a config, that is our source of truth
if c := n.Config; c != nil {
// Grab all the references
var result []string
result = append(result, c.DependsOn...)
result = append(result, ReferencesFromConfig(c.RawCount)...)
result = append(result, ReferencesFromConfig(c.RawConfig)...)
for _, p := range c.Provisioners {
result = append(result, ReferencesFromConfig(p.ConnInfo)...)
result = append(result, ReferencesFromConfig(p.RawConfig)...)
}
return result
}
// If we have state, that is our next source
if s := n.ResourceState; s != nil {
return s.Dependencies
}
return nil
}
// GraphNodeProviderConsumer
func (n *NodeAbstractResource) ProvidedBy() []string {
// If we have a config we prefer that above all else
if n.Config != nil {
return []string{resourceProvider(n.Config.Type, n.Config.Provider)}
}
// If we have state, then we will use the provider from there
if n.ResourceState != nil {
return []string{n.ResourceState.Provider}
}
// Use our type
return []string{resourceProvider(n.Addr.Type, "")}
}
// GraphNodeProvisionerConsumer
func (n *NodeAbstractResource) ProvisionedBy() []string {
// If we have no configuration, then we have no provisioners
if n.Config == nil {
return nil
}
// Build the list of provisioners we need based on the configuration.
// It is okay to have duplicates here.
result := make([]string, len(n.Config.Provisioners))
for i, p := range n.Config.Provisioners {
result[i] = p.Type
}
return result
}
// GraphNodeAttachResourceState
func (n *NodeAbstractResource) ResourceAddr() *ResourceAddress {
return n.Addr
}
// GraphNodeAttachResourceState
func (n *NodeAbstractResource) AttachResourceState(s *ResourceState) {
n.ResourceState = s
}
// GraphNodeAttachResourceConfig
func (n *NodeAbstractResource) AttachResourceConfig(c *config.Resource) {
n.Config = c
}

View File

@ -2,133 +2,40 @@ package terraform
import (
"fmt"
"github.com/hashicorp/terraform/config"
)
// NodeApplyableResource represents a resource that is "applyable":
// it is ready to be applied and is represented by a diff.
type NodeApplyableResource struct {
Addr *ResourceAddress // Addr is the address for this resource
Config *config.Resource // Config is the resource in the config
ResourceState *ResourceState // ResourceState is the ResourceState for this
}
func (n *NodeApplyableResource) Name() string {
return n.Addr.String()
}
// GraphNodeSubPath
func (n *NodeApplyableResource) Path() []string {
return n.Addr.Path
}
// GraphNodeReferenceable
func (n *NodeApplyableResource) ReferenceableName() []string {
if n.Config == nil {
return nil
}
return []string{n.Config.Id()}
}
// GraphNodeReferencer
func (n *NodeApplyableResource) References() []string {
// If we have a config, that is our source of truth
if c := n.Config; c != nil {
// Grab all the references
var result []string
result = append(result, c.DependsOn...)
result = append(result, ReferencesFromConfig(c.RawCount)...)
result = append(result, ReferencesFromConfig(c.RawConfig)...)
for _, p := range c.Provisioners {
result = append(result, ReferencesFromConfig(p.ConnInfo)...)
result = append(result, ReferencesFromConfig(p.RawConfig)...)
}
return result
}
// If we have state, that is our next source
if s := n.ResourceState; s != nil {
return s.Dependencies
}
return nil
}
// GraphNodeProviderConsumer
func (n *NodeApplyableResource) ProvidedBy() []string {
// If we have a config we prefer that above all else
if n.Config != nil {
return []string{resourceProvider(n.Config.Type, n.Config.Provider)}
}
// If we have state, then we will use the provider from there
if n.ResourceState != nil {
return []string{n.ResourceState.Provider}
}
// Use our type
return []string{resourceProvider(n.Addr.Type, "")}
}
// GraphNodeProvisionerConsumer
func (n *NodeApplyableResource) ProvisionedBy() []string {
// If we have no configuration, then we have no provisioners
if n.Config == nil {
return nil
}
// Build the list of provisioners we need based on the configuration.
// It is okay to have duplicates here.
result := make([]string, len(n.Config.Provisioners))
for i, p := range n.Config.Provisioners {
result[i] = p.Type
}
return result
*NodeAbstractResource
}
// GraphNodeCreator
func (n *NodeApplyableResource) CreateAddr() *ResourceAddress {
return n.Addr
}
// GraphNodeAttachResourceState
func (n *NodeApplyableResource) ResourceAddr() *ResourceAddress {
return n.Addr
}
// GraphNodeAttachResource
func (n *NodeApplyableResource) AttachResourceConfig(c *config.Resource) {
n.Config = c
}
// GraphNodeAttachResourceState
func (n *NodeApplyableResource) AttachResourceState(s *ResourceState) {
n.ResourceState = s
return n.NodeAbstractResource.Addr
}
// GraphNodeEvalable
func (n *NodeApplyableResource) EvalTree() EvalNode {
addr := n.NodeAbstractResource.Addr
// stateId is the ID to put into the state
stateId := n.Addr.stateId()
if n.Addr.Index > -1 {
stateId = fmt.Sprintf("%s.%d", stateId, n.Addr.Index)
stateId := addr.stateId()
if addr.Index > -1 {
stateId = fmt.Sprintf("%s.%d", stateId, addr.Index)
}
// Build the instance info. More of this will be populated during eval
info := &InstanceInfo{
Id: stateId,
Type: n.Addr.Type,
Type: addr.Type,
}
// Build the resource for eval
resource := &Resource{
Name: n.Addr.Name,
Type: n.Addr.Type,
CountIndex: n.Addr.Index,
Name: addr.Name,
Type: addr.Type,
CountIndex: addr.Index,
}
if resource.CountIndex < 0 {
resource.CountIndex = 0

View File

@ -134,7 +134,7 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
// This part is a little bit weird but is the best way to
// find the dependencies we need to: build a graph and use the
// attach config and state transformers then ask for references.
node := &NodeApplyableResource{Addr: addr}
node := &NodeAbstractResource{Addr: addr}
{
var g Graph
g.Add(node)

View File

@ -5,6 +5,7 @@ import (
"log"
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/dag"
)
// DiffTransformer is a GraphTransformer that adds the elements of
@ -19,6 +20,8 @@ import (
// is built based on the diff first, though, ensuring that only resources
// that are being modified are present in the graph.
type DiffTransformer struct {
Concrete ConcreteResourceNodeFunc
Diff *Diff
Module *module.Tree
State *State
@ -32,7 +35,7 @@ func (t *DiffTransformer) Transform(g *Graph) error {
// Go through all the modules in the diff.
log.Printf("[TRACE] DiffTransformer: starting")
var nodes []*NodeApplyableResource
var nodes []dag.Vertex
for _, m := range t.Diff.Modules {
log.Printf("[TRACE] DiffTransformer: Module: %s", m)
// TODO: If this is a destroy diff then add a module destroy node
@ -62,9 +65,13 @@ func (t *DiffTransformer) Transform(g *Graph) error {
// If we have changes, then add the applyable version
if len(inst.Attributes) > 0 {
// Add the resource to the graph
nodes = append(nodes, &NodeApplyableResource{
Addr: addr,
})
abstract := &NodeAbstractResource{Addr: addr}
var node dag.Vertex = abstract
if f := t.Concrete; f != nil {
node = f(abstract)
}
nodes = append(nodes, node)
}
}
}