terraform: support graphing modules

This commit is contained in:
Mitchell Hashimoto 2014-09-24 17:36:27 -07:00
parent 6904c131a7
commit 72e6f97093
3 changed files with 99 additions and 4 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ terraform.tfstate
bin/
config/y.go
config/y.output
modules-dev/
pkg/
vendor/
website/.vagrant

View File

@ -16,9 +16,12 @@ type GraphCommand struct {
}
func (c *GraphCommand) Run(args []string) int {
var moduleDepth int
args = c.Meta.process(args, false)
cmdFlags := flag.NewFlagSet("graph", flag.ContinueOnError)
cmdFlags.IntVar(&moduleDepth, "module-depth", 0, "module-depth")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil {
return 1
@ -55,7 +58,11 @@ func (c *GraphCommand) Run(args []string) int {
return 1
}
c.Ui.Output(terraform.GraphDot(g))
opts := &terraform.GraphDotOpts{
ModuleDepth: moduleDepth,
}
c.Ui.Output(terraform.GraphDot(g, opts))
return 0
}
@ -73,6 +80,11 @@ Usage: terraform graph [options] PATH
read this format is GraphViz, but many web services are also available
to read this format.
Options:
-module-depth=n The maximum depth to expand modules. By default this is
zero, which will not expand modules at all.
`
return strings.TrimSpace(helpText)
}

View File

@ -2,17 +2,34 @@ package terraform
import (
"bytes"
"bufio"
"fmt"
"strings"
"github.com/hashicorp/terraform/depgraph"
"github.com/hashicorp/terraform/digraph"
)
// GraphDotOpts are options for turning a graph into dot format.
type GraphDotOpts struct {
// ModuleDepth is the depth of modules to expand. Zero is no expansion,
// one expands the first set of modules, etc. If this is set to -1, then
// all modules are expanded.
ModuleDepth int
// Depth is an internal track of what depth we're at within
// the graph, used to control indentation and other such things.
depth int
}
// GraphDot returns the dot formatting of a visual representation of
// the given Terraform graph.
func GraphDot(g *depgraph.Graph) string {
func GraphDot(g *depgraph.Graph, opts *GraphDotOpts) string {
buf := new(bytes.Buffer)
buf.WriteString("digraph {\n")
if opts.depth == 0 {
buf.WriteString("digraph {\n")
}
// Determine and add the title
// graphDotTitle(buf, g)
@ -23,7 +40,13 @@ func GraphDot(g *depgraph.Graph) string {
// Add all the resource providers
graphDotAddResourceProviders(buf, g)
buf.WriteString("}\n")
// Add all the modules
graphDotAddModules(buf, g, opts)
if opts.depth == 0 {
buf.WriteString("}\n")
}
return buf.String()
}
@ -39,6 +62,65 @@ func graphDotAddRoot(buf *bytes.Buffer, n *depgraph.Noun) {
}
}
func graphDotAddModules(buf *bytes.Buffer, g *depgraph.Graph, opts *GraphDotOpts) {
for _, n := range g.Nouns {
_, ok := n.Meta.(*GraphNodeModule)
if !ok {
continue
}
if opts.ModuleDepth == opts.depth {
// We're not expanding, so just add the module on its own
graphDotAddModuleSingle(buf, n, opts)
} else {
// We're expanding
graphDotAddModuleExpand(buf, n, opts)
}
}
}
func graphDotAddModuleExpand(
buf *bytes.Buffer, n *depgraph.Noun, opts *GraphDotOpts) {
m := n.Meta.(*GraphNodeModule)
tab := strings.Repeat("\t", opts.depth+1)
// Wrap ourselves in a subgraph
buf.WriteString(fmt.Sprintf("%ssubgraph \"%s\" {\n", tab, n.Name))
defer buf.WriteString(fmt.Sprintf("%s}\n", tab))
// Graph the subgraph just as we would any other graph
subOpts := *opts
subOpts.depth++
subStr := GraphDot(m.Graph, &subOpts)
// Tab all the lines of the subgraph
s := bufio.NewScanner(strings.NewReader(subStr))
for s.Scan() {
buf.WriteString(fmt.Sprintf("%s%s\n", tab, s.Text()))
}
}
func graphDotAddModuleSingle(
buf *bytes.Buffer, n *depgraph.Noun, opts *GraphDotOpts) {
tab := strings.Repeat("\t", opts.depth+1)
//m := n.Meta.(*GraphNodeModule)
// Create this node.
buf.WriteString(fmt.Sprintf("%s\"%s\" [\n", tab, n))
buf.WriteString(fmt.Sprintf("%s\tshape=component\n", tab))
buf.WriteString(fmt.Sprintf("%s];\n", tab))
for _, e := range n.Edges() {
target := e.Tail()
buf.WriteString(fmt.Sprintf(
"%s\"%s\" -> \"%s\";\n",
tab,
n,
target))
}
}
func graphDotAddResources(buf *bytes.Buffer, g *depgraph.Graph) {
// Determine if we have diffs. If we do, then we're graphing a
// plan, which alters our graph a bit.