Skip to content

Commit

Permalink
fix: undo refactor changes in merge from dev
Browse files Browse the repository at this point in the history
  • Loading branch information
rjabhi committed Feb 7, 2025
1 parent 13d3842 commit 9907c5c
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 56 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import {
CloudFormationClient,
CreateStackRefactorCommand,
CreateStackRefactorCommandInput,
DescribeStackRefactorCommand,
DescribeStackRefactorCommandOutput,
ExecuteStackRefactorCommand,
StackRefactorExecutionStatus,
StackRefactorStatus,
} from '@aws-sdk/client-cloudformation';
import assert from 'node:assert';
import { FailedRefactorResponse } from './types';

const POLL_ATTEMPTS = 30;
const POLL_INTERVAL_MS = 1500;
const COMPLETION_STATE = '_COMPLETE';
const FAILED_STATE = '_FAILED';
export const UPDATE_COMPLETE = 'UPDATE_COMPLETE';
/**
* Refactors a stack with given source and destination template.
* @param cfnClient
* @param createStackRefactorCommandInput
* @param attempts number of attempts to poll CFN stack for update completion state. The interval between the polls is 1.5 seconds.
* @returns a tuple containing the success/failed state and the reason if any.
*/
export async function tryRefactorStack(
cfnClient: CloudFormationClient,
createStackRefactorCommandInput: CreateStackRefactorCommandInput,
attempts = POLL_ATTEMPTS,
): Promise<[boolean, FailedRefactorResponse | undefined]> {
const { StackRefactorId } = await cfnClient.send(new CreateStackRefactorCommand(createStackRefactorCommandInput));
assert(StackRefactorId);
let describeStackRefactorResponse = await pollStackRefactorForCompletionState(
cfnClient,
StackRefactorId,
(_describeStackRefactorResponse: DescribeStackRefactorCommandOutput) => {
assert(_describeStackRefactorResponse.Status);
return (
_describeStackRefactorResponse.Status.endsWith(COMPLETION_STATE) || _describeStackRefactorResponse.Status.endsWith(FAILED_STATE)
);
},
attempts,
);
if (describeStackRefactorResponse.Status !== StackRefactorStatus.CREATE_COMPLETE) {
return [false, {
status: describeStackRefactorResponse.Status,
reason: describeStackRefactorResponse.StatusReason,
stackRefactorId: StackRefactorId,
}];
}
// assert(describeStackRefactorResponse.Status === StackRefactorStatus.CREATE_COMPLETE);
await cfnClient.send(
new ExecuteStackRefactorCommand({
StackRefactorId,
}),
);
describeStackRefactorResponse = await pollStackRefactorForCompletionState(
cfnClient,
StackRefactorId,
(describeStackRefactorResponse: DescribeStackRefactorCommandOutput) => {
assert(describeStackRefactorResponse.ExecutionStatus);
return (
describeStackRefactorResponse.ExecutionStatus.endsWith(COMPLETION_STATE) ||
describeStackRefactorResponse.ExecutionStatus.endsWith(FAILED_STATE)
);
},
attempts,
);
if (describeStackRefactorResponse.ExecutionStatus !== StackRefactorExecutionStatus.EXECUTE_COMPLETE) {
return [false, {
status: describeStackRefactorResponse.ExecutionStatus,
stackRefactorId: StackRefactorId,
reason: describeStackRefactorResponse.ExecutionStatusReason,
}];
}
return [true, undefined];

// assert(describeStackRefactorResponse.ExecutionStatus === StackRefactorExecutionStatus.EXECUTE_COMPLETE);
}

