Merge pull request #36453 from hashicorp/IPL-7602/saved-plan-apply-hangs-with-auto-approve-flag

Fix: Saved plan apply hangs with `-auto-approve` flag using cloud backend
pull/36469/head
Mark DeCrane 1 year ago committed by GitHub
commit 166434811e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
kind: BUG FIXES
body: Fixes hanging behavior seen when applying a saved plan with -auto-approve using the cloud backend
time: 2025-02-06T15:50:25.767607-05:00
custom:
Issue: "36453"

@ -83,8 +83,8 @@ func (b *Cloud) opApply(stopCtx, cancelCtx context.Context, op *backendrun.Opera
var r *tfe.Run
var err error
if cp, ok := op.PlanFile.Cloud(); ok {
cp, hasSavedPlanFile := op.PlanFile.Cloud()
if hasSavedPlanFile {
log.Printf("[TRACE] Loading saved cloud plan for apply")
// Check hostname first, for a more actionable error than a generic 404 later
if cp.Hostname != b.Hostname {
@ -182,7 +182,9 @@ func (b *Cloud) opApply(stopCtx, cancelCtx context.Context, op *backendrun.Opera
}
// Do the apply!
if !op.AutoApprove && err != errRunApproved {
// If we have a saved plan file, we proceed to apply the run without confirmation
// regardless of the value of AutoApprove.
if (!op.AutoApprove || hasSavedPlanFile) && err != errRunApproved {
if err = b.client.Runs.Apply(stopCtx, r.ID, tfe.RunApplyOptions{}); err != nil {
return r, b.generalError("Failed to approve the apply command", err)
}

@ -508,6 +508,73 @@ func TestCloud_applyWithCloudPlan(t *testing.T) {
}
}
func TestCloud_applyAutoApprove_with_CloudPlan(t *testing.T) {
b, bCleanup := testBackendWithName(t)
defer bCleanup()
op, configCleanup, done := testOperationApply(t, "./testdata/apply-json")
defer configCleanup()
defer done(t)
op.AutoApprove = true
op.UIOut = b.CLI
op.Workspace = testBackendSingleWorkspaceName
mockSROWorkspace(t, b, op.Workspace)
ws, err := b.client.Workspaces.Read(context.Background(), b.Organization, b.WorkspaceMapping.Name)
if err != nil {
t.Fatalf("Couldn't read workspace: %s", err)
}
planRun, err := b.plan(context.Background(), context.Background(), op, ws)
if err != nil {
t.Fatalf("Couldn't perform plan: %s", err)
}
// Synthesize a cloud plan file with the plan's run ID
pf := &cloudplan.SavedPlanBookmark{
RemotePlanFormat: 1,
RunID: planRun.ID,
Hostname: b.Hostname,
}
op.PlanFile = planfile.NewWrappedCloud(pf)
// Start spying on the apply output (now that the plan's done)
stream, close := terminal.StreamsForTesting(t)
b.renderer = &jsonformat.Renderer{
Streams: stream,
Colorize: mockColorize(),
}
// Try apply
run, err := b.Operation(context.Background(), op)
if err != nil {
t.Fatalf("error starting operation: %v", err)
}
<-run.Done()
output := close(t)
if run.Result != backendrun.OperationSuccess {
t.Fatal("expected apply operation to succeed")
}
if run.PlanEmpty {
t.Fatalf("expected plan to not be empty")
}
gotOut := output.Stdout()
if !strings.Contains(gotOut, "1 added, 0 changed, 0 destroyed") {
t.Fatalf("expected apply summary in output: %s", gotOut)
}
stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
// An error suggests that the state was not unlocked after apply
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
}
}
func TestCloud_applyWithoutRefresh(t *testing.T) {
b, bCleanup := testBackendWithName(t)
defer bCleanup()

Loading…
Cancel
Save