diff --git a/backend/backend.go b/backend/backend.go index 3708cf40ab50..efa42d4b6fa6 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -121,10 +121,11 @@ type Operation struct { // The options below are more self-explanatory and affect the runtime // behavior of the operation. - Destroy bool - Targets []string - Variables map[string]interface{} - AutoApprove bool + Destroy bool + Targets []string + Variables map[string]interface{} + AutoApprove bool + DestroyForce bool // Input/output/control options. UIIn terraform.UIInput diff --git a/backend/local/backend_apply.go b/backend/local/backend_apply.go index 7ebee241e6d7..3eac6dafa08d 100644 --- a/backend/local/backend_apply.go +++ b/backend/local/backend_apply.go @@ -98,18 +98,46 @@ func (b *Local) opApply( trivialPlan := plan.Diff == nil || plan.Diff.Empty() hasUI := op.UIOut != nil && op.UIIn != nil - if hasUI && !op.AutoApprove && !trivialPlan { - op.UIOut.Output(strings.TrimSpace(approvePlanHeader) + "\n") - op.UIOut.Output(format.Plan(&format.PlanOpts{ - Plan: plan, - Color: b.Colorize(), - ModuleDepth: -1, - })) - desc := "Terraform will apply the plan described above.\n" + - "Only 'yes' will be accepted to approve." + if hasUI && ((op.Destroy && !op.DestroyForce) || + (!op.Destroy && !op.AutoApprove && !trivialPlan)) { + var desc, query string + if op.Destroy { + // Default destroy message + desc = "Terraform will delete all your managed infrastructure.\n" + + "There is no undo. Only 'yes' will be accepted to confirm." + + // If targets are specified, list those to user + if op.Targets != nil { + var descBuffer bytes.Buffer + descBuffer.WriteString("Terraform will delete the following infrastructure:\n") + for _, target := range op.Targets { + descBuffer.WriteString("\t") + descBuffer.WriteString(target) + descBuffer.WriteString("\n") + } + descBuffer.WriteString("There is no undo. Only 'yes' will be accepted to confirm") + desc = descBuffer.String() + } + query = "Do you really want to destroy?" + } else { + desc = "Terraform will apply the plan described above.\n" + + "Only 'yes' will be accepted to approve." + query = "Do you want to apply the plan above?" + } + + if !trivialPlan { + // Display the plan of what we are going to apply/destroy. + op.UIOut.Output(strings.TrimSpace(approvePlanHeader) + "\n") + op.UIOut.Output(format.Plan(&format.PlanOpts{ + Plan: plan, + Color: b.Colorize(), + ModuleDepth: -1, + })) + } + v, err := op.UIIn.Input(&terraform.InputOpts{ Id: "approve", - Query: "Do you want to apply the plan above?", + Query: query, Description: desc, }) if err != nil { @@ -117,7 +145,11 @@ func (b *Local) opApply( return } if v != "yes" { - runningOp.Err = errors.New("Apply cancelled.") + if op.Destroy { + runningOp.Err = errors.New("Destroy cancelled.") + } else { + runningOp.Err = errors.New("Apply cancelled.") + } return } } diff --git a/command/apply.go b/command/apply.go index d4fea85f8004..9cd93ef6fc24 100644 --- a/command/apply.go +++ b/command/apply.go @@ -155,41 +155,6 @@ func (c *ApplyCommand) Run(args []string) int { return 1 } - // If we're not forcing and we're destroying, verify with the - // user at this point. - if !destroyForce && c.Destroy { - // Default destroy message - desc := "Terraform will delete all your managed infrastructure.\n" + - "There is no undo. Only 'yes' will be accepted to confirm." - - // If targets are specified, list those to user - if c.Meta.targets != nil { - var descBuffer bytes.Buffer - descBuffer.WriteString("Terraform will delete the following infrastructure:\n") - for _, target := range c.Meta.targets { - descBuffer.WriteString("\t") - descBuffer.WriteString(target) - descBuffer.WriteString("\n") - } - descBuffer.WriteString("There is no undo. Only 'yes' will be accepted to confirm") - desc = descBuffer.String() - } - - v, err := c.UIInput().Input(&terraform.InputOpts{ - Id: "destroy", - Query: "Do you really want to destroy?", - Description: desc, - }) - if err != nil { - c.Ui.Error(fmt.Sprintf("Error asking for confirmation: %s", err)) - return 1 - } - if v != "yes" { - c.Ui.Output("Destroy cancelled.") - return 1 - } - } - // Build the operation opReq := c.Operation() opReq.Destroy = c.Destroy @@ -198,6 +163,7 @@ func (c *ApplyCommand) Run(args []string) int { opReq.PlanRefresh = refresh opReq.Type = backend.OperationTypeApply opReq.AutoApprove = autoApprove + opReq.DestroyForce = destroyForce // Perform the operation ctx, ctxCancel := context.WithCancel(context.Background())