mirror of
https://github.com/game-ci/unity-builder.git
synced 2025-07-04 12:25:19 -04:00
Feat/migrate aws sdk v3 (#698)
* chore(cloud-runner): migrate/replace deps aws-sdk v2 to v3 * chore(aws): refactor aws services to support SDK v3 * chore(aws): refactor aws runner to support SDK v3 * chore(aws): update dist * fix(aws): error handling wrap try/catch to avoid unhandled promise rejections. * fix(aws): keeping the syntax simpler for arrays
This commit is contained in:
parent
9d6bdcbdc5
commit
81ed299e10
BIN
dist/index.js
generated
vendored
BIN
dist/index.js
generated
vendored
Binary file not shown.
BIN
dist/index.js.map
generated
vendored
BIN
dist/index.js.map
generated
vendored
Binary file not shown.
BIN
dist/licenses.txt
generated
vendored
BIN
dist/licenses.txt
generated
vendored
Binary file not shown.
@ -32,6 +32,11 @@
|
|||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^1.11.1",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/github": "^6.0.0",
|
"@actions/github": "^6.0.0",
|
||||||
|
"@aws-sdk/client-cloudformation": "^3.777.0",
|
||||||
|
"@aws-sdk/client-cloudwatch-logs": "^3.777.0",
|
||||||
|
"@aws-sdk/client-ecs": "^3.778.0",
|
||||||
|
"@aws-sdk/client-kinesis": "^3.777.0",
|
||||||
|
"@aws-sdk/client-s3": "^3.779.0",
|
||||||
"@kubernetes/client-node": "^0.16.3",
|
"@kubernetes/client-node": "^0.16.3",
|
||||||
"@octokit/core": "^5.1.0",
|
"@octokit/core": "^5.1.0",
|
||||||
"async-wait-until": "^2.0.12",
|
"async-wait-until": "^2.0.12",
|
||||||
|
@ -1,6 +1,18 @@
|
|||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as SDK from 'aws-sdk';
|
import {
|
||||||
|
CloudFormation,
|
||||||
|
CreateStackCommand,
|
||||||
|
CreateStackCommandInput,
|
||||||
|
DescribeStacksCommand,
|
||||||
|
DescribeStacksCommandInput,
|
||||||
|
ListStacksCommand,
|
||||||
|
Parameter,
|
||||||
|
UpdateStackCommand,
|
||||||
|
UpdateStackCommandInput,
|
||||||
|
waitUntilStackCreateComplete,
|
||||||
|
waitUntilStackUpdateComplete,
|
||||||
|
} from '@aws-sdk/client-cloudformation';
|
||||||
import { BaseStackFormation } from './cloud-formations/base-stack-formation';
|
import { BaseStackFormation } from './cloud-formations/base-stack-formation';
|
||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
|
|
||||||
@ -10,51 +22,49 @@ export class AWSBaseStack {
|
|||||||
}
|
}
|
||||||
private baseStackName: string;
|
private baseStackName: string;
|
||||||
|
|
||||||
async setupBaseStack(CF: SDK.CloudFormation) {
|
async setupBaseStack(CF: CloudFormation) {
|
||||||
const baseStackName = this.baseStackName;
|
const baseStackName = this.baseStackName;
|
||||||
|
|
||||||
const baseStack = BaseStackFormation.formation;
|
const baseStack = BaseStackFormation.formation;
|
||||||
|
|
||||||
// Cloud Formation Input
|
// Cloud Formation Input
|
||||||
const describeStackInput: SDK.CloudFormation.DescribeStacksInput = {
|
const describeStackInput: DescribeStacksCommandInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
};
|
};
|
||||||
const parametersWithoutHash: SDK.CloudFormation.Parameter[] = [
|
const parametersWithoutHash: Parameter[] = [{ ParameterKey: 'EnvironmentName', ParameterValue: baseStackName }];
|
||||||
{ ParameterKey: 'EnvironmentName', ParameterValue: baseStackName },
|
|
||||||
];
|
|
||||||
const parametersHash = crypto
|
const parametersHash = crypto
|
||||||
.createHash('md5')
|
.createHash('md5')
|
||||||
.update(baseStack + JSON.stringify(parametersWithoutHash))
|
.update(baseStack + JSON.stringify(parametersWithoutHash))
|
||||||
.digest('hex');
|
.digest('hex');
|
||||||
const parameters: SDK.CloudFormation.Parameter[] = [
|
const parameters: Parameter[] = [
|
||||||
...parametersWithoutHash,
|
...parametersWithoutHash,
|
||||||
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
|
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
|
||||||
];
|
];
|
||||||
const updateInput: SDK.CloudFormation.UpdateStackInput = {
|
const updateInput: UpdateStackCommandInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
TemplateBody: baseStack,
|
TemplateBody: baseStack,
|
||||||
Parameters: parameters,
|
Parameters: parameters,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
};
|
};
|
||||||
const createStackInput: SDK.CloudFormation.CreateStackInput = {
|
const createStackInput: CreateStackCommandInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
TemplateBody: baseStack,
|
TemplateBody: baseStack,
|
||||||
Parameters: parameters,
|
Parameters: parameters,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const stacks = await CF.listStacks({
|
const stacks = await CF.send(
|
||||||
StackStatusFilter: ['UPDATE_COMPLETE', 'CREATE_COMPLETE', 'ROLLBACK_COMPLETE'],
|
new ListStacksCommand({ StackStatusFilter: ['UPDATE_COMPLETE', 'CREATE_COMPLETE', 'ROLLBACK_COMPLETE'] }),
|
||||||
}).promise();
|
);
|
||||||
const stackNames = stacks.StackSummaries?.map((x) => x.StackName) || [];
|
const stackNames = stacks.StackSummaries?.map((x) => x.StackName) || [];
|
||||||
const stackExists: Boolean = stackNames.includes(baseStackName) || false;
|
const stackExists: Boolean = stackNames.includes(baseStackName) || false;
|
||||||
const describeStack = async () => {
|
const describeStack = async () => {
|
||||||
return await CF.describeStacks(describeStackInput).promise();
|
return await CF.send(new DescribeStacksCommand(describeStackInput));
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
if (!stackExists) {
|
if (!stackExists) {
|
||||||
CloudRunnerLogger.log(`${baseStackName} stack does not exist (${JSON.stringify(stackNames)})`);
|
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})`);
|
CloudRunnerLogger.log(`created stack (version: ${parametersHash})`);
|
||||||
}
|
}
|
||||||
const CFState = await describeStack();
|
const CFState = await describeStack();
|
||||||
@ -65,7 +75,13 @@ export class AWSBaseStack {
|
|||||||
const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue;
|
const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue;
|
||||||
|
|
||||||
if (stack.StackStatus === 'CREATE_IN_PROGRESS') {
|
if (stack.StackStatus === 'CREATE_IN_PROGRESS') {
|
||||||
await CF.waitFor('stackCreateComplete', describeStackInput).promise();
|
await waitUntilStackCreateComplete(
|
||||||
|
{
|
||||||
|
client: CF,
|
||||||
|
maxWaitTime: 200,
|
||||||
|
},
|
||||||
|
describeStackInput,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackExists) {
|
if (stackExists) {
|
||||||
@ -73,7 +89,7 @@ export class AWSBaseStack {
|
|||||||
if (parametersHash !== stackVersion) {
|
if (parametersHash !== stackVersion) {
|
||||||
CloudRunnerLogger.log(`Attempting update of base stack`);
|
CloudRunnerLogger.log(`Attempting update of base stack`);
|
||||||
try {
|
try {
|
||||||
await CF.updateStack(updateInput).promise();
|
await CF.send(new UpdateStackCommand(updateInput));
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error['message'].includes('No updates are to be performed')) {
|
if (error['message'].includes('No updates are to be performed')) {
|
||||||
CloudRunnerLogger.log(`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') {
|
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');
|
CloudRunnerLogger.log('base stack is now ready');
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
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 * as core from '@actions/core';
|
||||||
import CloudRunner from '../../cloud-runner';
|
import CloudRunner from '../../cloud-runner';
|
||||||
|
|
||||||
export class AWSError {
|
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: ');
|
CloudRunnerLogger.log('aws error: ');
|
||||||
core.error(JSON.stringify(error, undefined, 4));
|
core.error(JSON.stringify(error, undefined, 4));
|
||||||
if (CloudRunner.buildParameters.cloudRunnerDebug) {
|
if (CloudRunner.buildParameters.cloudRunnerDebug) {
|
||||||
CloudRunnerLogger.log('Getting events and resources for task stack');
|
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));
|
CloudRunnerLogger.log(JSON.stringify(events, undefined, 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
||||||
import { AWSCloudFormationTemplates } from './aws-cloud-formation-templates';
|
import { AWSCloudFormationTemplates } from './aws-cloud-formation-templates';
|
||||||
@ -16,7 +24,7 @@ export class AWSJobStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async setupCloudFormations(
|
public async setupCloudFormations(
|
||||||
CF: SDK.CloudFormation,
|
CF: CloudFormation,
|
||||||
buildGuid: string,
|
buildGuid: string,
|
||||||
image: string,
|
image: string,
|
||||||
entrypoint: string[],
|
entrypoint: string[],
|
||||||
@ -119,7 +127,7 @@ export class AWSJobStack {
|
|||||||
let previousStackExists = true;
|
let previousStackExists = true;
|
||||||
while (previousStackExists) {
|
while (previousStackExists) {
|
||||||
previousStackExists = false;
|
previousStackExists = false;
|
||||||
const stacks = await CF.listStacks().promise();
|
const stacks = await CF.send(new ListStacksCommand({}));
|
||||||
if (!stacks.StackSummaries) {
|
if (!stacks.StackSummaries) {
|
||||||
throw new Error('Faild to get stacks');
|
throw new Error('Faild to get stacks');
|
||||||
}
|
}
|
||||||
@ -132,7 +140,7 @@ export class AWSJobStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const createStackInput: SDK.CloudFormation.CreateStackInput = {
|
const createStackInput: CreateStackCommandInput = {
|
||||||
StackName: taskDefStackName,
|
StackName: taskDefStackName,
|
||||||
TemplateBody: taskDefCloudFormation,
|
TemplateBody: taskDefCloudFormation,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
@ -140,9 +148,15 @@ export class AWSJobStack {
|
|||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
CloudRunnerLogger.log(`Creating job aws formation ${taskDefStackName}`);
|
CloudRunnerLogger.log(`Creating job aws formation ${taskDefStackName}`);
|
||||||
await CF.createStack(createStackInput).promise();
|
await CF.send(new CreateStackCommand(createStackInput));
|
||||||
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
|
await waitUntilStackCreateComplete(
|
||||||
const describeStack = await CF.describeStacks({ StackName: taskDefStackName }).promise();
|
{
|
||||||
|
client: CF,
|
||||||
|
maxWaitTime: 200,
|
||||||
|
},
|
||||||
|
{ StackName: taskDefStackName },
|
||||||
|
);
|
||||||
|
const describeStack = await CF.send(new DescribeStacksCommand({ StackName: taskDefStackName }));
|
||||||
for (const parameter of parameters) {
|
for (const parameter of parameters) {
|
||||||
if (!describeStack.Stacks?.[0].Parameters?.some((x) => x.ParameterKey === parameter.ParameterKey)) {
|
if (!describeStack.Stacks?.[0].Parameters?.some((x) => x.ParameterKey === parameter.ParameterKey)) {
|
||||||
throw new Error(`Parameter ${parameter.ParameterKey} not found in stack`);
|
throw new Error(`Parameter ${parameter.ParameterKey} not found in stack`);
|
||||||
@ -153,7 +167,7 @@ export class AWSJobStack {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createCleanupStackInput: SDK.CloudFormation.CreateStackInput = {
|
const createCleanupStackInput: CreateStackCommandInput = {
|
||||||
StackName: `${taskDefStackName}-cleanup`,
|
StackName: `${taskDefStackName}-cleanup`,
|
||||||
TemplateBody: CleanupCronFormation.formation,
|
TemplateBody: CleanupCronFormation.formation,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
@ -183,7 +197,7 @@ export class AWSJobStack {
|
|||||||
if (CloudRunnerOptions.useCleanupCron) {
|
if (CloudRunnerOptions.useCleanupCron) {
|
||||||
try {
|
try {
|
||||||
CloudRunnerLogger.log(`Creating job cleanup formation`);
|
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();
|
// await CF.waitFor('stackCreateComplete', { StackName: createCleanupStackInput.StackName }).promise();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -193,12 +207,15 @@ export class AWSJobStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const taskDefResources = (
|
const taskDefResources = (
|
||||||
await CF.describeStackResources({
|
await CF.send(
|
||||||
StackName: taskDefStackName,
|
new DescribeStackResourcesCommand({
|
||||||
}).promise()
|
StackName: taskDefStackName,
|
||||||
|
}),
|
||||||
|
)
|
||||||
).StackResources;
|
).StackResources;
|
||||||
|
|
||||||
const baseResources = (await CF.describeStackResources({ StackName: this.baseStackName }).promise()).StackResources;
|
const baseResources = (await CF.send(new DescribeStackResourcesCommand({ StackName: this.baseStackName })))
|
||||||
|
.StackResources;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
taskDefStackName,
|
taskDefStackName,
|
||||||
|
@ -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 CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
||||||
@ -12,8 +27,8 @@ import CloudRunnerOptions from '../../options/cloud-runner-options';
|
|||||||
import GitHub from '../../../github';
|
import GitHub from '../../../github';
|
||||||
|
|
||||||
class AWSTaskRunner {
|
class AWSTaskRunner {
|
||||||
public static ECS: AWS.ECS;
|
public static ECS: ECS;
|
||||||
public static Kinesis: AWS.Kinesis;
|
public static Kinesis: Kinesis;
|
||||||
private static readonly encodedUnderscore = `$252F`;
|
private static readonly encodedUnderscore = `$252F`;
|
||||||
static async runTask(
|
static async runTask(
|
||||||
taskDef: CloudRunnerAWSTaskDef,
|
taskDef: CloudRunnerAWSTaskDef,
|
||||||
@ -60,7 +75,7 @@ class AWSTaskRunner {
|
|||||||
throw new Error(`Container Overrides length must be at most 8192`);
|
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 || '';
|
const taskArn = task.tasks?.[0].taskArn || '';
|
||||||
CloudRunnerLogger.log('Cloud runner job is starting');
|
CloudRunnerLogger.log('Cloud runner job is starting');
|
||||||
await AWSTaskRunner.waitUntilTaskRunning(taskArn, cluster);
|
await AWSTaskRunner.waitUntilTaskRunning(taskArn, cluster);
|
||||||
@ -108,7 +123,13 @@ class AWSTaskRunner {
|
|||||||
|
|
||||||
private static async waitUntilTaskRunning(taskArn: string, cluster: string) {
|
private static async waitUntilTaskRunning(taskArn: string, cluster: string) {
|
||||||
try {
|
try {
|
||||||
await AWSTaskRunner.ECS.waitFor('tasksRunning', { tasks: [taskArn], cluster }).promise();
|
await waitUntilTasksRunning(
|
||||||
|
{
|
||||||
|
client: AWSTaskRunner.ECS,
|
||||||
|
maxWaitTime: 120,
|
||||||
|
},
|
||||||
|
{ tasks: [taskArn], cluster },
|
||||||
|
);
|
||||||
} catch (error_) {
|
} catch (error_) {
|
||||||
const error = error_ as Error;
|
const error = error_ as Error;
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
@ -124,10 +145,7 @@ class AWSTaskRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async describeTasks(clusterName: string, taskArn: string) {
|
static async describeTasks(clusterName: string, taskArn: string) {
|
||||||
const tasks = await AWSTaskRunner.ECS.describeTasks({
|
const tasks = await AWSTaskRunner.ECS.send(new DescribeTasksCommand({ cluster: clusterName, tasks: [taskArn] }));
|
||||||
cluster: clusterName,
|
|
||||||
tasks: [taskArn],
|
|
||||||
}).promise();
|
|
||||||
if (tasks.tasks?.[0]) {
|
if (tasks.tasks?.[0]) {
|
||||||
return tasks.tasks?.[0];
|
return tasks.tasks?.[0];
|
||||||
} else {
|
} else {
|
||||||
@ -169,9 +187,7 @@ class AWSTaskRunner {
|
|||||||
output: string,
|
output: string,
|
||||||
shouldCleanup: boolean,
|
shouldCleanup: boolean,
|
||||||
) {
|
) {
|
||||||
const records = await AWSTaskRunner.Kinesis.getRecords({
|
const records = await AWSTaskRunner.Kinesis.send(new GetRecordsCommand({ ShardIterator: iterator }));
|
||||||
ShardIterator: iterator,
|
|
||||||
}).promise();
|
|
||||||
iterator = records.NextShardIterator || '';
|
iterator = records.NextShardIterator || '';
|
||||||
({ shouldReadLogs, output, shouldCleanup } = AWSTaskRunner.logRecords(
|
({ shouldReadLogs, output, shouldCleanup } = AWSTaskRunner.logRecords(
|
||||||
records,
|
records,
|
||||||
@ -184,7 +200,7 @@ class AWSTaskRunner {
|
|||||||
return { iterator, shouldReadLogs, output, shouldCleanup };
|
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') {
|
if (taskData?.lastStatus === 'UNKNOWN') {
|
||||||
CloudRunnerLogger.log('## Cloud runner job unknwon');
|
CloudRunnerLogger.log('## Cloud runner job unknwon');
|
||||||
}
|
}
|
||||||
@ -204,15 +220,17 @@ class AWSTaskRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static logRecords(
|
private static logRecords(
|
||||||
records: AWS.Kinesis.GetRecordsOutput,
|
records: GetRecordsCommandOutput,
|
||||||
iterator: string,
|
iterator: string,
|
||||||
shouldReadLogs: boolean,
|
shouldReadLogs: boolean,
|
||||||
output: string,
|
output: string,
|
||||||
shouldCleanup: boolean,
|
shouldCleanup: boolean,
|
||||||
) {
|
) {
|
||||||
if (records.Records.length > 0 && iterator) {
|
if ((records.Records ?? []).length > 0 && iterator) {
|
||||||
for (const record of records.Records) {
|
for (const record of records.Records ?? []) {
|
||||||
const json = JSON.parse(zlib.gunzipSync(Buffer.from(record.Data as string, 'base64')).toString('utf8'));
|
const json = JSON.parse(
|
||||||
|
zlib.gunzipSync(Buffer.from(record.Data as unknown as string, 'base64')).toString('utf8'),
|
||||||
|
);
|
||||||
if (json.messageType === 'DATA_MESSAGE') {
|
if (json.messageType === 'DATA_MESSAGE') {
|
||||||
for (const logEvent of json.logEvents) {
|
for (const logEvent of json.logEvents) {
|
||||||
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
||||||
@ -230,19 +248,19 @@ class AWSTaskRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static async getLogStream(kinesisStreamName: string) {
|
private static async getLogStream(kinesisStreamName: string) {
|
||||||
return await AWSTaskRunner.Kinesis.describeStream({
|
return await AWSTaskRunner.Kinesis.send(new DescribeStreamCommand({ StreamName: kinesisStreamName }));
|
||||||
StreamName: kinesisStreamName,
|
|
||||||
}).promise();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async getLogIterator(stream: AWS.Kinesis.DescribeStreamOutput) {
|
private static async getLogIterator(stream: DescribeStreamCommandOutput) {
|
||||||
return (
|
return (
|
||||||
(
|
(
|
||||||
await AWSTaskRunner.Kinesis.getShardIterator({
|
await AWSTaskRunner.Kinesis.send(
|
||||||
ShardIteratorType: 'TRIM_HORIZON',
|
new GetShardIteratorCommand({
|
||||||
StreamName: stream.StreamDescription.StreamName,
|
ShardIteratorType: 'TRIM_HORIZON',
|
||||||
ShardId: stream.StreamDescription.Shards[0].ShardId,
|
StreamName: stream.StreamDescription?.StreamName ?? '',
|
||||||
}).promise()
|
ShardId: stream.StreamDescription?.Shards?.[0]?.ShardId || '',
|
||||||
|
}),
|
||||||
|
)
|
||||||
).ShardIterator || ''
|
).ShardIterator || ''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import * as AWS from 'aws-sdk';
|
import { StackResource } from '@aws-sdk/client-cloudformation';
|
||||||
|
|
||||||
class CloudRunnerAWSTaskDef {
|
class CloudRunnerAWSTaskDef {
|
||||||
public taskDefStackName!: string;
|
public taskDefStackName!: string;
|
||||||
public taskDefCloudFormation!: string;
|
public taskDefCloudFormation!: string;
|
||||||
public taskDefResources: AWS.CloudFormation.StackResources | undefined;
|
public taskDefResources: StackResource[] | undefined;
|
||||||
public baseResources: AWS.CloudFormation.StackResources | undefined;
|
public baseResources: StackResource[] | undefined;
|
||||||
}
|
}
|
||||||
export default CloudRunnerAWSTaskDef;
|
export default CloudRunnerAWSTaskDef;
|
||||||
|
@ -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 CloudRunnerSecret from '../../options/cloud-runner-secret';
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
||||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
||||||
@ -75,7 +77,7 @@ class AWSBuildEnvironment implements ProviderInterface {
|
|||||||
defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[],
|
defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[],
|
||||||
) {
|
) {
|
||||||
process.env.AWS_REGION = Input.region;
|
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);
|
await new AwsBaseStack(this.baseStackName).setupBaseStack(CF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,10 +91,10 @@ class AWSBuildEnvironment implements ProviderInterface {
|
|||||||
secrets: CloudRunnerSecret[],
|
secrets: CloudRunnerSecret[],
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const ECS = new SDK.ECS();
|
const ECS = new ECSClient({ region: Input.region });
|
||||||
const CF = new SDK.CloudFormation();
|
const CF = new CloudFormation({ region: Input.region });
|
||||||
AwsTaskRunner.ECS = ECS;
|
AwsTaskRunner.ECS = ECS;
|
||||||
AwsTaskRunner.Kinesis = new SDK.Kinesis();
|
AwsTaskRunner.Kinesis = new Kinesis({ region: Input.region });
|
||||||
CloudRunnerLogger.log(`AWS Region: ${CF.config.region}`);
|
CloudRunnerLogger.log(`AWS Region: ${CF.config.region}`);
|
||||||
const entrypoint = ['/bin/sh'];
|
const entrypoint = ['/bin/sh'];
|
||||||
const startTimeMs = Date.now();
|
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');
|
CloudRunnerLogger.log('Cleanup starting');
|
||||||
await CF.deleteStack({
|
await CF.send(new DeleteStackCommand({ StackName: taskDef.taskDefStackName }));
|
||||||
StackName: taskDef.taskDefStackName,
|
|
||||||
}).promise();
|
|
||||||
if (CloudRunnerOptions.useCleanupCron) {
|
if (CloudRunnerOptions.useCleanupCron) {
|
||||||
await CF.deleteStack({
|
await CF.send(new DeleteStackCommand({ StackName: `${taskDef.taskDefStackName}-cleanup` }));
|
||||||
StackName: `${taskDef.taskDefStackName}-cleanup`,
|
|
||||||
}).promise();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await CF.waitFor('stackDeleteComplete', {
|
await waitUntilStackDeleteComplete(
|
||||||
StackName: taskDef.taskDefStackName,
|
{
|
||||||
}).promise();
|
client: CF,
|
||||||
await CF.waitFor('stackDeleteComplete', {
|
maxWaitTime: 200,
|
||||||
StackName: `${taskDef.taskDefStackName}-cleanup`,
|
},
|
||||||
}).promise();
|
{
|
||||||
|
StackName: taskDef.taskDefStackName,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await waitUntilStackDeleteComplete(
|
||||||
|
{
|
||||||
|
client: CF,
|
||||||
|
maxWaitTime: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StackName: `${taskDef.taskDefStackName}-cleanup`,
|
||||||
|
},
|
||||||
|
);
|
||||||
CloudRunnerLogger.log(`Deleted Stack: ${taskDef.taskDefStackName}`);
|
CloudRunnerLogger.log(`Deleted Stack: ${taskDef.taskDefStackName}`);
|
||||||
CloudRunnerLogger.log('Cleanup complete');
|
CloudRunnerLogger.log('Cleanup complete');
|
||||||
}
|
}
|
||||||
|
@ -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 || '' }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,37 +132,48 @@ 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;
|
try {
|
||||||
const stackInfo = (await CF.describeStackResources({ StackName: job }).promise()) || undefined;
|
const stack =
|
||||||
const stackInfo2 = (await CF.describeStacks({ StackName: job }).promise()) || undefined;
|
(await CF.send(new ListStacksCommand({}))).StackSummaries?.find((_x) => _x.StackName === job) || undefined;
|
||||||
if (stack === undefined) {
|
const stackInfo = (await CF.send(new DescribeStackResourcesCommand({ StackName: job }))) || undefined;
|
||||||
throw new Error('stack not defined');
|
const stackInfo2 = (await CF.send(new DescribeStacksCommand({ StackName: job }))) || undefined;
|
||||||
}
|
if (stack === undefined) {
|
||||||
const ageDate: Date = new Date(Date.now() - stack.CreationTime.getTime());
|
throw new Error('stack not defined');
|
||||||
const message = `
|
}
|
||||||
|
if (!stack.CreationTime) {
|
||||||
|
CloudRunnerLogger.log(`${stack.StackName} due to undefined CreationTime`);
|
||||||
|
}
|
||||||
|
const ageDate: Date = new Date(Date.now() - (stack.CreationTime?.getTime() ?? 0));
|
||||||
|
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()}
|
||||||
${JSON.stringify(stack, undefined, 4)}
|
${JSON.stringify(stack, undefined, 4)}
|
||||||
${JSON.stringify(stackInfo, undefined, 4)}
|
${JSON.stringify(stackInfo, undefined, 4)}
|
||||||
${JSON.stringify(stackInfo2, undefined, 4)}
|
${JSON.stringify(stackInfo2, undefined, 4)}
|
||||||
`;
|
`;
|
||||||
CloudRunnerLogger.log(message);
|
CloudRunnerLogger.log(message);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
} catch (error) {
|
||||||
|
CloudRunnerLogger.error(
|
||||||
|
`Failed to describe job ${job}: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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 +197,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 || [];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user