terraform: support graphing modules
This commit is contained in:
parent
6904c131a7
commit
72e6f97093
|
@ -6,6 +6,7 @@ terraform.tfstate
|
||||||
bin/
|
bin/
|
||||||
config/y.go
|
config/y.go
|
||||||
config/y.output
|
config/y.output
|
||||||
|
modules-dev/
|
||||||
pkg/
|
pkg/
|
||||||
vendor/
|
vendor/
|
||||||
website/.vagrant
|
website/.vagrant
|
||||||
|
|
|
@ -16,9 +16,12 @@ type GraphCommand struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GraphCommand) Run(args []string) int {
|
func (c *GraphCommand) Run(args []string) int {
|
||||||
|
var moduleDepth int
|
||||||
|
|
||||||
args = c.Meta.process(args, false)
|
args = c.Meta.process(args, false)
|
||||||
|
|
||||||
cmdFlags := flag.NewFlagSet("graph", flag.ContinueOnError)
|
cmdFlags := flag.NewFlagSet("graph", flag.ContinueOnError)
|
||||||
|
cmdFlags.IntVar(&moduleDepth, "module-depth", 0, "module-depth")
|
||||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||||
if err := cmdFlags.Parse(args); err != nil {
|
if err := cmdFlags.Parse(args); err != nil {
|
||||||
return 1
|
return 1
|
||||||
|
@ -55,7 +58,11 @@ func (c *GraphCommand) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Ui.Output(terraform.GraphDot(g))
|
opts := &terraform.GraphDotOpts{
|
||||||
|
ModuleDepth: moduleDepth,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Ui.Output(terraform.GraphDot(g, opts))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -73,6 +80,11 @@ Usage: terraform graph [options] PATH
|
||||||
read this format is GraphViz, but many web services are also available
|
read this format is GraphViz, but many web services are also available
|
||||||
to read this format.
|
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)
|
return strings.TrimSpace(helpText)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,34 @@ package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/depgraph"
|
"github.com/hashicorp/terraform/depgraph"
|
||||||
"github.com/hashicorp/terraform/digraph"
|
"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
|
// GraphDot returns the dot formatting of a visual representation of
|
||||||
// the given Terraform graph.
|
// the given Terraform graph.
|
||||||
func GraphDot(g *depgraph.Graph) string {
|
func GraphDot(g *depgraph.Graph, opts *GraphDotOpts) string {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
if opts.depth == 0 {
|
||||||
buf.WriteString("digraph {\n")
|
buf.WriteString("digraph {\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Determine and add the title
|
// Determine and add the title
|
||||||
// graphDotTitle(buf, g)
|
// graphDotTitle(buf, g)
|
||||||
|
@ -23,7 +40,13 @@ func GraphDot(g *depgraph.Graph) string {
|
||||||
// Add all the resource providers
|
// Add all the resource providers
|
||||||
graphDotAddResourceProviders(buf, g)
|
graphDotAddResourceProviders(buf, g)
|
||||||
|
|
||||||
|
// Add all the modules
|
||||||
|
graphDotAddModules(buf, g, opts)
|
||||||
|
|
||||||
|
if opts.depth == 0 {
|
||||||
buf.WriteString("}\n")
|
buf.WriteString("}\n")
|
||||||
|
}
|
||||||
|
|
||||||
return buf.String()
|
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) {
|
func graphDotAddResources(buf *bytes.Buffer, g *depgraph.Graph) {
|
||||||
// Determine if we have diffs. If we do, then we're graphing a
|
// Determine if we have diffs. If we do, then we're graphing a
|
||||||
// plan, which alters our graph a bit.
|
// plan, which alters our graph a bit.
|
||||||
|
|
Loading…
Reference in New Issue