diff --git a/command/apply.go b/command/apply.go index 18f3f981f..a9588f7e5 100644 --- a/command/apply.go +++ b/command/apply.go @@ -24,9 +24,6 @@ type ApplyCommand struct { // If true, then this apply command will become the "destroy" // command. It is just like apply but only processes a destroy. Destroy bool - - // When this channel is closed, the apply will be cancelled. - ShutdownCh <-chan struct{} } func (c *ApplyCommand) Run(args []string) int { diff --git a/command/apply_test.go b/command/apply_test.go index 808bbbe2a..b30e287d7 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -837,9 +837,8 @@ func TestApply_shutdown(t *testing.T) { Meta: Meta{ testingOverrides: metaOverridesForProvider(p), Ui: ui, + ShutdownCh: shutdownCh, }, - - ShutdownCh: shutdownCh, } p.DiffFn = func( diff --git a/command/console.go b/command/console.go index 823558311..b1361c26f 100644 --- a/command/console.go +++ b/command/console.go @@ -17,9 +17,6 @@ import ( // configuration and actually builds or changes infrastructure. type ConsoleCommand struct { Meta - - // When this channel is closed, the apply will be cancelled. - ShutdownCh <-chan struct{} } func (c *ConsoleCommand) Run(args []string) int { diff --git a/command/meta.go b/command/meta.go index 92ddd8315..27f7765f9 100644 --- a/command/meta.go +++ b/command/meta.go @@ -76,6 +76,9 @@ type Meta struct { // is not suitable, e.g. because of a read-only filesystem. OverrideDataDir string + // When this channel is closed, the command will be cancelled. + ShutdownCh <-chan struct{} + //---------------------------------------------------------- // Protected: commands can set these //---------------------------------------------------------- diff --git a/command/plan.go b/command/plan.go index 757984f8f..ac557bbc8 100644 --- a/command/plan.go +++ b/command/plan.go @@ -104,17 +104,35 @@ func (c *PlanCommand) Run(args []string) int { opReq.Type = backend.OperationTypePlan // Perform the operation - op, err := b.Operation(context.Background(), opReq) + ctx, ctxCancel := context.WithCancel(context.Background()) + defer ctxCancel() + + op, err := b.Operation(ctx, opReq) if err != nil { c.Ui.Error(fmt.Sprintf("Error starting operation: %s", err)) return 1 } - // Wait for the operation to complete - <-op.Done() - if err := op.Err; err != nil { - c.showDiagnostics(err) - return 1 + select { + case <-c.ShutdownCh: + // Cancel our context so we can start gracefully exiting + ctxCancel() + // Notify the user + c.Ui.Output(outputInterrupt) + + // Still get the result, since there is still one + select { + case <-c.ShutdownCh: + c.Ui.Error( + "Two interrupts received. Exiting immediately") + return 1 + case <-op.Done(): + } + case <-op.Done(): + if err := op.Err; err != nil { + c.showDiagnostics(err) + return 1 + } } /*