Skip to content
This repository was archived by the owner on Dec 31, 2025. It is now read-only.

Commit c11c305

Browse files
committed
fix(upgrade): disable EventBridge rule NewLogGroup_rule during asea prep
1 parent 097e81a commit c11c305

File tree

6 files changed

+145
-61
lines changed

6 files changed

+145
-61
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"tabWidth": 2,
3+
"printWidth": 120,
4+
"singleQuote": true,
5+
"trailingComma": "all",
6+
"arrowParens": "avoid"
7+
}

reference-artifacts/Custom-Scripts/lza-upgrade/src/common/utils/accounts.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313

1414
import { DynamoDB } from '../aws/dynamodb';
1515
import { Account } from '../outputs/accounts';
16+
import { STS } from '../aws/sts';
17+
18+
19+
export interface Environment {
20+
accountId: string;
21+
accountKey: string;
22+
region: string;
23+
}
1624

1725
export async function loadAccounts(tableName: string, client: DynamoDB): Promise<Account[]> {
1826
let index = 0;
@@ -31,3 +39,22 @@ export async function loadAccounts(tableName: string, client: DynamoDB): Promise
3139
}
3240
return accounts;
3341
}
42+
43+
export function getEnvironments(accounts: Account[], regions: string[]): Environment[] {
44+
const environments: Environment[] = [];
45+
for (const account of accounts) {
46+
for (const region of regions) {
47+
environments.push({
48+
accountId: account.id,
49+
accountKey: account.key,
50+
region,
51+
});
52+
}
53+
}
54+
return environments;
55+
}
56+
57+
export async function assumeRole(accountId: string, roleName: string) {
58+
const sts = new STS();
59+
return sts.getCredentialsForAccountAndRole(accountId, roleName);
60+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
5+
* with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
10+
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*/
13+
14+
import { Account } from './common/outputs/accounts';
15+
import { DynamoDB } from './common/aws/dynamodb';
16+
import { Environment, getEnvironments, loadAccounts } from './common/utils/accounts';
17+
import { loadAseaConfig } from './asea-config/load';
18+
import { Config } from './config';
19+
import { AcceleratorConfig } from './asea-config';
20+
import { STS } from './common/aws/sts';
21+
import { throttlingBackOff } from './common/aws/backoff';
22+
import { EventBridgeClient, DisableRuleCommand, ResourceNotFoundException } from '@aws-sdk/client-eventbridge';
23+
24+
export class DisableRules {
25+
homeRegion: string;
26+
assumeRoleName: string;
27+
configRepositoryName: string;
28+
accountList: Account[];
29+
enabledRegions: string[];
30+
sts: STS;
31+
constructor(config: Config,
32+
disableRuleConfig: { accountList: Account[], enabledRegions: string[], acceleratorConfig: AcceleratorConfig },
33+
) {
34+
this.homeRegion = config.homeRegion;
35+
this.sts = new STS();
36+
this.assumeRoleName = config.assumeRoleName ?? 'OrganizationAccountAccessRole';
37+
this.configRepositoryName = config.repositoryName;
38+
this.accountList = disableRuleConfig.accountList;
39+
this.enabledRegions = disableRuleConfig.enabledRegions;
40+
}
41+
42+
static async init(config: Config) {
43+
const accountList = await loadAccounts(config.parametersTableName, new DynamoDB(undefined, config.homeRegion));
44+
const acceleratorConfig = await loadAseaConfig({
45+
filePath: 'raw/config.json',
46+
repositoryName: config.repositoryName,
47+
defaultRegion: config.homeRegion,
48+
});
49+
const enabledRegions = acceleratorConfig['global-options']['supported-regions'];
50+
const disableRules = new DisableRules(config, {accountList, enabledRegions, acceleratorConfig});
51+
return disableRules;
52+
}
53+
async disableAllAccountRules(prefix: string) {
54+
const environments = getEnvironments(this.accountList, this.enabledRegions);
55+
const eventBridgeClientMap = await this.getEventBridgeClientMap(environments);
56+
const deleteRulesPromises = environments.map(environment => this.disableEventBridgeRules(eventBridgeClientMap, environment.accountId, environment.region, prefix.replaceAll('-', '')));
57+
await Promise.all(deleteRulesPromises);
58+
}
59+
60+
async disableEventBridgeRules(eventBridgeClientMap: Map<string, EventBridgeClient>, accountId: string, region: string, prefix: string,){
61+
const client = eventBridgeClientMap.get(`${accountId}-${region}`);
62+
if (!client) {
63+
throw new Error(`No client found for account ${accountId} and region ${region}`);
64+
};
65+
const suffixes = [
66+
'NewLogGroup_rule'
67+
];
68+
for (const suffix of suffixes) {
69+
try {
70+
const command = new DisableRuleCommand({
71+
Name: `${prefix}-${suffix}`,
72+
});
73+
await throttlingBackOff (() => client.send(command));
74+
} catch (e: any) {
75+
if (e instanceof ResourceNotFoundException) {
76+
continue;
77+
}
78+
}
79+
console.log(`Disabling rule ${prefix}-${suffix} in ${accountId}-${region}`);
80+
}
81+
}
82+
83+
async getEventBridgeClientMap(environments: Environment[]) {
84+
const eventBridgeClientMap = new Map<string, EventBridgeClient>();
85+
const promises = [];
86+
for (const environment of environments) {
87+
promises.push(this.createEventBridgeClients(this.assumeRoleName, environment.accountId, environment.region));
88+
}
89+
const eventBridgeClients = await Promise.all(promises);
90+
eventBridgeClients.forEach((client) => {
91+
eventBridgeClientMap.set(`${client.accountId}-${client.region}`, client.client);
92+
});
93+
return eventBridgeClientMap;
94+
}
95+
96+
async createEventBridgeClients(assumeRoleName: string, accountId: string, region: string) {
97+
const credentials = await this.sts.getCredentialsForAccountAndRole(accountId, assumeRoleName);
98+
const client = new EventBridgeClient({ credentials, region });
99+
return {
100+
accountId,
101+
region,
102+
client,
103+
};
104+
}
105+
}

reference-artifacts/Custom-Scripts/lza-upgrade/src/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { PostMigration } from './post-migration';
2020
import { Preparation } from './preparation';
2121
import { ResourceMapping } from './resource-mapping';
2222
import { Snapshot } from './snapshot';
23+
import { DisableRules } from './disable-rules';
2324

2425
async function main() {
2526
const args = process.argv.slice(2);
@@ -49,8 +50,8 @@ async function main() {
4950
case 'asea-prep':
5051
const preparation = new Preparation(config);
5152
await preparation.prepareAsea();
52-
const disableAccountRules = new Snapshot(config);
53-
await disableAccountRules.disableSubscriptionRule();
53+
const disableRulesInPrep = await DisableRules.init(config);
54+
await disableRulesInPrep.disableAllAccountRules(config.aseaPrefix);
5455
break;
5556
case 'lza-prep':
5657
const lzaPreparation = new Preparation(config);
@@ -74,8 +75,8 @@ async function main() {
7475
}
7576
break;
7677
case 'disable-rules':
77-
const disableRules = new Snapshot(config);
78-
await disableRules.disableSubscriptionRule();
78+
const disableRules = await DisableRules.init(config);
79+
await disableRules.disableAllAccountRules(config.aseaPrefix);
7980
break;
8081
case 'post-migration':
8182
await new PostMigration(config, args).process();

reference-artifacts/Custom-Scripts/lza-upgrade/src/preparation/asea.ts

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,11 @@ import {
3030
ListImagesCommand,
3131
ListImagesCommandOutput,
3232
} from '@aws-sdk/client-ecr';
33-
import { EventBridgeClient, DisableRuleCommand, ResourceNotFoundException } from '@aws-sdk/client-eventbridge';
33+
import { EventBridgeClient, DisableRuleCommand } from '@aws-sdk/client-eventbridge';
3434
import { KMSClient, ListAliasesCommand, GetKeyPolicyCommand, PutKeyPolicyCommand } from '@aws-sdk/client-kms';
3535

3636
import { SSMClient, PutParameterCommandInput, PutParameterCommand } from '@aws-sdk/client-ssm';
3737

38-
import { AcceleratorConfig } from '../asea-config';
39-
import { getCredentials, getAccountList } from '../snapshot/snapshotConfiguration';
40-
import { AwsCredentialIdentity } from '@aws-sdk/types';
41-
4238
export async function updateSecretsKey(prefix: string, operationsAccountId: string, region: string): Promise<void> {
4339
const kmsClient = new KMSClient({ region: region });
4440
const keyAliases = await kmsClient.send(new ListAliasesCommand({}));
@@ -247,43 +243,3 @@ export async function disableASEARules(prefix: string) {
247243
await Promise.all(disableRulePromises);
248244
console.log('Disabled Rules');
249245
}
250-
251-
export async function disableAllAccountAseaRules(aseaConfig: AcceleratorConfig, roleName: string, prefix: string) {
252-
const accounts = await getAccountList();
253-
const regions = aseaConfig['global-options']['supported-regions'];
254-
const accountPromises = []
255-
for (const account of accounts) {
256-
if (account.Status !== 'SUSPENDED') {
257-
const credentials = await getCredentials(account.Id!, roleName);
258-
if (credentials === undefined) {
259-
continue;
260-
}
261-
console.log(`Disabling rules in ${account.Id}`);
262-
accountPromises.push(
263-
disableRules(credentials, regions, prefix),
264-
);
265-
}
266-
}
267-
await Promise.all(accountPromises);
268-
}
269-
270-
async function disableRules(credentials: AwsCredentialIdentity, regions: any, prefix: string){
271-
for (const region of regions) {
272-
const client = new EventBridgeClient({ region: region, credentials });
273-
const suffixes = [
274-
'NewLogGroup_rule'
275-
];
276-
for (const suffix of suffixes) {
277-
try {
278-
const command = new DisableRuleCommand({
279-
Name: `${prefix}-${suffix}`,
280-
});
281-
await client.send(command);
282-
} catch (e: any) {
283-
if (e instanceof ResourceNotFoundException) {
284-
continue;
285-
}
286-
}
287-
}
288-
}
289-
}

reference-artifacts/Custom-Scripts/lza-upgrade/src/snapshot.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { loadAseaConfig } from './asea-config/load';
1515
import { Config } from './config';
1616
import { Reset } from './snapshot/common/dynamodb';
1717
import { getChangedResources } from './snapshot/lib/reporting';
18-
import { disableAllAccountAseaRules } from './preparation/asea';
1918
import * as snapshot from './snapshot/snapshotConfiguration';
2019

2120
export class Snapshot {
@@ -79,15 +78,4 @@ export class Snapshot {
7978
const cleanup = new Reset(this.tableName, this.homeRegion);
8079
await cleanup.dropTable();
8180
}
82-
83-
async disableSubscriptionRule() {
84-
const aseaConfig = await loadAseaConfig({
85-
filePath: 'raw/config.json',
86-
repositoryName: this.aseaConfigRepositoryName,
87-
defaultRegion: this.homeRegion,
88-
localFilePath: this.localConfigFilePath,
89-
});
90-
91-
await disableAllAccountAseaRules(aseaConfig, this.roleName, this.aseaPrefix.replaceAll('-', ''));
92-
}
9381
}

0 commit comments

Comments
 (0)