From f13cad8a27b468cc108eb4f331388bb4b24cbdc2 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Tue, 18 Feb 2025 15:54:30 -0800 Subject: [PATCH 01/17] fix: avoid invalid token error Signed-off-by: Kevin Shan --- .../src/cleanup-e2e-resources.ts | 98 +++++++++++-------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index 54b9be31a..208f16da2 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -8,29 +8,24 @@ import fs from 'fs-extra'; import path from 'path'; import { deleteS3Bucket, sleep } from '@aws-amplify/amplify-codegen-e2e-core'; -// Ensure to update scripts/split-e2e-tests.ts is also updated this gets updated -const AWS_REGIONS_TO_RUN_TESTS = [ - 'ap-east-1', - 'ap-northeast-1', - 'ap-northeast-2', - 'ap-northeast-3', - 'ap-south-1', - 'ap-southeast-1', - 'ap-southeast-2', - 'ca-central-1', - 'eu-central-1', - 'eu-north-1', - 'eu-south-1', - 'eu-west-1', - 'eu-west-2', - 'eu-west-3', - 'me-south-1', - 'sa-east-1', - 'us-east-1', - 'us-east-2', - 'us-west-1', - 'us-west-2', -]; +/** + * Supported regions: + * - All Amplify regions, as reported https://docs.aws.amazon.com/general/latest/gr/amplify.html + * + * NOTE: The list of supported regions must be kept in sync amongst all of: + * - the internal pipeline that publishes new lambda layer versions + * - amplify-codegen/scripts/split-canary-tests.ts + * - amplify-codegen/scripts/split-e2e-tests.ts + */ +const REPO_ROOT = path.join(__dirname, '..', '..', '..'); +const SUPPORTED_REGIONS_PATH = path.join(REPO_ROOT, 'scripts', 'e2e-test-regions.json'); +const AWS_REGIONS_TO_RUN_TESTS_METADATA: TestRegion[] = JSON.parse(fs.readFileSync(SUPPORTED_REGIONS_PATH, 'utf-8')); +const AWS_REGIONS_TO_RUN_TESTS = AWS_REGIONS_TO_RUN_TESTS_METADATA.map(region => region.name); + +type TestRegion = { + name: string; + optIn: boolean; +}; const reportPathDir = path.normalize(path.join(__dirname, '..', 'amplify-e2e-reports')); @@ -175,8 +170,20 @@ const getOrphanTestIamRoles = async (account: AWSAccountInfo): Promise => { const amplifyClient = new aws.Amplify(getAWSConfig(account, region)); - const amplifyApps = await amplifyClient.listApps({ maxResults: 50 }).promise(); // keeping it to 50 as max supported is 50 const result: AmplifyAppInfo[] = []; + let amplifyApps = { apps: [] }; + try { + amplifyApps = await amplifyClient.listApps({ maxResults: 50 }).promise(); // keeping it to 50 as max supported is 50 + } catch (e) { + if (e?.code === 'UnrecognizedClientException') { + // Do not fail the cleanup and continue + console.log(`Listing apps for account ${account.accountId}-${region} failed with error with code ${e?.code}. Skipping.`); + return result; + } else { + throw e; + } + } + for (const app of amplifyApps.apps) { const backends: Record = {}; try { @@ -246,25 +253,36 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio const getStacks = async (account: AWSAccountInfo, region: string): Promise => { const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); - const stacks = await cfnClient - .listStacks({ - StackStatusFilter: [ - 'CREATE_COMPLETE', - 'ROLLBACK_FAILED', - 'DELETE_FAILED', - 'UPDATE_COMPLETE', - 'UPDATE_ROLLBACK_FAILED', - 'UPDATE_ROLLBACK_COMPLETE', - 'IMPORT_COMPLETE', - 'IMPORT_ROLLBACK_FAILED', - 'IMPORT_ROLLBACK_COMPLETE', - ], - }) - .promise(); + const results: StackInfo[] = []; + let stacks; + try { + stacks = await cfnClient + .listStacks({ + StackStatusFilter: [ + 'CREATE_COMPLETE', + 'ROLLBACK_FAILED', + 'DELETE_FAILED', + 'UPDATE_COMPLETE', + 'UPDATE_ROLLBACK_FAILED', + 'UPDATE_ROLLBACK_COMPLETE', + 'IMPORT_COMPLETE', + 'IMPORT_ROLLBACK_FAILED', + 'IMPORT_ROLLBACK_COMPLETE', + ], + }) + .promise(); + } catch (e) { + if (e?.code === 'InvalidClientTokenId') { + // Do not fail the cleanup and continue + console.log(`Listing stacks for account ${account.accountId}-${region} failed with error with code ${e?.code}. Skipping.`); + return results; + } else { + throw e; + } + } // We are interested in only the root stacks that are deployed by amplify-cli const rootStacks = stacks.StackSummaries.filter(stack => !stack.RootId); - const results: StackInfo[] = []; for (const stack of rootStacks) { try { const details = await getStackDetails(stack.StackName, account, region); From 914a65b69387f408054f5a1688feadfc3f601a4b Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Tue, 18 Feb 2025 16:22:33 -0800 Subject: [PATCH 02/17] chore: try use sdk to get opt status Signed-off-by: Kevin Shan --- .../src/cleanup-e2e-resources.ts | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index 208f16da2..ecc967312 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -1,5 +1,5 @@ /* eslint-disable spellcheck/spell-checker, camelcase, @typescript-eslint/no-explicit-any */ -import { CodeBuild } from 'aws-sdk'; +import { CodeBuild, Account } from 'aws-sdk'; import { config } from 'dotenv'; import yargs from 'yargs'; import * as aws from 'aws-sdk'; @@ -251,38 +251,45 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio }; }; -const getStacks = async (account: AWSAccountInfo, region: string): Promise => { - const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); - const results: StackInfo[] = []; - let stacks; +const isRegionEnabled = async (config: unknown, region: string): Promise => { try { - stacks = await cfnClient - .listStacks({ - StackStatusFilter: [ - 'CREATE_COMPLETE', - 'ROLLBACK_FAILED', - 'DELETE_FAILED', - 'UPDATE_COMPLETE', - 'UPDATE_ROLLBACK_FAILED', - 'UPDATE_ROLLBACK_COMPLETE', - 'IMPORT_COMPLETE', - 'IMPORT_ROLLBACK_FAILED', - 'IMPORT_ROLLBACK_COMPLETE', - ], - }) - .promise(); + const account = new Account(config); + const response = await account.getRegionOptStatus({ RegionName: region }).promise(); + + return response.RegionOptStatus === 'ENABLED' || response.RegionOptStatus === 'ENABLED_BY_DEFAULT'; } catch (e) { - if (e?.code === 'InvalidClientTokenId') { - // Do not fail the cleanup and continue - console.log(`Listing stacks for account ${account.accountId}-${region} failed with error with code ${e?.code}. Skipping.`); - return results; - } else { - throw e; - } + console.error(`Error checking region status: ${e}`); + throw e; + } +}; + +const getStacks = async (account: AWSAccountInfo, region: string): Promise => { + const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); + + const regionEnabled = await isRegionEnabled(getAWSConfig(account), region); + if (!regionEnabled) { + return []; } + const stacks = await cfnClient + .listStacks({ + StackStatusFilter: [ + 'CREATE_COMPLETE', + 'ROLLBACK_FAILED', + 'DELETE_FAILED', + 'UPDATE_COMPLETE', + 'UPDATE_ROLLBACK_FAILED', + 'UPDATE_ROLLBACK_COMPLETE', + 'IMPORT_COMPLETE', + 'IMPORT_ROLLBACK_FAILED', + 'IMPORT_ROLLBACK_COMPLETE', + ], + }) + .promise(); + // We are interested in only the root stacks that are deployed by amplify-cli const rootStacks = stacks.StackSummaries.filter(stack => !stack.RootId); + const results: StackInfo[] = []; for (const stack of rootStacks) { try { const details = await getStackDetails(stack.StackName, account, region); From 4e05757b86fa59004cd4483355aa580699b1588c Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Tue, 18 Feb 2025 17:21:24 -0800 Subject: [PATCH 03/17] chore: revert changes Signed-off-by: Kevin Shan --- .../src/cleanup-e2e-resources.ts | 61 ++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index ecc967312..208f16da2 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -1,5 +1,5 @@ /* eslint-disable spellcheck/spell-checker, camelcase, @typescript-eslint/no-explicit-any */ -import { CodeBuild, Account } from 'aws-sdk'; +import { CodeBuild } from 'aws-sdk'; import { config } from 'dotenv'; import yargs from 'yargs'; import * as aws from 'aws-sdk'; @@ -251,45 +251,38 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio }; }; -const isRegionEnabled = async (config: unknown, region: string): Promise => { - try { - const account = new Account(config); - const response = await account.getRegionOptStatus({ RegionName: region }).promise(); - - return response.RegionOptStatus === 'ENABLED' || response.RegionOptStatus === 'ENABLED_BY_DEFAULT'; - } catch (e) { - console.error(`Error checking region status: ${e}`); - throw e; - } -}; - const getStacks = async (account: AWSAccountInfo, region: string): Promise => { const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); - - const regionEnabled = await isRegionEnabled(getAWSConfig(account), region); - if (!regionEnabled) { - return []; + const results: StackInfo[] = []; + let stacks; + try { + stacks = await cfnClient + .listStacks({ + StackStatusFilter: [ + 'CREATE_COMPLETE', + 'ROLLBACK_FAILED', + 'DELETE_FAILED', + 'UPDATE_COMPLETE', + 'UPDATE_ROLLBACK_FAILED', + 'UPDATE_ROLLBACK_COMPLETE', + 'IMPORT_COMPLETE', + 'IMPORT_ROLLBACK_FAILED', + 'IMPORT_ROLLBACK_COMPLETE', + ], + }) + .promise(); + } catch (e) { + if (e?.code === 'InvalidClientTokenId') { + // Do not fail the cleanup and continue + console.log(`Listing stacks for account ${account.accountId}-${region} failed with error with code ${e?.code}. Skipping.`); + return results; + } else { + throw e; + } } - const stacks = await cfnClient - .listStacks({ - StackStatusFilter: [ - 'CREATE_COMPLETE', - 'ROLLBACK_FAILED', - 'DELETE_FAILED', - 'UPDATE_COMPLETE', - 'UPDATE_ROLLBACK_FAILED', - 'UPDATE_ROLLBACK_COMPLETE', - 'IMPORT_COMPLETE', - 'IMPORT_ROLLBACK_FAILED', - 'IMPORT_ROLLBACK_COMPLETE', - ], - }) - .promise(); - // We are interested in only the root stacks that are deployed by amplify-cli const rootStacks = stacks.StackSummaries.filter(stack => !stack.RootId); - const results: StackInfo[] = []; for (const stack of rootStacks) { try { const details = await getStackDetails(stack.StackName, account, region); From 03bf1249f4e8c94afd579b8273655076dc03833b Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Tue, 18 Feb 2025 17:32:35 -0800 Subject: [PATCH 04/17] chore: regex fix Signed-off-by: Kevin Shan --- packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index 208f16da2..bed72a0ba 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -92,7 +92,7 @@ type AWSAccountInfo = { }; const BUCKET_TEST_REGEX = /test/; -const IAM_TEST_REGEX = /!RotateE2eAwsToken-e2eTestContextRole|-integtest$|^amplify-|^eu-|^us-|^ap-/; +const IAM_TEST_REGEX = /!RotateE2eAwsToken-e2eTestContextRole|-integtest|^amplify-|^eu-|^us-|^ap-/; const STALE_DURATION_MS = 2 * 60 * 60 * 1000; // 2 hours in milliseconds const isCI = (): boolean => process.env.CI && process.env.CODEBUILD ? true : false; From bceb7718b38fcdb9b38e8688b16b4d1854f56ba3 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Wed, 19 Feb 2025 10:21:42 -0800 Subject: [PATCH 05/17] chore: test run Signed-off-by: Kevin Shan --- shared-scripts.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-scripts.sh b/shared-scripts.sh index 63bef63c6..07c7b3838 100644 --- a/shared-scripts.sh +++ b/shared-scripts.sh @@ -290,6 +290,7 @@ function _setupGen2E2ETestsWindows { function _runE2ETestsLinux { + printenv echo "RUN E2E Tests Linux" retry runE2eTest } From f1eba48026be542f89726f1196f03304d1fb1809 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Wed, 19 Feb 2025 10:57:50 -0800 Subject: [PATCH 06/17] fix: set actual regionalized tests Signed-off-by: Kevin Shan --- shared-scripts.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared-scripts.sh b/shared-scripts.sh index 07c7b3838..b7b0bea3c 100644 --- a/shared-scripts.sh +++ b/shared-scripts.sh @@ -380,6 +380,9 @@ function useChildAccountCredentials { echo "Using parent account credentials." fi echo "Region is set to use $CLI_REGION" + + export AWS_REGION=$CLI_REGION + export AWS_DEFAULT_REGION=$CLI_REGION } function retry { From f71f9553f8f3a265e7237e1f8eac932ee3095fbd Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Wed, 19 Feb 2025 12:34:23 -0800 Subject: [PATCH 07/17] chore: test run Signed-off-by: Kevin Shan --- .../amplify-codegen-e2e-core/src/init/initProjectHelper.ts | 2 +- shared-scripts.sh | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts b/packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts index ea742694d..1dd53b3bd 100644 --- a/packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts +++ b/packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts @@ -75,7 +75,7 @@ export function initJSProjectWithProfile(cwd: string, settings: Object = {}): Pr .wait('Select the authentication method you want to use:') .sendCarriageReturn() .wait('Please choose the profile you want to use') - .sendLine(s.profileName); + .sendLine('amplify-integ-test-user'); } chain diff --git a/shared-scripts.sh b/shared-scripts.sh index b7b0bea3c..86f6d2dec 100644 --- a/shared-scripts.sh +++ b/shared-scripts.sh @@ -365,6 +365,10 @@ function useChildAccountCredentials { echo "Unable to find a child account. Fatal error and test run aborted" exit 1 fi + + export AWS_REGION=$CLI_REGION + export AWS_DEFAULT_REGION=$CLI_REGION + creds=$(aws sts assume-role --role-arn arn:aws:iam::${pick_acct}:role/OrganizationAccountAccessRole --role-session-name testSession${session_id} --duration-seconds 3600) if [ -z $(echo $creds | jq -c -r '.AssumedRoleUser.Arn') ]; then echo "Unable to assume child account role. Fatal error and test run aborted" @@ -380,9 +384,6 @@ function useChildAccountCredentials { echo "Using parent account credentials." fi echo "Region is set to use $CLI_REGION" - - export AWS_REGION=$CLI_REGION - export AWS_DEFAULT_REGION=$CLI_REGION } function retry { From 6d535cf279d3782be65724857f08b4d3332a825b Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Wed, 19 Feb 2025 12:59:11 -0800 Subject: [PATCH 08/17] Chore: test run Signed-off-by: Kevin Shan --- packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts | 2 +- packages/amplify-codegen-e2e-tests/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts b/packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts index 1dd53b3bd..ea742694d 100644 --- a/packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts +++ b/packages/amplify-codegen-e2e-core/src/init/initProjectHelper.ts @@ -75,7 +75,7 @@ export function initJSProjectWithProfile(cwd: string, settings: Object = {}): Pr .wait('Select the authentication method you want to use:') .sendCarriageReturn() .wait('Please choose the profile you want to use') - .sendLine('amplify-integ-test-user'); + .sendLine(s.profileName); } chain diff --git a/packages/amplify-codegen-e2e-tests/package.json b/packages/amplify-codegen-e2e-tests/package.json index 7fb3a9f6b..ac2ad8360 100644 --- a/packages/amplify-codegen-e2e-tests/package.json +++ b/packages/amplify-codegen-e2e-tests/package.json @@ -19,7 +19,7 @@ "scripts": { "e2e": "npm run setup-profile && jest --verbose --forceExit", "e2e-gen2": "jest --verbose --forceExit", - "setup-profile": "ts-node ./src/configure_tests.ts", + "setup-profile": "ts-node ./src/configure_tests.ts && cat ~/.aws/config && cat ~/.aws/credentials", "clean-e2e-resources": "ts-node ./src/cleanup-e2e-resources.ts" }, "dependencies": { From 7f677214b85c8b529e8ee0937d193aad64ba6466 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Wed, 19 Feb 2025 13:51:19 -0800 Subject: [PATCH 09/17] chore: test run Signed-off-by: Kevin Shan --- packages/amplify-codegen-e2e-core/src/configure/index.ts | 8 ++++++++ shared-scripts.sh | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/amplify-codegen-e2e-core/src/configure/index.ts b/packages/amplify-codegen-e2e-core/src/configure/index.ts index 347af7b96..a254bba09 100644 --- a/packages/amplify-codegen-e2e-core/src/configure/index.ts +++ b/packages/amplify-codegen-e2e-core/src/configure/index.ts @@ -25,6 +25,13 @@ const defaultProjectSettings = { startCmd: '\r', }; +/** + * This is a list with regions same as Amplify CLI 'configure' dropdown. + * We need to keep order of regions in this list and sync with Amplify CLI regions to prevent + * configuration from failing. + * + * For CI: $CLI_REGION will be selected from this list. + */ export const amplifyRegions = [ 'us-east-1', 'us-east-2', @@ -38,6 +45,7 @@ export const amplifyRegions = [ 'eu-central-1', 'ap-northeast-1', 'ap-northeast-2', + 'ap-northeast-3', 'ap-southeast-1', 'ap-southeast-2', 'ap-south-1', diff --git a/shared-scripts.sh b/shared-scripts.sh index 86f6d2dec..b0fa49981 100644 --- a/shared-scripts.sh +++ b/shared-scripts.sh @@ -290,7 +290,6 @@ function _setupGen2E2ETestsWindows { function _runE2ETestsLinux { - printenv echo "RUN E2E Tests Linux" retry runE2eTest } From 5e4f7a080746e1beddc7e7516884e6b7519d5d30 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Wed, 19 Feb 2025 14:03:16 -0800 Subject: [PATCH 10/17] chore: test run Signed-off-by: Kevin Shan --- shared-scripts.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/shared-scripts.sh b/shared-scripts.sh index b0fa49981..63bef63c6 100644 --- a/shared-scripts.sh +++ b/shared-scripts.sh @@ -364,10 +364,6 @@ function useChildAccountCredentials { echo "Unable to find a child account. Fatal error and test run aborted" exit 1 fi - - export AWS_REGION=$CLI_REGION - export AWS_DEFAULT_REGION=$CLI_REGION - creds=$(aws sts assume-role --role-arn arn:aws:iam::${pick_acct}:role/OrganizationAccountAccessRole --role-session-name testSession${session_id} --duration-seconds 3600) if [ -z $(echo $creds | jq -c -r '.AssumedRoleUser.Arn') ]; then echo "Unable to assume child account role. Fatal error and test run aborted" From 3b2cd8e6577684e33c3c0b795e7a44867b78570f Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Wed, 19 Feb 2025 23:21:31 -0800 Subject: [PATCH 11/17] chore: add region detection function Signed-off-by: Kevin Shan --- .../amplify-codegen-e2e-tests/package.json | 2 +- .../src/cleanup-e2e-resources.ts | 51 ++++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/packages/amplify-codegen-e2e-tests/package.json b/packages/amplify-codegen-e2e-tests/package.json index ac2ad8360..7fb3a9f6b 100644 --- a/packages/amplify-codegen-e2e-tests/package.json +++ b/packages/amplify-codegen-e2e-tests/package.json @@ -19,7 +19,7 @@ "scripts": { "e2e": "npm run setup-profile && jest --verbose --forceExit", "e2e-gen2": "jest --verbose --forceExit", - "setup-profile": "ts-node ./src/configure_tests.ts && cat ~/.aws/config && cat ~/.aws/credentials", + "setup-profile": "ts-node ./src/configure_tests.ts", "clean-e2e-resources": "ts-node ./src/cleanup-e2e-resources.ts" }, "dependencies": { diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index bed72a0ba..ac85c5919 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -1,5 +1,5 @@ /* eslint-disable spellcheck/spell-checker, camelcase, @typescript-eslint/no-explicit-any */ -import { CodeBuild } from 'aws-sdk'; +import { CodeBuild, Account } from 'aws-sdk'; import { config } from 'dotenv'; import yargs from 'yargs'; import * as aws from 'aws-sdk'; @@ -12,15 +12,44 @@ import { deleteS3Bucket, sleep } from '@aws-amplify/amplify-codegen-e2e-core'; * Supported regions: * - All Amplify regions, as reported https://docs.aws.amazon.com/general/latest/gr/amplify.html * - * NOTE: The list of supported regions must be kept in sync amongst all of: + * NOTE: + * - The list is used to configure correct region in Amplify profile as env var $CLI_REGION + * - 'ap-east-1' is not included in the list due to known discrepancy in Amplify CLI 'configure' command dropdown and supported regions + * + * The list of supported regions must be kept in sync amongst all of: + * - Amplify CLI 'amplify configure' command regions dropdown * - the internal pipeline that publishes new lambda layer versions + * - amplify-codegen/scripts/e2e-test-regions.json * - amplify-codegen/scripts/split-canary-tests.ts * - amplify-codegen/scripts/split-e2e-tests.ts + * - amplify-codegen-e2e-core/src/configure/index.ts */ -const REPO_ROOT = path.join(__dirname, '..', '..', '..'); -const SUPPORTED_REGIONS_PATH = path.join(REPO_ROOT, 'scripts', 'e2e-test-regions.json'); -const AWS_REGIONS_TO_RUN_TESTS_METADATA: TestRegion[] = JSON.parse(fs.readFileSync(SUPPORTED_REGIONS_PATH, 'utf-8')); -const AWS_REGIONS_TO_RUN_TESTS = AWS_REGIONS_TO_RUN_TESTS_METADATA.map(region => region.name); +// const REPO_ROOT = path.join(__dirname, '..', '..', '..'); +// const SUPPORTED_REGIONS_PATH = path.join(REPO_ROOT, 'scripts', 'e2e-test-regions.json'); +// const AWS_REGIONS_TO_RUN_TESTS_METADATA: TestRegion[] = JSON.parse(fs.readFileSync(SUPPORTED_REGIONS_PATH, 'utf-8')); +// const AWS_REGIONS_TO_RUN_TESTS = AWS_REGIONS_TO_RUN_TESTS_METADATA.map(region => region.name); + +const AWS_REGIONS_TO_RUN_TESTS = [ + 'us-east-1', + 'us-east-2', + 'us-west-1', + 'us-west-2', + 'eu-north-1', + 'eu-south-1', + 'eu-west-1', + 'eu-west-2', + 'eu-west-3', + 'eu-central-1', + 'ap-northeast-1', + 'ap-northeast-2', + 'ap-northeast-3', + 'ap-southeast-1', + 'ap-southeast-2', + 'ap-south-1', + 'ca-central-1', + 'me-south-1', + 'sa-east-1', +]; type TestRegion = { name: string; @@ -251,6 +280,16 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio }; }; +const isRegionEnabled = async (accountInfo: AWSAccountInfo, region: string): Promise => { + const account = new Account(accountInfo); + const optStatus = await account.getRegionOptStatus({ + RegionName: region, + AccountId: accountInfo.accountId, + }).promise(); + + return optStatus.RegionOptStatus === 'ENABLED' || optStatus.RegionOptStatus === 'ENABLED_BY_DEFAULT'; +}; + const getStacks = async (account: AWSAccountInfo, region: string): Promise => { const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); const results: StackInfo[] = []; From 702775bdbc038d33c0843461fa41d2ecbe63bfcf Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Wed, 19 Feb 2025 23:36:05 -0800 Subject: [PATCH 12/17] chore: test run Signed-off-by: Kevin Shan --- .../src/cleanup-e2e-resources.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index ac85c5919..bd2081e03 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -292,6 +292,14 @@ const isRegionEnabled = async (accountInfo: AWSAccountInfo, region: string): Pro const getStacks = async (account: AWSAccountInfo, region: string): Promise => { const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); + + const optStatus = await isRegionEnabled(account, region); + console.log('---------'); + console.log(optStatus); + console.log(account); + console.log(region); + console.log('---------'); + const results: StackInfo[] = []; let stacks; try { From e8ed83cb2fdb784813e3a8f01cf7f3fe20f3d15a Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Thu, 20 Feb 2025 00:34:08 -0800 Subject: [PATCH 13/17] chore: test run Signed-off-by: Kevin Shan --- packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index bd2081e03..32dd75aff 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -281,7 +281,7 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio }; const isRegionEnabled = async (accountInfo: AWSAccountInfo, region: string): Promise => { - const account = new Account(accountInfo); + const account = new Account(getAWSConfig(accountInfo, region)); const optStatus = await account.getRegionOptStatus({ RegionName: region, AccountId: accountInfo.accountId, From 58842ae7cd6abf1cc6222c4a68b01aa46d0eae32 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Thu, 20 Feb 2025 01:08:48 -0800 Subject: [PATCH 14/17] chore: test run Signed-off-by: Kevin Shan --- .../src/cleanup-e2e-resources.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index 32dd75aff..f1342d9c2 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -282,12 +282,17 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio const isRegionEnabled = async (accountInfo: AWSAccountInfo, region: string): Promise => { const account = new Account(getAWSConfig(accountInfo, region)); - const optStatus = await account.getRegionOptStatus({ - RegionName: region, - AccountId: accountInfo.accountId, - }).promise(); + // const optStatus = await account.getRegionOptStatus({ + // RegionName: region, + // AccountId: accountInfo.accountId, + // }).promise(); - return optStatus.RegionOptStatus === 'ENABLED' || optStatus.RegionOptStatus === 'ENABLED_BY_DEFAULT'; + // return optStatus.RegionOptStatus === 'ENABLED' || optStatus.RegionOptStatus === 'ENABLED_BY_DEFAULT'; + + + const response = await account.listRegions().promise(); + const enabledRegions = response.Regions.map(r => (r.RegionOptStatus === 'ENABLED' ? r.RegionName : null)).filter(Boolean); + return enabledRegions.includes(region); }; const getStacks = async (account: AWSAccountInfo, region: string): Promise => { From 43645f1124aa68b272af0de7a4e5a90cc100e775 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Thu, 20 Feb 2025 01:37:38 -0800 Subject: [PATCH 15/17] chore: test run Signed-off-by: Kevin Shan --- .../src/cleanup-e2e-resources.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index f1342d9c2..14578e1ff 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -282,17 +282,14 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio const isRegionEnabled = async (accountInfo: AWSAccountInfo, region: string): Promise => { const account = new Account(getAWSConfig(accountInfo, region)); - // const optStatus = await account.getRegionOptStatus({ - // RegionName: region, - // AccountId: accountInfo.accountId, - // }).promise(); + const optStatus = await account.getRegionOptStatus({ RegionName: region }).promise(); - // return optStatus.RegionOptStatus === 'ENABLED' || optStatus.RegionOptStatus === 'ENABLED_BY_DEFAULT'; + return optStatus.RegionOptStatus === 'ENABLED' || optStatus.RegionOptStatus === 'ENABLED_BY_DEFAULT'; - const response = await account.listRegions().promise(); - const enabledRegions = response.Regions.map(r => (r.RegionOptStatus === 'ENABLED' ? r.RegionName : null)).filter(Boolean); - return enabledRegions.includes(region); + // const response = await account.listRegions().promise(); + // const enabledRegions = response.Regions.map(r => (r.RegionOptStatus === 'ENABLED' ? r.RegionName : null)).filter(Boolean); + // return enabledRegions.includes(region); }; const getStacks = async (account: AWSAccountInfo, region: string): Promise => { From 04f7cb197d9711920ad0754dfc72b7e78b8a07c1 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Thu, 20 Feb 2025 02:15:58 -0800 Subject: [PATCH 16/17] chore: test run Signed-off-by: Kevin Shan --- .../src/cleanup-e2e-resources.ts | 74 ++++++++----------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index 14578e1ff..1b5eb2855 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -200,19 +200,14 @@ const getOrphanTestIamRoles = async (account: AWSAccountInfo): Promise => { const amplifyClient = new aws.Amplify(getAWSConfig(account, region)); const result: AmplifyAppInfo[] = []; - let amplifyApps = { apps: [] }; - try { - amplifyApps = await amplifyClient.listApps({ maxResults: 50 }).promise(); // keeping it to 50 as max supported is 50 - } catch (e) { - if (e?.code === 'UnrecognizedClientException') { - // Do not fail the cleanup and continue - console.log(`Listing apps for account ${account.accountId}-${region} failed with error with code ${e?.code}. Skipping.`); - return result; - } else { - throw e; - } + + const optStatus = await isRegionEnabled(account, region); + if (!optStatus) { + return result; } + const amplifyApps = await amplifyClient.listApps({ maxResults: 50 }).promise(); // keeping it to 50 as max supported is 50 + for (const app of amplifyApps.apps) { const backends: Record = {}; try { @@ -294,42 +289,35 @@ const isRegionEnabled = async (accountInfo: AWSAccountInfo, region: string): Pro const getStacks = async (account: AWSAccountInfo, region: string): Promise => { const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); + const results: StackInfo[] = []; const optStatus = await isRegionEnabled(account, region); - console.log('---------'); - console.log(optStatus); - console.log(account); - console.log(region); - console.log('---------'); - - const results: StackInfo[] = []; - let stacks; - try { - stacks = await cfnClient - .listStacks({ - StackStatusFilter: [ - 'CREATE_COMPLETE', - 'ROLLBACK_FAILED', - 'DELETE_FAILED', - 'UPDATE_COMPLETE', - 'UPDATE_ROLLBACK_FAILED', - 'UPDATE_ROLLBACK_COMPLETE', - 'IMPORT_COMPLETE', - 'IMPORT_ROLLBACK_FAILED', - 'IMPORT_ROLLBACK_COMPLETE', - ], - }) - .promise(); - } catch (e) { - if (e?.code === 'InvalidClientTokenId') { - // Do not fail the cleanup and continue - console.log(`Listing stacks for account ${account.accountId}-${region} failed with error with code ${e?.code}. Skipping.`); - return results; - } else { - throw e; - } + if (!optStatus) { + return results; } + // console.log('---------'); + // console.log(optStatus); + // console.log(account); + // console.log(region); + // console.log('---------'); + + const stacks = await cfnClient + .listStacks({ + StackStatusFilter: [ + 'CREATE_COMPLETE', + 'ROLLBACK_FAILED', + 'DELETE_FAILED', + 'UPDATE_COMPLETE', + 'UPDATE_ROLLBACK_FAILED', + 'UPDATE_ROLLBACK_COMPLETE', + 'IMPORT_COMPLETE', + 'IMPORT_ROLLBACK_FAILED', + 'IMPORT_ROLLBACK_COMPLETE', + ], + }) + .promise(); + // We are interested in only the root stacks that are deployed by amplify-cli const rootStacks = stacks.StackSummaries.filter(stack => !stack.RootId); for (const stack of rootStacks) { From 22adffa8b1626164c1d3c0532ac7d127da08c7c2 Mon Sep 17 00:00:00 2001 From: Kevin Shan Date: Thu, 20 Feb 2025 10:47:32 -0800 Subject: [PATCH 17/17] chore: test run Signed-off-by: Kevin Shan --- .../src/cleanup-e2e-resources.ts | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts index 1b5eb2855..d8a459812 100644 --- a/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts @@ -30,25 +30,25 @@ import { deleteS3Bucket, sleep } from '@aws-amplify/amplify-codegen-e2e-core'; // const AWS_REGIONS_TO_RUN_TESTS = AWS_REGIONS_TO_RUN_TESTS_METADATA.map(region => region.name); const AWS_REGIONS_TO_RUN_TESTS = [ - 'us-east-1', - 'us-east-2', - 'us-west-1', - 'us-west-2', - 'eu-north-1', - 'eu-south-1', - 'eu-west-1', - 'eu-west-2', - 'eu-west-3', - 'eu-central-1', 'ap-northeast-1', 'ap-northeast-2', 'ap-northeast-3', + 'ap-south-1', 'ap-southeast-1', 'ap-southeast-2', - 'ap-south-1', 'ca-central-1', + 'eu-central-1', + 'eu-north-1', + 'eu-south-1', + 'eu-west-1', + 'eu-west-2', + 'eu-west-3', 'me-south-1', 'sa-east-1', + 'us-east-1', + 'us-east-2', + 'us-west-1', + 'us-west-2', ]; type TestRegion = { @@ -280,11 +280,6 @@ const isRegionEnabled = async (accountInfo: AWSAccountInfo, region: string): Pro const optStatus = await account.getRegionOptStatus({ RegionName: region }).promise(); return optStatus.RegionOptStatus === 'ENABLED' || optStatus.RegionOptStatus === 'ENABLED_BY_DEFAULT'; - - - // const response = await account.listRegions().promise(); - // const enabledRegions = response.Regions.map(r => (r.RegionOptStatus === 'ENABLED' ? r.RegionName : null)).filter(Boolean); - // return enabledRegions.includes(region); }; const getStacks = async (account: AWSAccountInfo, region: string): Promise => {