/**
* Polls a stack refactor operation for completion state
* @param cfnClient
* @param stackRefactorId
* @param exitCondition a function that determines if the stack refactor operation has reached a completion state.
* @param attempts number of attempts to poll for completion.
* @returns the stack status
*/
async function pollStackRefactorForCompletionState(
cfnClient: CloudFormationClient,
stackRefactorId: string,
exitCondition: (describeStackRefactorResponse: DescribeStackRefactorCommandOutput) => boolean,
attempts: number,
): Promise<DescribeStackRefactorCommandOutput> {
do {
const describeStackRefactorResponse = await cfnClient.send(
new DescribeStackRefactorCommand({
StackRefactorId: stackRefactorId,
}),
);
if (exitCondition(describeStackRefactorResponse)) {
return describeStackRefactorResponse;
}
await new Promise((res) => setTimeout(() => res(''), POLL_INTERVAL_MS));
attempts--;
} while (attempts > 0);
throw new Error(`Stack refactor ${stackRefactorId} did not reach a completion state within the given time period.`);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export async function tryUpdateStack(
* @param attempts number of attempts to poll for completion.
* @returns the stack status
*/
export async function pollStackForCompletionState(cfnClient: CloudFormationClient, stackName: string, attempts: number): Promise<string> {
async function pollStackForCompletionState(cfnClient: CloudFormationClient, stackName: string, attempts: number): Promise<string> {
do {
const { Stacks } = await cfnClient.send(
new DescribeStacksCommand({
Expand Down
58 changes: 10 additions & 48 deletions packages/amplify-migration-template-gen/src/template-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import CategoryTemplateGenerator from './category-template-generator';
import fs from 'node:fs/promises';
import { CATEGORY, CFN_AUTH_TYPE, CFN_CATEGORY_TYPE, CFN_S3_TYPE, CFNResource, CFNStackStatus } from './types';
import MigrationReadmeGenerator from './migration-readme-generator';
import { pollStackForCompletionState, tryUpdateStack } from './cfn-stack-updater';
import { tryUpdateStack } from './cfn-stack-updater';
import { SSMClient } from '@aws-sdk/client-ssm';
import { CognitoIdentityProviderClient } from '@aws-sdk/client-cognito-identity-provider';
import { tryRefactorStack } from './cfn-stack-refactor-updater';

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused import tryRefactorStack.
Expand Down Expand Up @@ -63,13 +63,13 @@ class TemplateGenerator {
if (!category) continue;
assert(Gen1PhysicalResourceId);
if (category === 'auth') {
const { StackResources: AuthStackResources } = await this.cfnClient.send(
const { StackResources: AuthStackResources } = await this.cfnClient.send(
new DescribeStackResourcesCommand({
StackName: Gen1PhysicalResourceId,
}),
);
assert(AuthStackResources);
if (AuthStackResources.some(authResource => authResource.ResourceType === CFN_AUTH_TYPE.UserPoolGroups)) {
if (AuthStackResources.some((authResource) => authResource.ResourceType === CFN_AUTH_TYPE.UserPoolGroups)) {
console.log('Skipping moving of user pool groups.');
continue;
}
Expand Down Expand Up @@ -118,7 +118,7 @@ class TemplateGenerator {
CFN_AUTH_TYPE.IdentityPool,
CFN_AUTH_TYPE.IdentityPoolRoleAttachment,
CFN_AUTH_TYPE.UserPoolDomain,
CFN_AUTH_TYPE.UserPoolGroups
CFN_AUTH_TYPE.UserPoolGroups,
],
resourcesToMovePredicate,
),
Expand Down Expand Up @@ -167,8 +167,11 @@ class TemplateGenerator {
assert(gen1StackUpdateStatus === CFNStackStatus.UPDATE_COMPLETE);
console.log(`Updated Gen1 ${category} stack successfully`);

const { newTemplate: newGen2Template, oldTemplate: oldGen2Template, parameters: gen2StackParameters } =
await categoryTemplateGenerator.generateGen2ResourceRemovalTemplate();
const {
newTemplate: newGen2Template,
oldTemplate: oldGen2Template,

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable oldGen2Template.
parameters: gen2StackParameters,
} = await categoryTemplateGenerator.generateGen2ResourceRemovalTemplate();
console.log(`Updating Gen2 ${category} stack...`);
const gen2StackUpdateStatus = await tryUpdateStack(this.cfnClient, gen2CategoryStackId, gen2StackParameters ?? [], newGen2Template);
assert(gen2StackUpdateStatus === CFNStackStatus.UPDATE_COMPLETE);
Expand All @@ -178,49 +181,8 @@ class TemplateGenerator {
newGen1Template,
newGen2Template,
);
let resourceMappings = [];
for (const [gen1LogicalId, gen2LogicalId] of logicalIdMapping) {
resourceMappings.push({
Source: {
StackName: gen1CategoryStackId,
LogicalResourceId: gen1LogicalId,
},
Destination: {
StackName: gen2CategoryStackId,
LogicalResourceId: gen2LogicalId,
},
});
}
console.log(`Moving ${category} resources from Gen1 to Gen2 stack...`);
const [success, failedRefactorMetadata] = await tryRefactorStack(this.cfnClient, {
StackDefinitions: [
{
TemplateBody: JSON.stringify(sourceTemplate),
StackName: gen1CategoryStackId,
},
{
TemplateBody: JSON.stringify(destinationTemplate),
StackName: gen2CategoryStackId,
},
],
ResourceMappings: resourceMappings,
});
if (!success) {
console.log(
`Moving ${category} resources from Gen1 to Gen2 stack failed. Reason: ${failedRefactorMetadata?.reason}. Status: ${failedRefactorMetadata?.status}. RefactorId: ${failedRefactorMetadata?.stackRefactorId}.`,
);
await pollStackForCompletionState(this.cfnClient, gen2CategoryStackId, 30);
console.log(`Rolling back Gen2 ${category} stack...`);
const gen2StackUpdateStatus = await tryUpdateStack(this.cfnClient, gen2CategoryStackId, gen2StackParameters ?? [], oldGen2Template);
assert(gen2StackUpdateStatus === CFNStackStatus.UPDATE_COMPLETE);
console.log(`Rolled back Gen2 ${category} stack successfully`);
return false;
} else {
console.log(`Moved ${category} resources from Gen1 to Gen2 stack successfully`);
}
// await migrationReadMeGenerator.renderStep1(sourceTemplate, destinationTemplate, logicalIdMapping, newGen1Template, newGen2Template);
await migrationReadMeGenerator.renderStep1(sourceTemplate, destinationTemplate, logicalIdMapping, newGen1Template, newGen2Template);
await migrationReadMeGenerator.renderStep2();
return true;
}
}
}
Expand Down
8 changes: 1 addition & 7 deletions packages/amplify-migration-template-gen/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export enum CFN_AUTH_TYPE {
IdentityPool = 'AWS::Cognito::IdentityPool',
IdentityPoolRoleAttachment = 'AWS::Cognito::IdentityPoolRoleAttachment',
UserPoolDomain = 'AWS::Cognito::UserPoolDomain',
UserPoolGroups = 'AWS::Cognito::UserPoolGroup'
UserPoolGroups = 'AWS::Cognito::UserPoolGroup',
}

export enum CFN_S3_TYPE {
Expand Down Expand Up @@ -111,9 +111,3 @@ export type OAuthClient = OAuthClientWithSecret | SignInWithAppleOAuthClient;
export type HostedUIProviderMeta = {
ProviderName: 'Amazon' | 'Facebook' | 'Google' | 'SignInWithApple';
};

export type FailedRefactorResponse = {
reason: string | undefined;
stackRefactorId: string;
status: StackRefactorStatus | StackRefactorExecutionStatus | undefined;
}

0 comments on commit 9907c5c

Please sign in to comment.