Skip to content

Commit 9f37a8c

Browse files
authored
fix: cleanup detection of regional availability (#940)
* fix: cleanup detection of regional availability Signed-off-by: Kevin Shan <[email protected]> * chore: update comment Signed-off-by: Kevin Shan <[email protected]> * chore: specific service region Signed-off-by: Kevin Shan <[email protected]> * chore: add retry and exponential backoff to avoid too many requests exception Signed-off-by: Kevin Shan <[email protected]> * chore: retrieve enabled region in list to reduce requests Signed-off-by: Kevin Shan <[email protected]> * chore: update iam matching regex Signed-off-by: Kevin Shan <[email protected]> --------- Signed-off-by: Kevin Shan <[email protected]>
1 parent d791086 commit 9f37a8c

File tree

1 file changed

+62
-30
lines changed

1 file changed

+62
-30
lines changed

packages/amplify-codegen-e2e-tests/src/cleanup-e2e-resources.ts

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable spellcheck/spell-checker, camelcase, @typescript-eslint/no-explicit-any */
2-
import { CodeBuild } from 'aws-sdk';
2+
import { CodeBuild, Account } from 'aws-sdk';
33
import { config } from 'dotenv';
44
import yargs from 'yargs';
55
import * as aws from 'aws-sdk';
@@ -8,29 +8,31 @@ import fs from 'fs-extra';
88
import path from 'path';
99
import { deleteS3Bucket, sleep } from '@aws-amplify/amplify-codegen-e2e-core';
1010

11-
// Ensure to update scripts/split-e2e-tests.ts is also updated this gets updated
12-
const AWS_REGIONS_TO_RUN_TESTS = [
13-
'ap-east-1',
14-
'ap-northeast-1',
15-
'ap-northeast-2',
16-
'ap-northeast-3',
17-
'ap-south-1',
18-
'ap-southeast-1',
19-
'ap-southeast-2',
20-
'ca-central-1',
21-
'eu-central-1',
22-
'eu-north-1',
23-
'eu-south-1',
24-
'eu-west-1',
25-
'eu-west-2',
26-
'eu-west-3',
27-
'me-south-1',
28-
'sa-east-1',
29-
'us-east-1',
30-
'us-east-2',
31-
'us-west-1',
32-
'us-west-2',
33-
];
11+
/**
12+
* Supported regions:
13+
* - All Amplify regions, as reported https://docs.aws.amazon.com/general/latest/gr/amplify.html
14+
*
15+
* NOTE:
16+
* - 'ap-east-1' is not included in the list due to known discrepancy in Amplify CLI 'configure' command dropdown and supported regions
17+
* - Since 'ap-east-1' is not available via 'amplify configure', test $CLI_REGION with 'ap-east-1' will run in 'us-east-1'
18+
* and fail Amplify profile assertion in test setup phase
19+
*
20+
* The list of supported regions must be kept in sync amongst all of:
21+
* - Amplify CLI 'amplify configure' command regions dropdown
22+
* - the internal pipeline that publishes new lambda layer versions
23+
* - amplify-codegen/scripts/e2e-test-regions.json
24+
* - amplify-codegen/scripts/split-canary-tests.ts
25+
* - amplify-codegen/scripts/split-e2e-tests.ts
26+
*/
27+
const REPO_ROOT = path.join(__dirname, '..', '..', '..');
28+
const SUPPORTED_REGIONS_PATH = path.join(REPO_ROOT, 'scripts', 'e2e-test-regions.json');
29+
const AWS_REGIONS_TO_RUN_TESTS_METADATA: TestRegion[] = JSON.parse(fs.readFileSync(SUPPORTED_REGIONS_PATH, 'utf-8'));
30+
const AWS_REGIONS_TO_RUN_TESTS = AWS_REGIONS_TO_RUN_TESTS_METADATA.map(region => region.name);
31+
32+
type TestRegion = {
33+
name: string;
34+
optIn: boolean;
35+
};
3436

3537
const reportPathDir = path.normalize(path.join(__dirname, '..', 'amplify-e2e-reports'));
3638

@@ -97,7 +99,7 @@ type AWSAccountInfo = {
9799
};
98100

99101
const BUCKET_TEST_REGEX = /test/;
100-
const IAM_TEST_REGEX = /!RotateE2eAwsToken-e2eTestContextRole|-integtest$|^amplify-|^eu-|^us-|^ap-/;
102+
const IAM_TEST_REGEX = /-RotateE2eAwsToken-e2eTestContextRole|-integtest|^amplify-/;
101103
const STALE_DURATION_MS = 2 * 60 * 60 * 1000; // 2 hours in milliseconds
102104

103105
const isCI = (): boolean => process.env.CI && process.env.CODEBUILD ? true : false;
@@ -164,7 +166,23 @@ const getOrphanTestIamRoles = async (account: AWSAccountInfo): Promise<IamRoleIn
164166
},
165167
...(region ? { region } : {}),
166168
maxRetries: 10,
167-
});
169+
});
170+
171+
/**
172+
* Returns a list of regions enabled given the AWS account information
173+
* @param accountInfo aws account to check region
174+
* @returns Promise<string[]> a list of AWS regions enabled by the account
175+
*/
176+
const getRegionsEnabled = async (accountInfo: AWSAccountInfo): Promise<string[]> => {
177+
// Specify service region to avoid possible endpoint unavailable error
178+
const account = new Account({ ...accountInfo, region: 'us-east-1' });
179+
const response = await account.listRegions().promise();
180+
const enabledRegions = response.Regions.map(r =>
181+
r.RegionOptStatus === 'ENABLED' || r.RegionOptStatus === 'ENABLED_BY_DEFAULT' ? r.RegionName : null,
182+
).filter(Boolean);
183+
184+
return enabledRegions;
185+
};
168186

