github.com/archgrove/terraform@v0.9.5-0.20170502093151-adb789f0f8d2/command/plan.go (about) 1 package command 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/hashicorp/terraform/backend" 9 "github.com/hashicorp/terraform/config/module" 10 ) 11 12 // PlanCommand is a Command implementation that compares a Terraform 13 // configuration to an actual infrastructure and shows the differences. 14 type PlanCommand struct { 15 Meta 16 } 17 18 func (c *PlanCommand) Run(args []string) int { 19 var destroy, refresh, detailed bool 20 var outPath string 21 var moduleDepth int 22 23 args = c.Meta.process(args, true) 24 25 cmdFlags := c.Meta.flagSet("plan") 26 cmdFlags.BoolVar(&destroy, "destroy", false, "destroy") 27 cmdFlags.BoolVar(&refresh, "refresh", true, "refresh") 28 c.addModuleDepthFlag(cmdFlags, &moduleDepth) 29 cmdFlags.StringVar(&outPath, "out", "", "path") 30 cmdFlags.IntVar( 31 &c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism") 32 cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path") 33 cmdFlags.BoolVar(&detailed, "detailed-exitcode", false, "detailed-exitcode") 34 cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state") 35 cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout") 36 cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } 37 if err := cmdFlags.Parse(args); err != nil { 38 return 1 39 } 40 41 configPath, err := ModulePath(cmdFlags.Args()) 42 if err != nil { 43 c.Ui.Error(err.Error()) 44 return 1 45 } 46 47 // Check if the path is a plan 48 plan, err := c.Plan(configPath) 49 if err != nil { 50 c.Ui.Error(err.Error()) 51 return 1 52 } 53 if plan != nil { 54 // Disable refreshing no matter what since we only want to show the plan 55 refresh = false 56 57 // Set the config path to empty for backend loading 58 configPath = "" 59 } 60 61 // Load the module if we don't have one yet (not running from plan) 62 var mod *module.Tree 63 if plan == nil { 64 mod, err = c.Module(configPath) 65 if err != nil { 66 c.Ui.Error(fmt.Sprintf("Failed to load root config module: %s", err)) 67 return 1 68 } 69 } 70 71 // Load the backend 72 b, err := c.Backend(&BackendOpts{ 73 ConfigPath: configPath, 74 Plan: plan, 75 }) 76 if err != nil { 77 c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err)) 78 return 1 79 } 80 81 // Build the operation 82 opReq := c.Operation() 83 opReq.Destroy = destroy 84 opReq.Module = mod 85 opReq.Plan = plan 86 opReq.PlanRefresh = refresh 87 opReq.PlanOutPath = outPath 88 opReq.Type = backend.OperationTypePlan 89 90 // Perform the operation 91 op, err := b.Operation(context.Background(), opReq) 92 if err != nil { 93 c.Ui.Error(fmt.Sprintf("Error starting operation: %s", err)) 94 return 1 95 } 96 97 // Wait for the operation to complete 98 <-op.Done() 99 if err := op.Err; err != nil { 100 c.Ui.Error(err.Error()) 101 return 1 102 } 103 104 /* 105 err = terraform.SetDebugInfo(DefaultDataDir) 106 if err != nil { 107 c.Ui.Error(err.Error()) 108 return 1 109 } 110 */ 111 112 if detailed && !op.PlanEmpty { 113 return 2 114 } 115 116 return 0 117 } 118 119 func (c *PlanCommand) Help() string { 120 helpText := ` 121 Usage: terraform plan [options] [DIR-OR-PLAN] 122 123 Generates an execution plan for Terraform. 124 125 This execution plan can be reviewed prior to running apply to get a 126 sense for what Terraform will do. Optionally, the plan can be saved to 127 a Terraform plan file, and apply can take this plan file to execute 128 this plan exactly. 129 130 If a saved plan is passed as an argument, this command will output 131 the saved plan contents. It will not modify the given plan. 132 133 Options: 134 135 -destroy If set, a plan will be generated to destroy all resources 136 managed by the given configuration and state. 137 138 -detailed-exitcode Return detailed exit codes when the command exits. This 139 will change the meaning of exit codes to: 140 0 - Succeeded, diff is empty (no changes) 141 1 - Errored 142 2 - Succeeded, there is a diff 143 144 -input=true Ask for input for variables if not directly set. 145 146 -lock=true Lock the state file when locking is supported. 147 148 -lock-timeout=0s Duration to retry a state lock. 149 150 -module-depth=n Specifies the depth of modules to show in the output. 151 This does not affect the plan itself, only the output 152 shown. By default, this is -1, which will expand all. 153 154 -no-color If specified, output won't contain any color. 155 156 -out=path Write a plan file to the given path. This can be used as 157 input to the "apply" command. 158 159 -parallelism=n Limit the number of concurrent operations. Defaults to 10. 160 161 -refresh=true Update state prior to checking for differences. 162 163 -state=statefile Path to a Terraform state file to use to look 164 up Terraform-managed resources. By default it will 165 use the state "terraform.tfstate" if it exists. 166 167 -target=resource Resource to target. Operation will be limited to this 168 resource and its dependencies. This flag can be used 169 multiple times. 170 171 -var 'foo=bar' Set a variable in the Terraform configuration. This 172 flag can be set multiple times. 173 174 -var-file=foo Set variables in the Terraform configuration from 175 a file. If "terraform.tfvars" is present, it will be 176 automatically loaded if this flag is not specified. 177 ` 178 return strings.TrimSpace(helpText) 179 } 180 181 func (c *PlanCommand) Synopsis() string { 182 return "Generate and show an execution plan" 183 }