github.com/spirius/terraform@v0.10.0-beta2.0.20170714185654-87b2c0cf8fea/command/graph.go (about) 1 package command 2 3 import ( 4 "flag" 5 "fmt" 6 "strings" 7 8 "github.com/hashicorp/terraform/backend" 9 "github.com/hashicorp/terraform/config" 10 "github.com/hashicorp/terraform/config/module" 11 "github.com/hashicorp/terraform/dag" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 // GraphCommand is a Command implementation that takes a Terraform 16 // configuration and outputs the dependency tree in graphical form. 17 type GraphCommand struct { 18 Meta 19 } 20 21 func (c *GraphCommand) Run(args []string) int { 22 var moduleDepth int 23 var verbose bool 24 var drawCycles bool 25 var graphTypeStr string 26 27 args, err := c.Meta.process(args, false) 28 if err != nil { 29 return 1 30 } 31 32 cmdFlags := flag.NewFlagSet("graph", flag.ContinueOnError) 33 c.addModuleDepthFlag(cmdFlags, &moduleDepth) 34 cmdFlags.BoolVar(&verbose, "verbose", false, "verbose") 35 cmdFlags.BoolVar(&drawCycles, "draw-cycles", false, "draw-cycles") 36 cmdFlags.StringVar(&graphTypeStr, "type", "", "type") 37 cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } 38 if err := cmdFlags.Parse(args); err != nil { 39 return 1 40 } 41 42 configPath, err := ModulePath(cmdFlags.Args()) 43 if err != nil { 44 c.Ui.Error(err.Error()) 45 return 1 46 } 47 48 // Check if the path is a plan 49 plan, err := c.Plan(configPath) 50 if err != nil { 51 c.Ui.Error(err.Error()) 52 return 1 53 } 54 if plan != nil { 55 // Reset for backend loading 56 configPath = "" 57 } 58 59 // Load the module 60 var mod *module.Tree 61 if plan == nil { 62 mod, err = c.Module(configPath) 63 if err != nil { 64 c.Ui.Error(fmt.Sprintf("Failed to load root config module: %s", err)) 65 return 1 66 } 67 } 68 69 var conf *config.Config 70 if mod != nil { 71 conf = mod.Config() 72 } 73 74 // Load the backend 75 b, err := c.Backend(&BackendOpts{ 76 Config: conf, 77 Plan: plan, 78 }) 79 if err != nil { 80 c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err)) 81 return 1 82 } 83 84 // We require a local backend 85 local, ok := b.(backend.Local) 86 if !ok { 87 c.Ui.Error(ErrUnsupportedLocalOp) 88 return 1 89 } 90 91 // Build the operation 92 opReq := c.Operation() 93 opReq.Module = mod 94 opReq.Plan = plan 95 96 // Get the context 97 ctx, _, err := local.Context(opReq) 98 if err != nil { 99 c.Ui.Error(err.Error()) 100 return 1 101 } 102 103 // Determine the graph type 104 graphType := terraform.GraphTypePlan 105 if plan != nil { 106 graphType = terraform.GraphTypeApply 107 } 108 109 if graphTypeStr != "" { 110 v, ok := terraform.GraphTypeMap[graphTypeStr] 111 if !ok { 112 c.Ui.Error(fmt.Sprintf("Invalid graph type requested: %s", graphTypeStr)) 113 return 1 114 } 115 116 graphType = v 117 } 118 119 // Skip validation during graph generation - we want to see the graph even if 120 // it is invalid for some reason. 121 g, err := ctx.Graph(graphType, &terraform.ContextGraphOpts{ 122 Verbose: verbose, 123 Validate: false, 124 }) 125 if err != nil { 126 c.Ui.Error(fmt.Sprintf("Error creating graph: %s", err)) 127 return 1 128 } 129 130 graphStr, err := terraform.GraphDot(g, &dag.DotOpts{ 131 DrawCycles: drawCycles, 132 MaxDepth: moduleDepth, 133 Verbose: verbose, 134 }) 135 if err != nil { 136 c.Ui.Error(fmt.Sprintf("Error converting graph: %s", err)) 137 return 1 138 } 139 140 c.Ui.Output(graphStr) 141 142 return 0 143 } 144 145 func (c *GraphCommand) Help() string { 146 helpText := ` 147 Usage: terraform graph [options] [DIR] 148 149 Outputs the visual execution graph of Terraform resources according to 150 configuration files in DIR (or the current directory if omitted). 151 152 The graph is outputted in DOT format. The typical program that can 153 read this format is GraphViz, but many web services are also available 154 to read this format. 155 156 The -type flag can be used to control the type of graph shown. Terraform 157 creates different graphs for different operations. See the options below 158 for the list of types supported. The default type is "plan" if a 159 configuration is given, and "apply" if a plan file is passed as an 160 argument. 161 162 Options: 163 164 -draw-cycles Highlight any cycles in the graph with colored edges. 165 This helps when diagnosing cycle errors. 166 167 -no-color If specified, output won't contain any color. 168 169 -type=plan Type of graph to output. Can be: plan, plan-destroy, apply, 170 validate, input, refresh. 171 172 173 ` 174 return strings.TrimSpace(helpText) 175 } 176 177 func (c *GraphCommand) Synopsis() string { 178 return "Create a visual graph of Terraform resources" 179 }