From 477fa851b35954b62917e8319a13d01b446ddeae Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Wed, 7 Dec 2022 16:01:38 +0100 Subject: [PATCH] fix(toolkit): endless wait if CDKToolkit stack is `REVIEW_IN_PROGRESS` (#23230) If a `cdk bootstrap` operation is interrupted after the ChangeSet has been created, but before it is executed, the CDKToolkit stack will be left in the `REVIEW_IN_PROGRESS` state, which is a stable state until something or someone either executes or deletes the pending ChangeSet. This resulted in an endless (and silent, unless `cdk bootstrap` is executed in verbose mode) wait, as this was considered an "in progress" (aka unstable) state. This changes `REVIEW_IN_PROGRESS` to be treated as stable, while still debug-logging an indication that we are "ignoring" the existing ChangeSet. --- packages/aws-cdk/lib/api/util/cloudformation.ts | 8 ++++++++ .../aws-cdk/lib/api/util/cloudformation/stack-status.ts | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk/lib/api/util/cloudformation.ts b/packages/aws-cdk/lib/api/util/cloudformation.ts index e4fa597e506b4..66f7752371f7c 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation.ts @@ -371,6 +371,14 @@ export async function stabilizeStack(cfn: CloudFormation, stackName: string) { if (status.isInProgress) { debug('Stack %s has an ongoing operation in progress and is not stable (%s)', stackName, status); return undefined; + } else if (status.isReviewInProgress) { + // This may happen if a stack creation operation is interrupted before the ChangeSet execution starts. Recovering + // from this would requiring manual intervention (deleting or executing the pending ChangeSet), and failing to do + // so will result in an endless wait here (the ChangeSet wont delete or execute itself). Instead of blocking + // "forever" we proceed as if the stack was existing and stable. If there is a concurrent operation that just + // hasn't finished proceeding just yet, either this operation or the concurrent one may fail due to the other one + // having made progress. Which is fine. I guess. + debug('Stack %s is in REVIEW_IN_PROGRESS state. Considering this is a stable status (%s)', stackName, status); } return stack; diff --git a/packages/aws-cdk/lib/api/util/cloudformation/stack-status.ts b/packages/aws-cdk/lib/api/util/cloudformation/stack-status.ts index 76069868cf99b..8e2ae674a9074 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation/stack-status.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation/stack-status.ts @@ -26,7 +26,11 @@ export class StackStatus { } get isInProgress(): boolean { - return this.name.endsWith('_IN_PROGRESS'); + return this.name.endsWith('_IN_PROGRESS') && !this.isReviewInProgress; + } + + get isReviewInProgress(): boolean { + return this.name === 'REVIEW_IN_PROGRESS'; } get isNotFound(): boolean {