github.com/bpineau/terraform@v0.8.0-rc1.0.20161126184705-a8886012d185/command/graph.go (about)

     1  package command
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/terraform/dag"
    10  	"github.com/hashicorp/terraform/terraform"
    11  )
    12  
    13  // GraphCommand is a Command implementation that takes a Terraform
    14  // configuration and outputs the dependency tree in graphical form.
    15  type GraphCommand struct {
    16  	Meta
    17  }
    18  
    19  func (c *GraphCommand) Run(args []string) int {
    20  	var moduleDepth int
    21  	var verbose bool
    22  	var drawCycles bool
    23  
    24  	args = c.Meta.process(args, false)
    25  
    26  	cmdFlags := flag.NewFlagSet("graph", flag.ContinueOnError)
    27  	c.addModuleDepthFlag(cmdFlags, &moduleDepth)
    28  	cmdFlags.BoolVar(&verbose, "verbose", false, "verbose")
    29  	cmdFlags.BoolVar(&drawCycles, "draw-cycles", false, "draw-cycles")
    30  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    31  	if err := cmdFlags.Parse(args); err != nil {
    32  		return 1
    33  	}
    34  
    35  	var path string
    36  	args = cmdFlags.Args()
    37  	if len(args) > 1 {
    38  		c.Ui.Error("The graph command expects one argument.\n")
    39  		cmdFlags.Usage()
    40  		return 1
    41  	} else if len(args) == 1 {
    42  		path = args[0]
    43  	} else {
    44  		var err error
    45  		path, err = os.Getwd()
    46  		if err != nil {
    47  			c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
    48  		}
    49  	}
    50  
    51  	ctx, _, err := c.Context(contextOpts{
    52  		Path:      path,
    53  		StatePath: "",
    54  	})
    55  	if err != nil {
    56  		c.Ui.Error(fmt.Sprintf("Error loading Terraform: %s", err))
    57  		return 1
    58  	}
    59  
    60  	// Skip validation during graph generation - we want to see the graph even if
    61  	// it is invalid for some reason.
    62  	g, err := ctx.Graph(&terraform.ContextGraphOpts{
    63  		Verbose:  verbose,
    64  		Validate: false,
    65  	})
    66  	if err != nil {
    67  		c.Ui.Error(fmt.Sprintf("Error creating graph: %s", err))
    68  		return 1
    69  	}
    70  
    71  	graphStr, err := terraform.GraphDot(g, &dag.DotOpts{
    72  		DrawCycles: drawCycles,
    73  		MaxDepth:   moduleDepth,
    74  		Verbose:    verbose,
    75  	})
    76  	if err != nil {
    77  		c.Ui.Error(fmt.Sprintf("Error converting graph: %s", err))
    78  		return 1
    79  	}
    80  
    81  	c.Ui.Output(graphStr)
    82  
    83  	return 0
    84  }
    85  
    86  func (c *GraphCommand) Help() string {
    87  	helpText := `
    88  Usage: terraform graph [options] [DIR]
    89  
    90    Outputs the visual dependency graph of Terraform resources according to
    91    configuration files in DIR (or the current directory if omitted).
    92  
    93    The graph is outputted in DOT format. The typical program that can
    94    read this format is GraphViz, but many web services are also available
    95    to read this format.
    96  
    97  Options:
    98  
    99    -draw-cycles         Highlight any cycles in the graph with colored edges.
   100                         This helps when diagnosing cycle errors.
   101  
   102    -module-depth=n      The maximum depth to expand modules. By default this is
   103                         -1, which will expand resources within all modules.
   104  
   105    -verbose             Generate a verbose, "worst-case" graph, with all nodes
   106                         for potential operations in place.
   107  
   108    -no-color           If specified, output won't contain any color.
   109  
   110  `
   111  	return strings.TrimSpace(helpText)
   112  }
   113  
   114  func (c *GraphCommand) Synopsis() string {
   115  	return "Create a visual graph of Terraform resources"
   116  }