@cloudsnorkel/cdk-github-runners
Version:
CDK construct to create GitHub Actions self-hosted runners. Creates ephemeral runners on demand. Easy to deploy and highly customizable.
209 lines (205 loc) • 6.26 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/image-builders/aws-image-builder/delete-resources.lambda.ts
var delete_resources_lambda_exports = {};
__export(delete_resources_lambda_exports, {
handler: () => handler
});
module.exports = __toCommonJS(delete_resources_lambda_exports);
var import_client_ec2 = require("@aws-sdk/client-ec2");
var import_client_ecr = require("@aws-sdk/client-ecr");
var import_client_imagebuilder = require("@aws-sdk/client-imagebuilder");
// src/lambda-helpers.ts
var import_client_secrets_manager = require("@aws-sdk/client-secrets-manager");
var sm = new import_client_secrets_manager.SecretsManagerClient();
async function customResourceRespond(event, responseStatus, reason, physicalResourceId, data) {
const responseBody = JSON.stringify({
Status: responseStatus,
Reason: reason,
PhysicalResourceId: physicalResourceId,
StackId: event.StackId,
RequestId: event.RequestId,
LogicalResourceId: event.LogicalResourceId,
NoEcho: false,
Data: data
});
console.log({
notice: "Responding to CloudFormation custom resource",
status: responseStatus,
reason,
physicalResourceId,
responseBody
});
const parsedUrl = require("url").parse(event.ResponseURL);
const requestOptions = {
hostname: parsedUrl.hostname,
path: parsedUrl.path,
method: "PUT",
headers: {
"content-type": "",
"content-length": responseBody.length
}
};
return new Promise((resolve, reject) => {
try {
const request = require("https").request(requestOptions, resolve);
request.on("error", reject);
request.write(responseBody);
request.end();
} catch (e) {
reject(e);
}
});
}
// src/image-builders/aws-image-builder/delete-resources.lambda.ts
var ec2 = new import_client_ec2.EC2Client();
var ecr = new import_client_ecr.ECRClient();
var ib = new import_client_imagebuilder.ImagebuilderClient();
async function deleteResources(props) {
const buildsToDelete = [];
const amisToDelete = [];
const dockerImagesToDelete = [];
let result = {};
do {
result = await ib.send(new import_client_imagebuilder.ListImageBuildVersionsCommand({
imageVersionArn: props.ImageVersionArn,
nextToken: result.nextToken
}));
if (result.imageSummaryList) {
for (const image of result.imageSummaryList) {
if (image.arn) {
buildsToDelete.push(image.arn);
}
for (const output of image.outputResources?.amis ?? []) {
if (output.image) {
amisToDelete.push(output.image);
}
}
for (const output of image.outputResources?.containers ?? []) {
if (output.imageUris) {
dockerImagesToDelete.push(...output.imageUris);
}
}
}
}
} while (result.nextToken);
for (const imageId of amisToDelete) {
try {
console.log({
notice: "Deleting AMI",
image: imageId
});
const imageDesc = await ec2.send(new import_client_ec2.DescribeImagesCommand({
Owners: ["self"],
ImageIds: [imageId]
}));
if (imageDesc.Images?.length !== 1) {
console.warn({
notice: "Unable to find AMI",
image: imageId
});
continue;
}
await ec2.send(new import_client_ec2.DeregisterImageCommand({
ImageId: imageId,
DeleteAssociatedSnapshots: true
}));
} catch (e) {
console.warn({
notice: "Failed to delete AMI",
image: imageId,
error: e
});
}
}
for (const image of dockerImagesToDelete) {
try {
console.log({
notice: "Deleting Docker Image",
image
});
const parts = image.split("/")[1].split(":");
const repo = parts[0];
const tag = parts[1];
await ecr.send(new import_client_ecr.BatchDeleteImageCommand({
repositoryName: repo,
imageIds: [
{
imageTag: tag
}
]
}));
} catch (e) {
console.warn({
notice: "Failed to delete docker image",
image,
error: e
});
}
}
for (const build of buildsToDelete) {
try {
console.log({
notice: "Deleting Image Build",
build
});
await ib.send(new import_client_imagebuilder.DeleteImageCommand({
imageBuildVersionArn: build
}));
} catch (e) {
console.warn({
notice: "Failed to delete image version build",
build,
error: e
});
}
}
}
async function handler(event, _context) {
try {
console.log({
notice: "CloudFormation custom resource request",
...event,
ResponseURL: "..."
});
const props = event.ResourceProperties;
switch (event.RequestType) {
case "Create":
case "Update":
await customResourceRespond(event, "SUCCESS", "OK", props.ImageVersionArn, {});
break;
case "Delete":
if (event.PhysicalResourceId != "FAIL") {
await deleteResources(props);
}
await customResourceRespond(event, "SUCCESS", "OK", event.PhysicalResourceId, {});
break;
}
} catch (e) {
console.error({
notice: "Failed to delete Image Builder resources",
error: `${e}`
});
await customResourceRespond(event, "FAILED", e.message || "Internal Error", "FAIL", {});
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
handler
});