169187
/**
170188
* Returns a list of Amplify Apps in the region. The apps includes information about the CI build that created the app
@@ -173,8 +191,14 @@ const getOrphanTestIamRoles = async (account: AWSAccountInfo): Promise<IamRoleIn
173191
* @param region aws region to query for amplify Apps
174192
* @returns Promise<AmplifyAppInfo[]> a list of Amplify Apps in the region with build info
175193
*/
176-
const getAmplifyApps = async (account: AWSAccountInfo, region: string): Promise<AmplifyAppInfo[]> => {
194+
const getAmplifyApps = async (account: AWSAccountInfo, region: string, regionsEnabled: string[]): Promise<AmplifyAppInfo[]> => {
177195
const amplifyClient = new aws.Amplify(getAWSConfig(account, region));
196+
197+
if (!regionsEnabled.includes(region)) {
198+
console.error(`Listing apps for account ${account.accountId}-${region} failed since ${region} is not enabled. Skipping.`);
199+
return [];
200+
}
201+
178202
const amplifyApps = await amplifyClient.listApps({ maxResults: 50 }).promise(); // keeping it to 50 as max supported is 50
179203
const result: AmplifyAppInfo[] = [];
180204
for (const app of amplifyApps.apps) {
@@ -244,8 +268,14 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio
244268
};
245269
};
246270

247-
const getStacks = async (account: AWSAccountInfo, region: string): Promise<StackInfo[]> => {
271+
const getStacks = async (account: AWSAccountInfo, region: string, regionsEnabled: string[]): Promise<StackInfo[]> => {
248272
const cfnClient = new aws.CloudFormation(getAWSConfig(account, region));
273+
274+
if (!regionsEnabled.includes(region)) {
275+
console.error(`Listing stacks for account ${account.accountId}-${region} failed since ${region} is not enabled. Skipping.`);
276+
return [];
277+
}
278+
249279
const stacks = await cfnClient
250280
.listStacks({
251281
StackStatusFilter: [
@@ -725,8 +755,10 @@ const getAccountsToCleanup = async (): Promise<AWSAccountInfo[]> => {
725755
};
726756

727757
const cleanupAccount = async (account: AWSAccountInfo, accountIndex: number, filterPredicate: JobFilterPredicate): Promise<void> => {
728-
const appPromises = AWS_REGIONS_TO_RUN_TESTS.map(region => getAmplifyApps(account, region));
729-
const stackPromises = AWS_REGIONS_TO_RUN_TESTS.map(region => getStacks(account, region));
758+
const regionsEnabled = await getRegionsEnabled(account);
759+
760+
const appPromises = AWS_REGIONS_TO_RUN_TESTS.map(region => getAmplifyApps(account, region, regionsEnabled));
761+
const stackPromises = AWS_REGIONS_TO_RUN_TESTS.map(region => getStacks(account, region, regionsEnabled));
730762
const bucketPromise = getS3Buckets(account);
731763
const orphanBucketPromise = getOrphanS3TestBuckets(account);
732764
const orphanIamRolesPromise = getOrphanTestIamRoles(account);

0 commit comments

Comments
 (0)