Ctrl K
ComunidadGuías…

src/providers/ami-root-device.lambda.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { DescribeImagesCommand, DescribeLaunchTemplateVersionsCommand, EC2Client } from '@aws-sdk/client-ec2';
import { GetImageCommand, ImagebuilderClient } from '@aws-sdk/client-imagebuilder';
import { GetParameterCommand, SSMClient } from '@aws-sdk/client-ssm';
import * as AWSLambda from 'aws-lambda';
import { customResourceRespond } from '../lambda-helpers';

const ssm = new SSMClient();
const ec2 = new EC2Client();
const ib = new ImagebuilderClient();


async function handleAmi(event: AWSLambda.CloudFormationCustomResourceEvent, ami: string) {
  const imageDescs = (await ec2.send(new DescribeImagesCommand({ ImageIds: [ami] })));
  if (imageDescs.Images?.length !== 1) {
    await customResourceRespond(event, 'FAILED', `${ami} doesn't exist`, 'ERROR', {});
    return;
  }

  const rootDevice = imageDescs.Images[0].RootDeviceName;
  if (!rootDevice) {
    await customResourceRespond(event, 'FAILED', `${ami} has no root device`, 'ERROR', {});
    return;
  }

  console.log({
    notice: 'Resolved AMI root device',
    ami,
    rootDevice,
  });

  await customResourceRespond(event, 'SUCCESS', 'OK', rootDevice, {});
  return;
}


export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent, context: AWSLambda.Context) {
  try {
    console.log({
      notice: 'CloudFormation custom resource request',
      ...event,
      ResponseURL: '...',
    });

    const ami = event.ResourceProperties.Ami as string;

    switch (event.RequestType) {
      case 'Create':
      case 'Update':
        if (ami.startsWith('ami-')) {
          console.log({
            notice: 'Checking AMI',
            ami,
          });

          await handleAmi(event, ami);
          break;
        }

        if (ami.startsWith('resolve:ssm:')) {
          const ssmParam = ami.substring('resolve:ssm:'.length);
          console.log({
            notice: 'Checking SSM',
            ssmParam,
          });

          const ssmValue = (await ssm.send(new GetParameterCommand({ Name: ssmParam }))).Parameter?.Value;
          if (!ssmValue) {
            await customResourceRespond(event, 'FAILED', `${ami} has no value`, 'ERROR', {});
            break;
          }

          await handleAmi(event, ssmValue);
          break;
        }

        if (ami.startsWith('ssm:')) {
          const ssmParam = ami.substring('ssm:'.length);
          console.log({
            notice: 'Checking SSM',
            ssmParam,
          });

          const ssmValue = (await ssm.send(new GetParameterCommand({ Name: ssmParam }))).Parameter?.Value;
          if (!ssmValue) {
            await customResourceRespond(event, 'FAILED', `${ami} has no value`, 'ERROR', {});
            break;
          }

          await handleAmi(event, ssmValue);
          break;
        }

        if (ami.startsWith('lt-')) {
          console.log({
            notice: 'Checking Launch Template',
            launchTemplateId: ami,
          });

          const lts = await ec2.send(new DescribeLaunchTemplateVersionsCommand({ LaunchTemplateId: ami, Versions: ['$Latest'] }));
          if (lts.LaunchTemplateVersions?.length !== 1) {
            await customResourceRespond(event, 'FAILED', `${ami} doesn't exist`, 'ERROR', {});
            break;
          }

          if (!lts.LaunchTemplateVersions[0].LaunchTemplateData?.ImageId) {
            await customResourceRespond(event, 'FAILED', `${ami} doesn't have an AMI`, 'ERROR', {});
            break;
          }

          await handleAmi(event, lts.LaunchTemplateVersions[0].LaunchTemplateData.ImageId);
          break;
        }

        if (ami.match('^arn:aws[^:]*:imagebuilder:[^:]+:[^:]+:image/.*$')) {
          console.log({
            notice: 'Checking Image Builder',
            imageBuildVersionArn: ami,
          });

          const img = await ib.send(new GetImageCommand({ imageBuildVersionArn: ami }));
          const actualAmi = img.image?.outputResources?.amis?.[0]?.image;
          if (!actualAmi) {
            await customResourceRespond(event, 'FAILED', `${ami} doesn't have an AMI`, 'ERROR', {});
            break;
          }

          await handleAmi(event, actualAmi);
          break;
        }

        await customResourceRespond(event, 'FAILED', `Unknown type of AMI ${ami}`, 'ERROR', {});
        break;
      case 'Delete':
        console.log({
          notice: 'Nothing to delete',
          ami,
        });
        await customResourceRespond(event, 'SUCCESS', 'OK', event.PhysicalResourceId, {});
        break;
    }
  } catch (e) {
    console.error({
      notice: 'Failed to resolve AMI root device',
      error: e,
    });
    await customResourceRespond(event, 'FAILED', (e as Error).message || 'Internal Error', context.logStreamName, {});
  }
}