diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index c753cd97c..6929985c8 100644 --- a/terraform/graph_builder_apply.go +++ b/terraform/graph_builder_apply.go @@ -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, diff --git a/terraform/node_resource_abstract.go b/terraform/node_resource_abstract.go new file mode 100644 index 000000000..7d7a21b5e --- /dev/null +++ b/terraform/node_resource_abstract.go @@ -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 +} diff --git a/terraform/node_resource_apply.go b/terraform/node_resource_apply.go index b5676bcbe..f663cd893 100644 --- a/terraform/node_resource_apply.go +++ b/terraform/node_resource_apply.go @@ -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 diff --git a/terraform/transform_destroy_edge.go b/terraform/transform_destroy_edge.go index 6c156f360..a3a8f8d9f 100644 --- a/terraform/transform_destroy_edge.go +++ b/terraform/transform_destroy_edge.go @@ -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) diff --git a/terraform/transform_diff.go b/terraform/transform_diff.go index 81bebab9a..d33140911 100644 --- a/terraform/transform_diff.go +++ b/terraform/transform_diff.go @@ -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) } } }