terraform: start FlattenGraph impl.

This commit is contained in:
Mitchell Hashimoto 2015-04-30 20:46:54 -07:00
parent 5e767f63b9
commit 12c30feb0f
6 changed files with 117 additions and 8 deletions

View File

@ -2,6 +2,7 @@ package terraform
import ( import (
"fmt" "fmt"
"strings"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/config/module"
@ -152,7 +153,75 @@ func (n *graphNodeModuleExpanded) EvalTree() EvalNode {
} }
} }
// GraphNodeFlattenable impl.
func (n *graphNodeModuleExpanded) FlattenGraph() *Graph {
graph := n.Subgraph()
// Build the string that represents the path. We do this once here
// so that we only have to compute it once. The block below is in {}
// so that parts drops out of scope immediately.
var pathStr string
{
parts := make([]string, 0, len(graph.Path)*2)
for _, p := range graph.Path[1:] {
parts = append(parts, "module", p)
}
pathStr = strings.Join(parts, ".")
}
// Go over each vertex in the graph and wrap the configuration
// items so that the dependencies properly map to the modules.
// See the docs for graphNodeModuleWrappable for more info.
for _, v := range graph.Vertices() {
if sn, ok := v.(graphNodeModuleSkippable); ok && sn.FlattenSkip() {
graph.Remove(v)
continue
}
wn, ok := v.(graphNodeModuleWrappable)
if !ok {
panic("unwrappable node: " + dag.VertexName(v))
}
graph.Replace(v, &graphNodeModuleFlatWrap{
graphNodeModuleWrappable: wn,
Path: graph.Path,
PathString: pathStr,
})
}
return graph
}
// GraphNodeSubgraph impl. // GraphNodeSubgraph impl.
func (n *graphNodeModuleExpanded) Subgraph() *Graph { func (n *graphNodeModuleExpanded) Subgraph() *Graph {
return n.Graph return n.Graph
} }
// This interface can be implemented to be skipped/ignored when
// flattening the module graph.
type graphNodeModuleSkippable interface {
FlattenSkip() bool
}
// This is the interface that all nodes within a module graph must
// implement to be wrapped for flattening.
type graphNodeModuleWrappable interface {
graphNodeConfig
}
// graphNodeModuleFlatWrap wraps elements of the module graph
// when they are flattened so that the dependency information is
// correct.
type graphNodeModuleFlatWrap struct {
graphNodeModuleWrappable
Path []string
PathString string
}
func (n *graphNodeModuleFlatWrap) Name() string {
return fmt.Sprintf("%s.%s", n.PathString, n.graphNodeModuleWrappable.Name())
}

View File

@ -39,3 +39,42 @@ func TestGraphNodeConfigModuleExpand(t *testing.T) {
t.Fatalf("bad:\n\n%s", actual) t.Fatalf("bad:\n\n%s", actual)
} }
} }
func TestGraphNodeConfigModuleExpandFlatten(t *testing.T) {
mod := testModule(t, "graph-node-module-flatten")
node := &GraphNodeConfigModule{
Path: []string{RootModuleName, "child"},
Module: &config.Module{},
Tree: nil,
}
g, err := node.Expand(&BasicGraphBuilder{
Steps: []GraphTransformer{
&ConfigTransformer{Module: mod},
},
})
if err != nil {
t.Fatalf("err: %s", err)
}
fg := g.(GraphNodeFlattenable)
actual := strings.TrimSpace(fg.FlattenGraph().String())
expected := strings.TrimSpace(testGraphNodeModuleExpandFlattenStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
}
}
const testGraphNodeModuleExpandStr = `
aws_instance.bar
aws_instance.foo
aws_instance.foo
module inputs
module inputs
`
const testGraphNodeModuleExpandFlattenStr = `
module.child.aws_instance.foo
`

View File

@ -113,11 +113,3 @@ func TestGraphNodeConfigVariable_impl(t *testing.T) {
var _ dag.NamedVertex = new(GraphNodeConfigVariable) var _ dag.NamedVertex = new(GraphNodeConfigVariable)
var _ graphNodeConfig = new(GraphNodeConfigVariable) var _ graphNodeConfig = new(GraphNodeConfigVariable)
} }
const testGraphNodeModuleExpandStr = `
aws_instance.bar
aws_instance.foo
aws_instance.foo
module inputs
module inputs
`

View File

@ -0,0 +1 @@
resource "aws_instance" "foo" {}

View File

@ -0,0 +1,3 @@
module "child" {
source = "./child"
}

View File

@ -45,3 +45,8 @@ func (n *graphNodeModuleInput) Name() string {
func (n *graphNodeModuleInput) EvalTree() EvalNode { func (n *graphNodeModuleInput) EvalTree() EvalNode {
return &EvalSetVariables{Variables: n.Variables} return &EvalSetVariables{Variables: n.Variables}
} }
// graphNodeModuleSkippable impl.
func (n *graphNodeModuleInput) FlattenSkip() bool {
return true
}