Skip to content

Commit 8079231

Browse files
authored
Merge pull request #30979 from hashicorp/jbardin/cancel-auto-approve
check for cancellation before apply confirmation
2 parents 28e9401 + df0a70b commit 8079231

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

internal/backend/local/backend_apply.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package local
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"log"
78

@@ -16,6 +17,9 @@ import (
1617
"github.com/hashicorp/terraform/internal/tfdiags"
1718
)
1819

20+
// test hook called between plan+apply during opApply
21+
var testHookStopPlanApply func()
22+
1923
func (b *Local) opApply(
2024
stopCtx context.Context,
2125
cancelCtx context.Context,
@@ -88,6 +92,22 @@ func (b *Local) opApply(
8892
mustConfirm := hasUI && !op.AutoApprove && !trivialPlan
8993
op.View.Plan(plan, schemas)
9094

95+
if testHookStopPlanApply != nil {
96+
testHookStopPlanApply()
97+
}
98+
99+
// Check if we've been stopped before going through confirmation, or
100+
// skipping confirmation in the case of -auto-approve.
101+
// This can currently happen if a single stop request was received
102+
// during the final batch of resource plan calls, so no operations were
103+
// forced to abort, and no errors were returned from Plan.
104+
if stopCtx.Err() != nil {
105+
diags = diags.Append(errors.New("execution halted"))
106+
runningOp.Result = backend.OperationFailure
107+
op.ReportResult(runningOp, diags)
108+
return
109+
}
110+
91111
if mustConfirm {
92112
var desc, query string
93113
switch op.PlanMode {

internal/backend/local/backend_apply_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,36 @@ func applyFixtureSchema() *terraform.ProviderSchema {
351351
},
352352
}
353353
}
354+
355+
func TestApply_applyCanceledAutoApprove(t *testing.T) {
356+
b := TestLocal(t)
357+
358+
TestLocalProvider(t, b, "test", applyFixtureSchema())
359+
360+
op, configCleanup, done := testOperationApply(t, "./testdata/apply")
361+
op.AutoApprove = true
362+
defer configCleanup()
363+
defer func() {
364+
output := done(t)
365+
if !strings.Contains(output.Stderr(), "execution halted") {
366+
t.Fatal("expected 'execution halted', got:\n", output.All())
367+
}
368+
}()
369+
370+
ctx, cancel := context.WithCancel(context.Background())
371+
testHookStopPlanApply = cancel
372+
defer func() {
373+
testHookStopPlanApply = nil
374+
}()
375+
376+
run, err := b.Operation(ctx, op)
377+
if err != nil {
378+
t.Fatalf("error starting operation: %v", err)
379+
}
380+
381+
<-run.Done()
382+
if run.Result == backend.OperationSuccess {
383+
t.Fatal("expected apply operation to fail")
384+
}
385+
386+
}

0 commit comments

Comments
 (0)