terraform: re-enable dot-graphs

This commit is contained in:
Mitchell Hashimoto 2015-02-19 22:58:42 -08:00
parent 4b6f258f1f
commit c2593f6ada
5 changed files with 128 additions and 1 deletions

View File

@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"os" "os"
"strings" "strings"
"github.com/hashicorp/terraform/terraform"
) )
// GraphCommand is a Command implementation that takes a Terraform // GraphCommand is a Command implementation that takes a Terraform
@ -56,7 +58,7 @@ func (c *GraphCommand) Run(args []string) int {
return 1 return 1
} }
c.Ui.Output(g.String()) c.Ui.Output(terraform.GraphDot(g, nil))
return 0 return 0
} }

View File

@ -173,6 +173,17 @@ func (n *GraphNodeConfigProvider) ProviderName() string {
return n.Provider.Name return n.Provider.Name
} }
// GraphNodeDotter impl.
func (n *GraphNodeConfigProvider) Dot(name string) string {
return fmt.Sprintf(
"\"%s\" [\n"+
"\tlabel=\"%s\"\n"+
"\tshape=diamond\n"+
"];",
name,
n.Name())
}
// GraphNodeConfigResource represents a resource within the config graph. // GraphNodeConfigResource represents a resource within the config graph.
type GraphNodeConfigResource struct { type GraphNodeConfigResource struct {
Resource *config.Resource Resource *config.Resource
@ -235,6 +246,21 @@ func (n *GraphNodeConfigResource) Name() string {
return result return result
} }
// GraphNodeDotter impl.
func (n *GraphNodeConfigResource) Dot(name string) string {
if n.DestroyMode != DestroyNone {
return ""
}
return fmt.Sprintf(
"\"%s\" [\n"+
"\tlabel=\"%s\"\n"+
"\tshape=box\n"+
"];",
name,
n.Name())
}
// GraphNodeDynamicExpandable impl. // GraphNodeDynamicExpandable impl.
func (n *GraphNodeConfigResource) DynamicExpand(ctx EvalContext) (*Graph, error) { func (n *GraphNodeConfigResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
state, lock := ctx.State() state, lock := ctx.State()
@ -476,6 +502,17 @@ func (n *graphNodeModuleExpanded) Name() string {
return fmt.Sprintf("%s (expanded)", dag.VertexName(n.Original)) return fmt.Sprintf("%s (expanded)", dag.VertexName(n.Original))
} }
// GraphNodeDotter impl.
func (n *graphNodeModuleExpanded) Dot(name string) string {
return fmt.Sprintf(
"\"%s\" [\n"+
"\tlabel=\"%s\"\n"+
"\tshape=component\n"+
"];",
name,
dag.VertexName(n.Original))
}
// GraphNodeEvalable impl. // GraphNodeEvalable impl.
func (n *graphNodeModuleExpanded) EvalTree() EvalNode { func (n *graphNodeModuleExpanded) EvalTree() EvalNode {
var resourceConfig *ResourceConfig var resourceConfig *ResourceConfig

71
terraform/graph_dot.go Normal file
View File

@ -0,0 +1,71 @@
package terraform
import (
"bufio"
"bytes"
"fmt"
"strings"
"github.com/hashicorp/terraform/dag"
)
// GraphNodeDotter can be implemented by a node to cause it to be included
// in the dot graph. The Dot method will be called which is expected to
// return a representation of this node.
type GraphNodeDotter interface {
// Dot is called to return the dot formatting for the node.
// The parameter must be the title of the node.
Dot(string) string
}
// GraphDotOpts are the options for generating a dot formatted Graph.
type GraphDotOpts struct{}
// GraphDot returns the dot formatting of a visual representation of
// the given Terraform graph.
func GraphDot(g *Graph, opts *GraphDotOpts) string {
buf := new(bytes.Buffer)
// Start the graph
buf.WriteString("digraph {\n")
buf.WriteString("\tcompound = true;\n")
// Go through all the vertices and draw it
vertices := g.Vertices()
dotVertices := make(map[dag.Vertex]struct{}, len(vertices))
for _, v := range vertices {
if dn, ok := v.(GraphNodeDotter); !ok {
continue
} else if dn.Dot("fake") == "" {
continue
}
dotVertices[v] = struct{}{}
}
for v, _ := range dotVertices {
dn := v.(GraphNodeDotter)
scanner := bufio.NewScanner(strings.NewReader(
dn.Dot(dag.VertexName(v))))
for scanner.Scan() {
buf.WriteString("\t" + scanner.Text() + "\n")
}
// Draw all the edges
for _, t := range g.DownEdges(v).List() {
target := t.(dag.Vertex)
if _, ok := dotVertices[target]; !ok {
continue
}
buf.WriteString(fmt.Sprintf(
"\t\"%s\" -> \"%s\";\n",
dag.VertexName(v),
dag.VertexName(target)))
}
}
// End the graph
buf.WriteString("}\n")
return buf.String()
}

View File

@ -111,6 +111,17 @@ func (n *graphNodeMissingProvider) ProviderName() string {
return n.ProviderNameValue return n.ProviderNameValue
} }
// GraphNodeDotter impl.
func (n *graphNodeMissingProvider) Dot(name string) string {
return fmt.Sprintf(
"\"%s\" [\n"+
"\tlabel=\"%s\"\n"+
"\tshape=diamond\n"+
"];",
name,
n.Name())
}
func providerVertexMap(g *Graph) map[string]dag.Vertex { func providerVertexMap(g *Graph) map[string]dag.Vertex {
m := make(map[string]dag.Vertex) m := make(map[string]dag.Vertex)
for _, v := range g.Vertices() { for _, v := range g.Vertices() {

View File

@ -1,6 +1,8 @@
package terraform package terraform
import ( import (
"fmt"
"github.com/hashicorp/terraform/dag" "github.com/hashicorp/terraform/dag"
) )
@ -36,3 +38,7 @@ type graphNodeRoot struct{}
func (n graphNodeRoot) Name() string { func (n graphNodeRoot) Name() string {
return "root" return "root"
} }
func (n graphNodeRoot) Dot(name string) string {
return fmt.Sprintf("\"%s\" [shape=circle];", name)
}