From c041900a087ad4f3023cd4e24b0a819c35775966 Mon Sep 17 00:00:00 2001 From: Matheus Costa Date: Wed, 2 Apr 2025 21:04:15 -0300 Subject: [PATCH] chore(aws): refactor aws runner to support SDK v3 --- dist/index.js.map | Bin 16340497 -> 16341889 bytes .../providers/aws/aws-base-stack.ts | 56 +++++++++----- .../cloud-runner/providers/aws/aws-error.ts | 6 +- .../providers/aws/aws-job-stack.ts | 43 +++++++---- .../providers/aws/aws-task-runner.ts | 70 +++++++++++------- .../aws/cloud-runner-aws-task-def.ts | 6 +- src/model/cloud-runner/providers/aws/index.ts | 46 +++++++----- 7 files changed, 147 insertions(+), 80 deletions(-) diff --git a/dist/index.js.map b/dist/index.js.map index 7a7ce7a1e5f27af61733fe4cda8d35e535421db0..954f869113d6d8e4914ccc9074ee925011ad7bcd 100644 GIT binary patch delta 9507 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 G_WuIv507&I delta 7867 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 x.StackName) || []; const stackExists: Boolean = stackNames.includes(baseStackName) || false; const describeStack = async () => { - return await CF.describeStacks(describeStackInput).promise(); + return await CF.send(new DescribeStacksCommand(describeStackInput)); }; try { if (!stackExists) { CloudRunnerLogger.log(`${baseStackName} stack does not exist (${JSON.stringify(stackNames)})`); - await CF.createStack(createStackInput).promise(); + await CF.send(new CreateStackCommand(createStackInput)); CloudRunnerLogger.log(`created stack (version: ${parametersHash})`); } const CFState = await describeStack(); @@ -65,7 +75,13 @@ export class AWSBaseStack { const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue; if (stack.StackStatus === 'CREATE_IN_PROGRESS') { - await CF.waitFor('stackCreateComplete', describeStackInput).promise(); + await waitUntilStackCreateComplete( + { + client: CF, + maxWaitTime: 200, + }, + describeStackInput, + ); } if (stackExists) { @@ -73,7 +89,7 @@ export class AWSBaseStack { if (parametersHash !== stackVersion) { CloudRunnerLogger.log(`Attempting update of base stack`); try { - await CF.updateStack(updateInput).promise(); + await CF.send(new UpdateStackCommand(updateInput)); } catch (error: any) { if (error['message'].includes('No updates are to be performed')) { CloudRunnerLogger.log(`No updates are to be performed`); @@ -93,7 +109,13 @@ export class AWSBaseStack { ); } if (stack.StackStatus === 'UPDATE_IN_PROGRESS') { - await CF.waitFor('stackUpdateComplete', describeStackInput).promise(); + await waitUntilStackUpdateComplete( + { + client: CF, + maxWaitTime: 200, + }, + describeStackInput, + ); } } CloudRunnerLogger.log('base stack is now ready'); diff --git a/src/model/cloud-runner/providers/aws/aws-error.ts b/src/model/cloud-runner/providers/aws/aws-error.ts index bf58e20b..ae9fc0ab 100644 --- a/src/model/cloud-runner/providers/aws/aws-error.ts +++ b/src/model/cloud-runner/providers/aws/aws-error.ts @@ -1,15 +1,15 @@ import CloudRunnerLogger from '../../services/core/cloud-runner-logger'; -import * as SDK from 'aws-sdk'; +import { CloudFormation, DescribeStackEventsCommand } from '@aws-sdk/client-cloudformation'; import * as core from '@actions/core'; import CloudRunner from '../../cloud-runner'; export class AWSError { - static async handleStackCreationFailure(error: any, CF: SDK.CloudFormation, taskDefStackName: string) { + static async handleStackCreationFailure(error: any, CF: CloudFormation, taskDefStackName: string) { CloudRunnerLogger.log('aws error: '); core.error(JSON.stringify(error, undefined, 4)); if (CloudRunner.buildParameters.cloudRunnerDebug) { CloudRunnerLogger.log('Getting events and resources for task stack'); - const events = (await CF.describeStackEvents({ StackName: taskDefStackName }).promise()).StackEvents; + const events = (await CF.send(new DescribeStackEventsCommand({ StackName: taskDefStackName }))).StackEvents; CloudRunnerLogger.log(JSON.stringify(events, undefined, 4)); } } diff --git a/src/model/cloud-runner/providers/aws/aws-job-stack.ts b/src/model/cloud-runner/providers/aws/aws-job-stack.ts index 189155bc..aaf62218 100644 --- a/src/model/cloud-runner/providers/aws/aws-job-stack.ts +++ b/src/model/cloud-runner/providers/aws/aws-job-stack.ts @@ -1,4 +1,12 @@ -import * as SDK from 'aws-sdk'; +import { + CloudFormation, + CreateStackCommand, + CreateStackCommandInput, + DescribeStackResourcesCommand, + DescribeStacksCommand, + ListStacksCommand, + waitUntilStackCreateComplete, +} from '@aws-sdk/client-cloudformation'; import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def'; import CloudRunnerSecret from '../../options/cloud-runner-secret'; import { AWSCloudFormationTemplates } from './aws-cloud-formation-templates'; @@ -16,7 +24,7 @@ export class AWSJobStack { } public async setupCloudFormations( - CF: SDK.CloudFormation, + CF: CloudFormation, buildGuid: string, image: string, entrypoint: string[], @@ -119,7 +127,7 @@ export class AWSJobStack { let previousStackExists = true; while (previousStackExists) { previousStackExists = false; - const stacks = await CF.listStacks().promise(); + const stacks = await CF.send(new ListStacksCommand({})); if (!stacks.StackSummaries) { throw new Error('Faild to get stacks'); } @@ -132,7 +140,7 @@ export class AWSJobStack { } } } - const createStackInput: SDK.CloudFormation.CreateStackInput = { + const createStackInput: CreateStackCommandInput = { StackName: taskDefStackName, TemplateBody: taskDefCloudFormation, Capabilities: ['CAPABILITY_IAM'], @@ -140,9 +148,15 @@ export class AWSJobStack { }; try { CloudRunnerLogger.log(`Creating job aws formation ${taskDefStackName}`); - await CF.createStack(createStackInput).promise(); - await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise(); - const describeStack = await CF.describeStacks({ StackName: taskDefStackName }).promise(); + await CF.send(new CreateStackCommand(createStackInput)); + await waitUntilStackCreateComplete( + { + client: CF, + maxWaitTime: 200, + }, + { StackName: taskDefStackName }, + ); + const describeStack = await CF.send(new DescribeStacksCommand({ StackName: taskDefStackName })); for (const parameter of parameters) { if (!describeStack.Stacks?.[0].Parameters?.some((x) => x.ParameterKey === parameter.ParameterKey)) { throw new Error(`Parameter ${parameter.ParameterKey} not found in stack`); @@ -153,7 +167,7 @@ export class AWSJobStack { throw error; } - const createCleanupStackInput: SDK.CloudFormation.CreateStackInput = { + const createCleanupStackInput: CreateStackCommandInput = { StackName: `${taskDefStackName}-cleanup`, TemplateBody: CleanupCronFormation.formation, Capabilities: ['CAPABILITY_IAM'], @@ -183,7 +197,7 @@ export class AWSJobStack { if (CloudRunnerOptions.useCleanupCron) { try { CloudRunnerLogger.log(`Creating job cleanup formation`); - await CF.createStack(createCleanupStackInput).promise(); + await CF.send(new CreateStackCommand(createCleanupStackInput)); // await CF.waitFor('stackCreateComplete', { StackName: createCleanupStackInput.StackName }).promise(); } catch (error) { @@ -193,12 +207,15 @@ export class AWSJobStack { } const taskDefResources = ( - await CF.describeStackResources({ - StackName: taskDefStackName, - }).promise() + await CF.send( + new DescribeStackResourcesCommand({ + StackName: taskDefStackName, + }), + ) ).StackResources; - const baseResources = (await CF.describeStackResources({ StackName: this.baseStackName }).promise()).StackResources; + const baseResources = (await CF.send(new DescribeStackResourcesCommand({ StackName: this.baseStackName }))) + .StackResources; return { taskDefStackName, diff --git a/src/model/cloud-runner/providers/aws/aws-task-runner.ts b/src/model/cloud-runner/providers/aws/aws-task-runner.ts index 2030d845..69175115 100644 --- a/src/model/cloud-runner/providers/aws/aws-task-runner.ts +++ b/src/model/cloud-runner/providers/aws/aws-task-runner.ts @@ -1,4 +1,19 @@ -import * as AWS from 'aws-sdk'; +import { + DescribeTasksCommand, + ECS, + RunTaskCommand, + RunTaskCommandInput, + Task, + waitUntilTasksRunning, +} from '@aws-sdk/client-ecs'; +import { + DescribeStreamCommand, + DescribeStreamCommandOutput, + GetRecordsCommand, + GetRecordsCommandOutput, + GetShardIteratorCommand, + Kinesis, +} from '@aws-sdk/client-kinesis'; import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable'; import * as core from '@actions/core'; import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def'; @@ -12,8 +27,8 @@ import CloudRunnerOptions from '../../options/cloud-runner-options'; import GitHub from '../../../github'; class AWSTaskRunner { - public static ECS: AWS.ECS; - public static Kinesis: AWS.Kinesis; + public static ECS: ECS; + public static Kinesis: Kinesis; private static readonly encodedUnderscore = `$252F`; static async runTask( taskDef: CloudRunnerAWSTaskDef, @@ -60,7 +75,7 @@ class AWSTaskRunner { throw new Error(`Container Overrides length must be at most 8192`); } - const task = await AWSTaskRunner.ECS.runTask(runParameters).promise(); + const task = await AWSTaskRunner.ECS.send(new RunTaskCommand(runParameters as RunTaskCommandInput)); const taskArn = task.tasks?.[0].taskArn || ''; CloudRunnerLogger.log('Cloud runner job is starting'); await AWSTaskRunner.waitUntilTaskRunning(taskArn, cluster); @@ -108,7 +123,13 @@ class AWSTaskRunner { private static async waitUntilTaskRunning(taskArn: string, cluster: string) { try { - await AWSTaskRunner.ECS.waitFor('tasksRunning', { tasks: [taskArn], cluster }).promise(); + await waitUntilTasksRunning( + { + client: AWSTaskRunner.ECS, + maxWaitTime: 120, + }, + { tasks: [taskArn], cluster }, + ); } catch (error_) { const error = error_ as Error; await new Promise((resolve) => setTimeout(resolve, 3000)); @@ -124,10 +145,7 @@ class AWSTaskRunner { } static async describeTasks(clusterName: string, taskArn: string) { - const tasks = await AWSTaskRunner.ECS.describeTasks({ - cluster: clusterName, - tasks: [taskArn], - }).promise(); + const tasks = await AWSTaskRunner.ECS.send(new DescribeTasksCommand({ cluster: clusterName, tasks: [taskArn] })); if (tasks.tasks?.[0]) { return tasks.tasks?.[0]; } else { @@ -169,9 +187,7 @@ class AWSTaskRunner { output: string, shouldCleanup: boolean, ) { - const records = await AWSTaskRunner.Kinesis.getRecords({ - ShardIterator: iterator, - }).promise(); + const records = await AWSTaskRunner.Kinesis.send(new GetRecordsCommand({ ShardIterator: iterator })); iterator = records.NextShardIterator || ''; ({ shouldReadLogs, output, shouldCleanup } = AWSTaskRunner.logRecords( records, @@ -184,7 +200,7 @@ class AWSTaskRunner { return { iterator, shouldReadLogs, output, shouldCleanup }; } - private static checkStreamingShouldContinue(taskData: AWS.ECS.Task, timestamp: number, shouldReadLogs: boolean) { + private static checkStreamingShouldContinue(taskData: Task, timestamp: number, shouldReadLogs: boolean) { if (taskData?.lastStatus === 'UNKNOWN') { CloudRunnerLogger.log('## Cloud runner job unknwon'); } @@ -204,15 +220,17 @@ class AWSTaskRunner { } private static logRecords( - records: AWS.Kinesis.GetRecordsOutput, + records: GetRecordsCommandOutput, iterator: string, shouldReadLogs: boolean, output: string, shouldCleanup: boolean, ) { - if (records.Records.length > 0 && iterator) { - for (const record of records.Records) { - const json = JSON.parse(zlib.gunzipSync(Buffer.from(record.Data as string, 'base64')).toString('utf8')); + if ((records.Records ?? []).length > 0 && iterator) { + for (const record of records.Records ?? []) { + const json = JSON.parse( + zlib.gunzipSync(Buffer.from(record.Data as unknown as string, 'base64')).toString('utf8'), + ); if (json.messageType === 'DATA_MESSAGE') { for (const logEvent of json.logEvents) { ({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration( @@ -230,19 +248,19 @@ class AWSTaskRunner { } private static async getLogStream(kinesisStreamName: string) { - return await AWSTaskRunner.Kinesis.describeStream({ - StreamName: kinesisStreamName, - }).promise(); + return await AWSTaskRunner.Kinesis.send(new DescribeStreamCommand({ StreamName: kinesisStreamName })); } - private static async getLogIterator(stream: AWS.Kinesis.DescribeStreamOutput) { + private static async getLogIterator(stream: DescribeStreamCommandOutput) { return ( ( - await AWSTaskRunner.Kinesis.getShardIterator({ - ShardIteratorType: 'TRIM_HORIZON', - StreamName: stream.StreamDescription.StreamName, - ShardId: stream.StreamDescription.Shards[0].ShardId, - }).promise() + await AWSTaskRunner.Kinesis.send( + new GetShardIteratorCommand({ + ShardIteratorType: 'TRIM_HORIZON', + StreamName: stream.StreamDescription?.StreamName ?? '', + ShardId: stream.StreamDescription?.Shards?.[0]?.ShardId || '', + }), + ) ).ShardIterator || '' ); } diff --git a/src/model/cloud-runner/providers/aws/cloud-runner-aws-task-def.ts b/src/model/cloud-runner/providers/aws/cloud-runner-aws-task-def.ts index 4ec16196..d3d9e071 100644 --- a/src/model/cloud-runner/providers/aws/cloud-runner-aws-task-def.ts +++ b/src/model/cloud-runner/providers/aws/cloud-runner-aws-task-def.ts @@ -1,9 +1,9 @@ -import * as AWS from 'aws-sdk'; +import { StackResource } from '@aws-sdk/client-cloudformation'; class CloudRunnerAWSTaskDef { public taskDefStackName!: string; public taskDefCloudFormation!: string; - public taskDefResources: AWS.CloudFormation.StackResources | undefined; - public baseResources: AWS.CloudFormation.StackResources | undefined; + public taskDefResources: Array | undefined; + public baseResources: Array | undefined; } export default CloudRunnerAWSTaskDef; diff --git a/src/model/cloud-runner/providers/aws/index.ts b/src/model/cloud-runner/providers/aws/index.ts index 2acd48c9..2486d92e 100644 --- a/src/model/cloud-runner/providers/aws/index.ts +++ b/src/model/cloud-runner/providers/aws/index.ts @@ -1,4 +1,6 @@ -import * as SDK from 'aws-sdk'; +import { CloudFormation, DeleteStackCommand, waitUntilStackDeleteComplete } from '@aws-sdk/client-cloudformation'; +import { ECS as ECSClient } from '@aws-sdk/client-ecs'; +import { Kinesis } from '@aws-sdk/client-kinesis'; import CloudRunnerSecret from '../../options/cloud-runner-secret'; import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable'; import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def'; @@ -75,7 +77,7 @@ class AWSBuildEnvironment implements ProviderInterface { defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[], ) { process.env.AWS_REGION = Input.region; - const CF = new SDK.CloudFormation(); + const CF = new CloudFormation({ region: Input.region }); await new AwsBaseStack(this.baseStackName).setupBaseStack(CF); } @@ -89,10 +91,10 @@ class AWSBuildEnvironment implements ProviderInterface { secrets: CloudRunnerSecret[], ): Promise { process.env.AWS_REGION = Input.region; - const ECS = new SDK.ECS(); - const CF = new SDK.CloudFormation(); + const ECS = new ECSClient({ region: Input.region }); + const CF = new CloudFormation({ region: Input.region }); AwsTaskRunner.ECS = ECS; - AwsTaskRunner.Kinesis = new SDK.Kinesis(); + AwsTaskRunner.Kinesis = new Kinesis({ region: Input.region }); CloudRunnerLogger.log(`AWS Region: ${CF.config.region}`); const entrypoint = ['/bin/sh']; const startTimeMs = Date.now(); @@ -129,23 +131,31 @@ class AWSBuildEnvironment implements ProviderInterface { } } - async cleanupResources(CF: SDK.CloudFormation, taskDef: CloudRunnerAWSTaskDef) { + async cleanupResources(CF: CloudFormation, taskDef: CloudRunnerAWSTaskDef) { CloudRunnerLogger.log('Cleanup starting'); - await CF.deleteStack({ - StackName: taskDef.taskDefStackName, - }).promise(); + await CF.send(new DeleteStackCommand({ StackName: taskDef.taskDefStackName })); if (CloudRunnerOptions.useCleanupCron) { - await CF.deleteStack({ - StackName: `${taskDef.taskDefStackName}-cleanup`, - }).promise(); + await CF.send(new DeleteStackCommand({ StackName: `${taskDef.taskDefStackName}-cleanup` })); } - await CF.waitFor('stackDeleteComplete', { - StackName: taskDef.taskDefStackName, - }).promise(); - await CF.waitFor('stackDeleteComplete', { - StackName: `${taskDef.taskDefStackName}-cleanup`, - }).promise(); + await waitUntilStackDeleteComplete( + { + client: CF, + maxWaitTime: 200, + }, + { + StackName: taskDef.taskDefStackName, + }, + ); + await waitUntilStackDeleteComplete( + { + client: CF, + maxWaitTime: 200, + }, + { + StackName: `${taskDef.taskDefStackName}-cleanup`, + }, + ); CloudRunnerLogger.log(`Deleted Stack: ${taskDef.taskDefStackName}`); CloudRunnerLogger.log('Cleanup complete'); }