Skip to content

Commit

Permalink
fix(aws-cdk): Auto-delete stacks that failed creating before new atte…
Browse files Browse the repository at this point in the history
…mpt (#917)

Restore the previous behavior around stacks that failed creation,
detecting the condition and automatically deleting the stack before
making a new attempt.

The stack is not deleted after the failure in order to allow for
forensics to be performed. Also, deleting the stack on the next creation
attempt is more robust.
  • Loading branch information
RomainMuller authored Oct 12, 2018
1 parent f2b1048 commit 2af8309
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
11 changes: 10 additions & 1 deletion packages/aws-cdk/lib/api/deploy-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { prepareAssets } from '../assets';
import { debug, error } from '../logging';
import { Mode } from './aws-auth/credentials';
import { ToolkitInfo } from './toolkit-info';
import { describeStack, stackExists, waitForChangeSet, waitForStack } from './util/cloudformation';
import { describeStack, stackExists, stackFailedCreating, waitForChangeSet, waitForStack } from './util/cloudformation';
import { StackActivityMonitor } from './util/cloudformation/stack-activity-monitor';
import { StackStatus } from './util/cloudformation/stack-status';
import { SDK } from './util/sdk';
Expand Down Expand Up @@ -43,6 +43,15 @@ export async function deployStack(stack: cxapi.SynthesizedStack,
const cfn = await sdk.cloudFormation(stack.environment, Mode.ForWriting);
const bodyParameter = await makeBodyParameter(stack, toolkitInfo);

if (await stackFailedCreating(cfn, deployName)) {
debug(`Found existing stack ${deployName} that had previously failed creation. Deleting it before attempting to re-create it.`);
await cfn.deleteStack({ StackName: deployName }).promise();
const deletedStack = await waitForStack(cfn, deployName, false);
if (deletedStack && deletedStack.StackStatus !== 'DELETE_COMPLETE') {
throw new Error(`Failed deleting stack ${deployName} that had previously failed creation (current state: ${deletedStack.StackStatus})`);
}
}

const update = await stackExists(cfn, deployName);

const changeSetName = `CDK-${executionId}`;
Expand Down
14 changes: 14 additions & 0 deletions packages/aws-cdk/lib/api/util/cloudformation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ export async function stackExists(cfn: CloudFormation, stackName: string): Promi
return description !== undefined;
}

/**
* Checks whether a stack has failed creation in CloudFormation. This is identified by the current stack Status being
* ``ROLLBACK_COMPLETE``.
*
* @param cfn a CloudFormation client
* @param stackName the name of the stack to be checked for
*
* @returns +true+ if the stack exists and is in failed-creation state.
*/
export async function stackFailedCreating(cfn: CloudFormation, stackName: string): Promise<boolean> {
const description = await describeStack(cfn, stackName);
return description != null && description.StackStatus === 'ROLLBACK_COMPLETE';
}

/**
* Waits for a function to return non-+undefined+ before returning.
*
Expand Down

0 comments on commit 2af8309

Please sign in to comment.