2015-01-21 23:39:16 +01:00
|
|
|
package terraform
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/config"
|
2015-01-24 02:52:51 +01:00
|
|
|
"github.com/hashicorp/terraform/config/module"
|
2015-01-23 02:12:32 +01:00
|
|
|
"github.com/hashicorp/terraform/dag"
|
2015-01-21 23:39:16 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// graphNodeConfig is an interface that all graph nodes for the
|
|
|
|
// configuration graph need to implement in order to build the variable
|
|
|
|
// dependencies properly.
|
|
|
|
type graphNodeConfig interface {
|
2015-01-24 00:21:27 +01:00
|
|
|
dag.NamedVertex
|
2015-01-21 23:39:16 +01:00
|
|
|
|
2015-01-27 23:56:01 +01:00
|
|
|
// All graph nodes should be dependent on other things, and able to
|
|
|
|
// be depended on.
|
|
|
|
GraphNodeDependable
|
|
|
|
GraphNodeDependent
|
2015-01-21 23:39:16 +01:00
|
|
|
}
|
|
|
|
|
2015-01-21 23:53:50 +01:00
|
|
|
// GraphNodeConfigModule represents a module within the configuration graph.
|
|
|
|
type GraphNodeConfigModule struct {
|
2015-02-08 01:19:08 +01:00
|
|
|
Path []string
|
2015-01-21 23:53:50 +01:00
|
|
|
Module *config.Module
|
2015-01-24 02:52:51 +01:00
|
|
|
Tree *module.Tree
|
2015-01-21 23:53:50 +01:00
|
|
|
}
|
|
|
|
|
2015-01-27 06:23:27 +01:00
|
|
|
func (n *GraphNodeConfigModule) DependableName() []string {
|
|
|
|
return []string{n.Name()}
|
|
|
|
}
|
2015-01-21 23:53:50 +01:00
|
|
|
|
2015-01-27 23:56:01 +01:00
|
|
|
func (n *GraphNodeConfigModule) DependentOn() []string {
|
2015-01-22 00:37:17 +01:00
|
|
|
vars := n.Module.RawConfig.Variables
|
|
|
|
result := make([]string, 0, len(vars))
|
|
|
|
for _, v := range vars {
|
2015-01-27 23:56:01 +01:00
|
|
|
if vn := varNameForVar(v); vn != "" {
|
|
|
|
result = append(result, vn)
|
|
|
|
}
|
2015-01-22 00:37:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
2015-01-21 23:53:50 +01:00
|
|
|
}
|
|
|
|
|
2015-01-27 23:56:01 +01:00
|
|
|
func (n *GraphNodeConfigModule) Name() string {
|
|
|
|
return fmt.Sprintf("module.%s", n.Module.Name)
|
|
|
|
}
|
|
|
|
|
2015-02-08 01:19:08 +01:00
|
|
|
// GraphNodeExpandable
|
2015-02-12 02:01:08 +01:00
|
|
|
func (n *GraphNodeConfigModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) {
|
|
|
|
// Build the graph first
|
|
|
|
graph, err := b.Build(n.Path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the parameters node to the module
|
|
|
|
t := &ModuleInputTransformer{Variables: make(map[string]string)}
|
|
|
|
if err := t.Transform(graph); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the actual subgraph node
|
|
|
|
return &graphNodeModuleExpanded{
|
|
|
|
Original: n,
|
|
|
|
Graph: graph,
|
|
|
|
InputConfig: n.Module.RawConfig,
|
|
|
|
Variables: t.Variables,
|
|
|
|
}, nil
|
2015-02-08 01:19:08 +01:00
|
|
|
}
|
|
|
|
|
2015-02-10 08:32:28 +01:00
|
|
|
// GraphNodeExpandable
|
|
|
|
func (n *GraphNodeConfigModule) ProvidedBy() []string {
|
|
|
|
// Build up the list of providers by simply going over our configuration
|
|
|
|
// to find the providers that are configured there as well as the
|
|
|
|
// providers that the resources use.
|
|
|
|
config := n.Tree.Config()
|
|
|
|
providers := make(map[string]struct{})
|
|
|
|
for _, p := range config.ProviderConfigs {
|
|
|
|
providers[p.Name] = struct{}{}
|
|
|
|
}
|
|
|
|
for _, r := range config.Resources {
|
|
|
|
providers[resourceProvider(r.Type)] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Turn the map into a string. This makes sure that the list is
|
|
|
|
// de-dupped since we could be going over potentially many resources.
|
|
|
|
result := make([]string, 0, len(providers))
|
|
|
|
for p, _ := range providers {
|
|
|
|
result = append(result, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2015-02-12 07:21:17 +01:00
|
|
|
// GraphNodeConfigOutput represents an output configured within the
|
|
|
|
// configuration.
|
|
|
|
type GraphNodeConfigOutput struct {
|
|
|
|
Output *config.Output
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *GraphNodeConfigOutput) Name() string {
|
|
|
|
return fmt.Sprintf("output.%s", n.Output.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *GraphNodeConfigOutput) DependableName() []string {
|
|
|
|
return []string{n.Name()}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *GraphNodeConfigOutput) DependentOn() []string {
|
|
|
|
vars := n.Output.RawConfig.Variables
|
|
|
|
result := make([]string, 0, len(vars))
|
|
|
|
for _, v := range vars {
|
|
|
|
if vn := varNameForVar(v); vn != "" {
|
|
|
|
result = append(result, vn)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
// GraphNodeEvalable impl.
|
|
|
|
func (n *GraphNodeConfigOutput) EvalTree() EvalNode {
|
2015-02-12 07:33:38 +01:00
|
|
|
return &EvalOpFilter{
|
2015-02-13 04:41:44 +01:00
|
|
|
Ops: []walkOperation{walkRefresh, walkPlan, walkApply},
|
2015-02-12 07:33:38 +01:00
|
|
|
Node: &EvalWriteOutput{
|
|
|
|
Name: n.Output.Name,
|
|
|
|
Value: &EvalInterpolate{Config: n.Output.RawConfig},
|
|
|
|
},
|
|
|
|
}
|
2015-02-12 07:21:17 +01:00
|
|
|
}
|
|
|
|
|
2015-01-21 23:53:50 +01:00
|
|
|
// GraphNodeConfigProvider represents a configured provider within the
|
|
|
|
// configuration graph. These are only immediately in the graph when an
|
|
|
|
// explicit `provider` configuration block is in the configuration.
|
2015-01-21 23:39:16 +01:00
|
|
|
type GraphNodeConfigProvider struct {
|
|
|
|
Provider *config.ProviderConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *GraphNodeConfigProvider) Name() string {
|
|
|
|
return fmt.Sprintf("provider.%s", n.Provider.Name)
|
|
|
|
}
|
|
|
|
|
2015-01-27 23:56:01 +01:00
|
|
|
func (n *GraphNodeConfigProvider) DependableName() []string {
|
|
|
|
return []string{n.Name()}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *GraphNodeConfigProvider) DependentOn() []string {
|
2015-01-22 00:37:17 +01:00
|
|
|
vars := n.Provider.RawConfig.Variables
|
|
|
|
result := make([]string, 0, len(vars))
|
|
|
|
for _, v := range vars {
|
2015-01-27 23:56:01 +01:00
|
|
|
if vn := varNameForVar(v); vn != "" {
|
|
|
|
result = append(result, vn)
|
|
|
|
}
|
2015-01-22 00:37:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
2015-01-21 23:39:16 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 10:43:18 +01:00
|
|
|
// GraphNodeEvalable impl.
|
|
|
|
func (n *GraphNodeConfigProvider) EvalTree() EvalNode {
|
2015-02-05 23:32:36 +01:00
|
|
|
return ProviderEvalTree(n.Provider.Name, n.Provider.RawConfig)
|
2015-02-03 10:43:18 +01:00
|
|
|
}
|
|
|
|
|
2015-01-28 06:48:46 +01:00
|
|
|
// GraphNodeProvider implementation
|
|
|
|
func (n *GraphNodeConfigProvider) ProviderName() string {
|
|
|
|
return n.Provider.Name
|
|
|
|
}
|
|
|
|
|
2015-01-21 23:39:16 +01:00
|
|
|
// GraphNodeConfigResource represents a resource within the config graph.
|
|
|
|
type GraphNodeConfigResource struct {
|
|
|
|
Resource *config.Resource
|
2015-02-12 20:40:48 +01:00
|
|
|
|
|
|
|
// If set to true, this represents a resource that can only be
|
|
|
|
// destroyed. It doesn't mean that the resource WILL be destroyed, only
|
|
|
|
// that logically this node is where it would happen.
|
|
|
|
Destroy bool
|
2015-01-21 23:39:16 +01:00
|
|
|
}
|
|
|
|
|
2015-01-27 05:17:52 +01:00
|
|
|
func (n *GraphNodeConfigResource) DependableName() []string {
|
|
|
|
return []string{n.Resource.Id()}
|
|
|
|
}
|
|
|
|
|
2015-02-08 23:00:13 +01:00
|
|
|
// GraphNodeDependent impl.
|
2015-01-27 23:56:01 +01:00
|
|
|
func (n *GraphNodeConfigResource) DependentOn() []string {
|
2015-01-22 00:37:17 +01:00
|
|
|
result := make([]string, len(n.Resource.DependsOn),
|
|
|
|
len(n.Resource.RawCount.Variables)+
|
|
|
|
len(n.Resource.RawConfig.Variables)+
|
|
|
|
len(n.Resource.DependsOn))
|
|
|
|
copy(result, n.Resource.DependsOn)
|
|
|
|
for _, v := range n.Resource.RawCount.Variables {
|
2015-01-27 23:56:01 +01:00
|
|
|
if vn := varNameForVar(v); vn != "" {
|
|
|
|
result = append(result, vn)
|
|
|
|
}
|
2015-01-22 00:37:17 +01:00
|
|
|
}
|
|
|
|
for _, v := range n.Resource.RawConfig.Variables {
|
2015-01-27 23:56:01 +01:00
|
|
|
if vn := varNameForVar(v); vn != "" {
|
|
|
|
result = append(result, vn)
|
|
|
|
}
|
2015-01-21 23:39:16 +01:00
|
|
|
}
|
|
|
|
|
2015-01-22 00:37:17 +01:00
|
|
|
return result
|
2015-01-21 23:39:16 +01:00
|
|
|
}
|
2015-01-27 23:56:01 +01:00
|
|
|
|
|
|
|
func (n *GraphNodeConfigResource) Name() string {
|
2015-02-12 20:40:48 +01:00
|
|
|
result := n.Resource.Id()
|
|
|
|
if n.Destroy {
|
|
|
|
result += " (destroy)"
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
2015-01-27 23:56:01 +01:00
|
|
|
}
|
2015-01-28 06:48:46 +01:00
|
|
|
|
2015-02-08 23:00:13 +01:00
|
|
|
// GraphNodeDynamicExpandable impl.
|
|
|
|
func (n *GraphNodeConfigResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
2015-02-12 20:40:48 +01:00
|
|
|
// Start creating the steps
|
|
|
|
steps := make([]GraphTransformer, 0, 5)
|
|
|
|
steps = append(steps, &ResourceCountTransformer{
|
|
|
|
Resource: n.Resource,
|
|
|
|
Destroy: n.Destroy,
|
|
|
|
})
|
|
|
|
|
|
|
|
// If we're destroying, then we care about adding orphans to
|
|
|
|
// the graph. Orphans in this case are the leftover resources when
|
|
|
|
// we decrease count.
|
|
|
|
if n.Destroy {
|
|
|
|
state, lock := ctx.State()
|
|
|
|
lock.RLock()
|
|
|
|
defer lock.RUnlock()
|
|
|
|
|
|
|
|
steps = append(steps, &OrphanTransformer{
|
|
|
|
State: state,
|
|
|
|
View: n.Resource.Id(),
|
|
|
|
})
|
2015-02-05 00:44:23 +01:00
|
|
|
}
|
2015-02-08 23:00:13 +01:00
|
|
|
|
2015-02-12 20:40:48 +01:00
|
|
|
// Always end with the root being added
|
|
|
|
steps = append(steps, &RootTransformer{})
|
|
|
|
|
|
|
|
// Build the graph
|
|
|
|
b := &BasicGraphBuilder{Steps: steps}
|
2015-02-08 23:00:13 +01:00
|
|
|
return b.Build(ctx.Path())
|
2015-02-05 00:44:23 +01:00
|
|
|
}
|
|
|
|
|
2015-02-09 02:20:46 +01:00
|
|
|
// GraphNodeEvalable impl.
|
|
|
|
func (n *GraphNodeConfigResource) EvalTree() EvalNode {
|
2015-02-12 08:02:55 +01:00
|
|
|
return &EvalSequence{
|
|
|
|
Nodes: []EvalNode{
|
|
|
|
&EvalInterpolate{Config: n.Resource.RawCount},
|
|
|
|
&EvalOpFilter{
|
|
|
|
Ops: []walkOperation{walkValidate},
|
|
|
|
Node: &EvalValidateCount{Resource: n.Resource},
|
|
|
|
},
|
2015-02-12 20:40:48 +01:00
|
|
|
&EvalCountFixZeroOneBoundary{Resource: n.Resource},
|
2015-02-12 08:02:55 +01:00
|
|
|
},
|
2015-02-09 02:20:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-28 06:48:46 +01:00
|
|
|
// GraphNodeProviderConsumer
|
2015-02-10 08:32:28 +01:00
|
|
|
func (n *GraphNodeConfigResource) ProvidedBy() []string {
|
|
|
|
return []string{resourceProvider(n.Resource.Type)}
|
2015-01-28 06:48:46 +01:00
|
|
|
}
|
2015-02-09 19:14:09 +01:00
|
|
|
|
|
|
|
// GraphNodeProvisionerConsumer
|
|
|
|
func (n *GraphNodeConfigResource) ProvisionedBy() []string {
|
|
|
|
result := make([]string, len(n.Resource.Provisioners))
|
|
|
|
for i, p := range n.Resource.Provisioners {
|
|
|
|
result[i] = p.Type
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
2015-02-12 02:01:08 +01:00
|
|
|
|
2015-02-12 19:54:28 +01:00
|
|
|
// GraphNodeDestroyable
|
|
|
|
func (n *GraphNodeConfigResource) DestroyNode() dag.Vertex {
|
2015-02-12 20:40:48 +01:00
|
|
|
// If we're already a destroy node, then don't do anything
|
|
|
|
if n.Destroy {
|
|
|
|
return nil
|
|
|
|
}
|
2015-02-12 19:54:28 +01:00
|
|
|
|
2015-02-12 20:40:48 +01:00
|
|
|
// Just make a copy that is set to destroy
|
|
|
|
result := *n
|
|
|
|
result.Destroy = true
|
2015-02-12 19:54:28 +01:00
|
|
|
|
2015-02-12 20:40:48 +01:00
|
|
|
return &result
|
2015-02-12 19:54:28 +01:00
|
|
|
}
|
|
|
|
|
2015-02-12 02:01:08 +01:00
|
|
|
// graphNodeModuleExpanded represents a module where the graph has
|
|
|
|
// been expanded. It stores the graph of the module as well as a reference
|
|
|
|
// to the map of variables.
|
|
|
|
type graphNodeModuleExpanded struct {
|
|
|
|
Original dag.Vertex
|
|
|
|
Graph *Graph
|
|
|
|
InputConfig *config.RawConfig
|
|
|
|
|
|
|
|
// Variables is a map of the input variables. This reference should
|
|
|
|
// be shared with ModuleInputTransformer in order to create a connection
|
|
|
|
// where the variables are set properly.
|
|
|
|
Variables map[string]string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *graphNodeModuleExpanded) Name() string {
|
|
|
|
return fmt.Sprintf("%s (expanded)", dag.VertexName(n.Original))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GraphNodeEvalable impl.
|
|
|
|
func (n *graphNodeModuleExpanded) EvalTree() EvalNode {
|
2015-02-12 21:49:48 +01:00
|
|
|
return &EvalSequence{
|
|
|
|
Nodes: []EvalNode{
|
|
|
|
&EvalVariableBlock{
|
|
|
|
Config: &EvalInterpolate{Config: n.InputConfig},
|
|
|
|
Variables: n.Variables,
|
|
|
|
},
|
|
|
|
|
|
|
|
&EvalOpFilter{
|
|
|
|
Ops: []walkOperation{walkPlanDestroy},
|
|
|
|
Node: &EvalSequence{
|
|
|
|
Nodes: []EvalNode{
|
|
|
|
&EvalDiffDestroyModule{Path: n.Graph.Path},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-12 02:01:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GraphNodeSubgraph impl.
|
|
|
|
func (n *graphNodeModuleExpanded) Subgraph() *Graph {
|
|
|
|
return n.Graph
|
|
|
|
}
|