chore(aws): refactor aws services to support SDK v3

This commit is contained in:
Matheus Costa 2025-04-02 21:00:11 -03:00
parent 914032f6fb
commit ac08240d19
No known key found for this signature in database
GPG Key ID: 3574E997C5D4563B
5 changed files with 82 additions and 40 deletions

BIN
dist/index.js generated vendored

Binary file not shown.

BIN
dist/index.js.map generated vendored

Binary file not shown.

BIN
dist/licenses.txt generated vendored

Binary file not shown.

View File

@ -1,4 +1,11 @@
import AWS from 'aws-sdk'; import {
CloudFormation,
DeleteStackCommand,
DeleteStackCommandInput,
DescribeStackResourcesCommand,
} from '@aws-sdk/client-cloudformation';
import { CloudWatchLogs, DeleteLogGroupCommand } from '@aws-sdk/client-cloudwatch-logs';
import { ECS, StopTaskCommand } from '@aws-sdk/client-ecs';
import Input from '../../../../input'; import Input from '../../../../input';
import CloudRunnerLogger from '../../../services/core/cloud-runner-logger'; import CloudRunnerLogger from '../../../services/core/cloud-runner-logger';
import { TaskService } from './task-service'; import { TaskService } from './task-service';
@ -12,9 +19,9 @@ export class GarbageCollectionService {
public static async cleanup(deleteResources = false, OneDayOlderOnly: boolean = false) { public static async cleanup(deleteResources = false, OneDayOlderOnly: boolean = false) {
process.env.AWS_REGION = Input.region; process.env.AWS_REGION = Input.region;
const CF = new AWS.CloudFormation(); const CF = new CloudFormation({ region: Input.region });
const ecs = new AWS.ECS(); const ecs = new ECS({ region: Input.region });
const cwl = new AWS.CloudWatchLogs(); const cwl = new CloudWatchLogs({ region: Input.region });
const taskDefinitionsInUse = new Array(); const taskDefinitionsInUse = new Array();
const tasks = await TaskService.getTasks(); const tasks = await TaskService.getTasks();
@ -23,14 +30,14 @@ export class GarbageCollectionService {
taskDefinitionsInUse.push(taskElement.taskDefinitionArn); taskDefinitionsInUse.push(taskElement.taskDefinitionArn);
if (deleteResources && (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(taskElement.createdAt!))) { if (deleteResources && (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(taskElement.createdAt!))) {
CloudRunnerLogger.log(`Stopping task ${taskElement.containers?.[0].name}`); CloudRunnerLogger.log(`Stopping task ${taskElement.containers?.[0].name}`);
await ecs.stopTask({ task: taskElement.taskArn || '', cluster: element }).promise(); await ecs.send(new StopTaskCommand({ task: taskElement.taskArn || '', cluster: element }));
} }
} }
const jobStacks = await TaskService.getCloudFormationJobStacks(); const jobStacks = await TaskService.getCloudFormationJobStacks();
for (const element of jobStacks) { for (const element of jobStacks) {
if ( if (
(await CF.describeStackResources({ StackName: element.StackName }).promise()).StackResources?.some( (await CF.send(new DescribeStackResourcesCommand({ StackName: element.StackName }))).StackResources?.some(
(x) => x.ResourceType === 'AWS::ECS::TaskDefinition' && taskDefinitionsInUse.includes(x.PhysicalResourceId), (x) => x.ResourceType === 'AWS::ECS::TaskDefinition' && taskDefinitionsInUse.includes(x.PhysicalResourceId),
) )
) { ) {
@ -39,7 +46,10 @@ export class GarbageCollectionService {
return; return;
} }
if (deleteResources && (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(element.CreationTime))) { if (
deleteResources &&
(!OneDayOlderOnly || (element.CreationTime && GarbageCollectionService.isOlderThan1day(element.CreationTime)))
) {
if (element.StackName === 'game-ci' || element.TemplateDescription === 'Game-CI base stack') { if (element.StackName === 'game-ci' || element.TemplateDescription === 'Game-CI base stack') {
CloudRunnerLogger.log(`Skipping ${element.StackName} ignore list`); CloudRunnerLogger.log(`Skipping ${element.StackName} ignore list`);
@ -47,8 +57,8 @@ export class GarbageCollectionService {
} }
CloudRunnerLogger.log(`Deleting ${element.StackName}`); CloudRunnerLogger.log(`Deleting ${element.StackName}`);
const deleteStackInput: AWS.CloudFormation.DeleteStackInput = { StackName: element.StackName }; const deleteStackInput: DeleteStackCommandInput = { StackName: element.StackName };
await CF.deleteStack(deleteStackInput).promise(); await CF.send(new DeleteStackCommand(deleteStackInput));
} }
} }
const logGroups = await TaskService.getLogGroups(); const logGroups = await TaskService.getLogGroups();
@ -58,7 +68,7 @@ export class GarbageCollectionService {
(!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(new Date(element.creationTime!))) (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(new Date(element.creationTime!)))
) { ) {
CloudRunnerLogger.log(`Deleting ${element.logGroupName}`); CloudRunnerLogger.log(`Deleting ${element.logGroupName}`);
await cwl.deleteLogGroup({ logGroupName: element.logGroupName || '' }).promise(); await cwl.send(new DeleteLogGroupCommand({ logGroupName: element.logGroupName || '' }));
} }
} }

View File

@ -1,12 +1,31 @@
import AWS from 'aws-sdk'; import {
CloudFormation,
DescribeStackResourcesCommand,
DescribeStacksCommand,
ListStacksCommand,
StackSummary,
} from '@aws-sdk/client-cloudformation';
import {
CloudWatchLogs,
DescribeLogGroupsCommand,
DescribeLogGroupsCommandInput,
LogGroup,
} from '@aws-sdk/client-cloudwatch-logs';
import {
DescribeTasksCommand,
DescribeTasksCommandInput,
ECS,
ListClustersCommand,
ListTasksCommand,
ListTasksCommandInput,
Task,
} from '@aws-sdk/client-ecs';
import { ListObjectsCommand, ListObjectsCommandInput, S3 } from '@aws-sdk/client-s3';
import Input from '../../../../input'; import Input from '../../../../input';
import CloudRunnerLogger from '../../../services/core/cloud-runner-logger'; import CloudRunnerLogger from '../../../services/core/cloud-runner-logger';
import { BaseStackFormation } from '../cloud-formations/base-stack-formation'; import { BaseStackFormation } from '../cloud-formations/base-stack-formation';
import AwsTaskRunner from '../aws-task-runner'; import AwsTaskRunner from '../aws-task-runner';
import { ListObjectsRequest } from 'aws-sdk/clients/s3';
import CloudRunner from '../../../cloud-runner'; import CloudRunner from '../../../cloud-runner';
import { StackSummaries } from 'aws-sdk/clients/cloudformation';
import { LogGroups } from 'aws-sdk/clients/cloudwatchlogs';
export class TaskService { export class TaskService {
static async watch() { static async watch() {
@ -20,20 +39,24 @@ export class TaskService {
return output; return output;
} }
public static async getCloudFormationJobStacks() { public static async getCloudFormationJobStacks() {
const result: StackSummaries = []; const result: StackSummary[] = [];
CloudRunnerLogger.log(``); CloudRunnerLogger.log(``);
CloudRunnerLogger.log(`List Cloud Formation Stacks`); CloudRunnerLogger.log(`List Cloud Formation Stacks`);
process.env.AWS_REGION = Input.region; process.env.AWS_REGION = Input.region;
const CF = new AWS.CloudFormation(); const CF = new CloudFormation({ region: Input.region });
const stacks = const stacks =
(await CF.listStacks().promise()).StackSummaries?.filter( (await CF.send(new ListStacksCommand({}))).StackSummaries?.filter(
(_x) => (_x) =>
_x.StackStatus !== 'DELETE_COMPLETE' && _x.TemplateDescription !== BaseStackFormation.baseStackDecription, _x.StackStatus !== 'DELETE_COMPLETE' && _x.TemplateDescription !== BaseStackFormation.baseStackDecription,
) || []; ) || [];
CloudRunnerLogger.log(``); CloudRunnerLogger.log(``);
CloudRunnerLogger.log(`Cloud Formation Stacks ${stacks.length}`); CloudRunnerLogger.log(`Cloud Formation Stacks ${stacks.length}`);
for (const element of stacks) { for (const element of stacks) {
const ageDate: Date = new Date(Date.now() - element.CreationTime.getTime()); if (!element.CreationTime) {
CloudRunnerLogger.log(`${element.StackName} due to undefined CreationTime`);
}
const ageDate: Date = new Date(Date.now() - (element.CreationTime?.getTime() ?? 0));
CloudRunnerLogger.log( CloudRunnerLogger.log(
`Task Stack ${element.StackName} - Age D${Math.floor( `Task Stack ${element.StackName} - Age D${Math.floor(
@ -43,14 +66,18 @@ export class TaskService {
result.push(element); result.push(element);
} }
const baseStacks = const baseStacks =
(await CF.listStacks().promise()).StackSummaries?.filter( (await CF.send(new ListStacksCommand({}))).StackSummaries?.filter(
(_x) => (_x) =>
_x.StackStatus !== 'DELETE_COMPLETE' && _x.TemplateDescription === BaseStackFormation.baseStackDecription, _x.StackStatus !== 'DELETE_COMPLETE' && _x.TemplateDescription === BaseStackFormation.baseStackDecription,
) || []; ) || [];
CloudRunnerLogger.log(``); CloudRunnerLogger.log(``);
CloudRunnerLogger.log(`Base Stacks ${baseStacks.length}`); CloudRunnerLogger.log(`Base Stacks ${baseStacks.length}`);
for (const element of baseStacks) { for (const element of baseStacks) {
const ageDate: Date = new Date(Date.now() - element.CreationTime.getTime()); if (!element.CreationTime) {
CloudRunnerLogger.log(`${element.StackName} due to undefined CreationTime`);
}
const ageDate: Date = new Date(Date.now() - (element.CreationTime?.getTime() ?? 0));
CloudRunnerLogger.log( CloudRunnerLogger.log(
`Task Stack ${element.StackName} - Age D${Math.floor( `Task Stack ${element.StackName} - Age D${Math.floor(
@ -64,22 +91,22 @@ export class TaskService {
return result; return result;
} }
public static async getTasks() { public static async getTasks() {
const result: { taskElement: AWS.ECS.Task; element: string }[] = []; const result: { taskElement: Task; element: string }[] = [];
CloudRunnerLogger.log(``); CloudRunnerLogger.log(``);
CloudRunnerLogger.log(`List Tasks`); CloudRunnerLogger.log(`List Tasks`);
process.env.AWS_REGION = Input.region; process.env.AWS_REGION = Input.region;
const ecs = new AWS.ECS(); const ecs = new ECS({ region: Input.region });
const clusters = (await ecs.listClusters().promise()).clusterArns || []; const clusters = (await ecs.send(new ListClustersCommand({}))).clusterArns || [];
CloudRunnerLogger.log(`Task Clusters ${clusters.length}`); CloudRunnerLogger.log(`Task Clusters ${clusters.length}`);
for (const element of clusters) { for (const element of clusters) {
const input: AWS.ECS.ListTasksRequest = { const input: ListTasksCommandInput = {
cluster: element, cluster: element,
}; };
const list = (await ecs.listTasks(input).promise()).taskArns || []; const list = (await ecs.send(new ListTasksCommand(input))).taskArns || [];
if (list.length > 0) { if (list.length > 0) {
const describeInput: AWS.ECS.DescribeTasksRequest = { tasks: list, cluster: element }; const describeInput: DescribeTasksCommandInput = { tasks: list, cluster: element };
const describeList = (await ecs.describeTasks(describeInput).promise()).tasks || []; const describeList = (await ecs.send(new DescribeTasksCommand(describeInput))).tasks || [];
if (describeList.length === 0) { if (describeList.length === 0) {
CloudRunnerLogger.log(`No Tasks`); CloudRunnerLogger.log(`No Tasks`);
continue; continue;
@ -105,14 +132,18 @@ export class TaskService {
} }
public static async awsDescribeJob(job: string) { public static async awsDescribeJob(job: string) {
process.env.AWS_REGION = Input.region; process.env.AWS_REGION = Input.region;
const CF = new AWS.CloudFormation(); const CF = new CloudFormation({ region: Input.region });
const stack = (await CF.listStacks().promise()).StackSummaries?.find((_x) => _x.StackName === job) || undefined; const stack =
const stackInfo = (await CF.describeStackResources({ StackName: job }).promise()) || undefined; (await CF.send(new ListStacksCommand({}))).StackSummaries?.find((_x) => _x.StackName === job) || undefined;
const stackInfo2 = (await CF.describeStacks({ StackName: job }).promise()) || undefined; const stackInfo = (await CF.send(new DescribeStackResourcesCommand({ StackName: job }))) || undefined;
const stackInfo2 = (await CF.send(new DescribeStacksCommand({ StackName: job }))) || undefined;
if (stack === undefined) { if (stack === undefined) {
throw new Error('stack not defined'); throw new Error('stack not defined');
} }
const ageDate: Date = new Date(Date.now() - stack.CreationTime.getTime()); if (!stack.CreationTime) {
CloudRunnerLogger.log(`${stack.StackName} due to undefined CreationTime`);
}
const ageDate: Date = new Date(Date.now() - (stack.CreationTime?.getTime() ?? 0));
const message = ` const message = `
Task Stack ${stack.StackName} Task Stack ${stack.StackName}
Age D${Math.floor(ageDate.getHours() / 24)} H${ageDate.getHours()} M${ageDate.getMinutes()} Age D${Math.floor(ageDate.getHours() / 24)} H${ageDate.getHours()} M${ageDate.getMinutes()}
@ -125,17 +156,17 @@ export class TaskService {
return message; return message;
} }
public static async getLogGroups() { public static async getLogGroups() {
const result: LogGroups = []; const result: Array<LogGroup> = [];
process.env.AWS_REGION = Input.region; process.env.AWS_REGION = Input.region;
const ecs = new AWS.CloudWatchLogs(); const ecs = new CloudWatchLogs();
let logStreamInput: AWS.CloudWatchLogs.DescribeLogGroupsRequest = { let logStreamInput: DescribeLogGroupsCommandInput = {
/* logGroupNamePrefix: 'game-ci' */ /* logGroupNamePrefix: 'game-ci' */
}; };
let logGroupsDescribe = await ecs.describeLogGroups(logStreamInput).promise(); let logGroupsDescribe = await ecs.send(new DescribeLogGroupsCommand(logStreamInput));
const logGroups = logGroupsDescribe.logGroups || []; const logGroups = logGroupsDescribe.logGroups || [];
while (logGroupsDescribe.nextToken) { while (logGroupsDescribe.nextToken) {
logStreamInput = { /* logGroupNamePrefix: 'game-ci',*/ nextToken: logGroupsDescribe.nextToken }; logStreamInput = { /* logGroupNamePrefix: 'game-ci',*/ nextToken: logGroupsDescribe.nextToken };
logGroupsDescribe = await ecs.describeLogGroups(logStreamInput).promise(); logGroupsDescribe = await ecs.send(new DescribeLogGroupsCommand(logStreamInput));
logGroups.push(...(logGroupsDescribe?.logGroups || [])); logGroups.push(...(logGroupsDescribe?.logGroups || []));
} }
@ -159,11 +190,12 @@ export class TaskService {
} }
public static async getLocks() { public static async getLocks() {
process.env.AWS_REGION = Input.region; process.env.AWS_REGION = Input.region;
const s3 = new AWS.S3(); const s3 = new S3({ region: Input.region });
const listRequest: ListObjectsRequest = { const listRequest: ListObjectsCommandInput = {
Bucket: CloudRunner.buildParameters.awsStackName, Bucket: CloudRunner.buildParameters.awsStackName,
}; };
const results = await s3.listObjects(listRequest).promise();
const results = await s3.send(new ListObjectsCommand(listRequest));
return results.Contents || []; return results.Contents || [];
} }