UNPKG

@lumigo/cdk-constructs-v2

Version:

Home to the Lumigo constructs for the AWS Cloud Development Kit (AWS CDK)

807 lines 136 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.Lumigo = exports.DEFAULT_LUMIGO_INJECTOR_IMAGE_NAME = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const path_1 = require("path"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const aws_ecs_1 = require("aws-cdk-lib/aws-ecs"); const aws_ecs_patterns_1 = require("aws-cdk-lib/aws-ecs-patterns"); const aws_lambda_1 = require("aws-cdk-lib/aws-lambda"); const aws_lambda_nodejs_1 = require("aws-cdk-lib/aws-lambda-nodejs"); const aws_secretsmanager_1 = require("aws-cdk-lib/aws-secretsmanager"); const aws_ssm_1 = require("aws-cdk-lib/aws-ssm"); /* eslint-disable */ const { name, version } = require(path_1.join(path_1.dirname(__dirname), 'package.json')); /* eslint-enable */ const lambdaLayersNodejs = require("./lambda_layers_nodejs.json"); const lambdaLayersPython = require("./lambda_layers_python.json"); const lumigo_autotrace_image_json_1 = require("./lumigo_autotrace_image.json"); exports.DEFAULT_LUMIGO_INJECTOR_IMAGE_NAME = lumigo_autotrace_image_json_1.image; // Layer type to layer name var LambdaLayerType; (function (LambdaLayerType) { LambdaLayerType["NODE"] = "lumigo-node-tracer"; LambdaLayerType["PYTHON"] = "lumigo-python-tracer"; })(LambdaLayerType || (LambdaLayerType = {})); const AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_NAME = 'AWS_LAMBDA_EXEC_WRAPPER'; const AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_VALUE = '/opt/lumigo_wrapper'; const LUMIGO_ORIGINAL_HANDLER_ENV_VAR_NAME = 'LUMIGO_ORIGINAL_HANDLER'; const LUMIGO_PROPAGATE_W3C_ENV_VAR_NAME = 'LUMIGO_PROPAGATE_W3C'; const LUMIGO_TRACER_TOKEN_ENV_VAR_NAME = 'LUMIGO_TRACER_TOKEN'; const LUMIGO_AUTOTRACE_TAG_NAME = 'lumigo:auto-trace'; const LUMIGO_AUTOTRACE_TAG_VALUE = `${name}@${version}`; const LUMIGO_TAG_TAG_NAME = 'LUMIGO_TAG'; const LUMIGO_LAMBDA_PYTHON_HANDLER = 'lumigo_tracer._handler'; const LUMIGO_INJECTOR_CONTAINER_NAME = 'lumigo-injector'; const LUMIGO_INJECTOR_VOLUME_NAME = 'lumigo-injector'; const LUMIGO_INJECTOR_VOLUME_MOUNT_POINT = '/opt/lumigo'; const LUMIGO_INJECTOR_ENV_VAR_NAME = 'LD_PRELOAD'; const LUMIGO_INJECTOR_ENV_VAR_VALUE = `${LUMIGO_INJECTOR_VOLUME_MOUNT_POINT}/injector/lumigo_injector.so`; const DEFAULT_LUMIGO_TRACE_PROPS = { traceLambda: true, traceEcs: true, lambdaEnableW3CTraceContext: true, }; const DEFAULT_TRACE_ECS_TASK_DEFINITION_PROPS = { applyAutoTraceTag: true, lumigoAutoTraceImage: exports.DEFAULT_LUMIGO_INJECTOR_IMAGE_NAME, }; const isTrueOrUndefined = (value) => value === true || value === undefined; /** * The `Lumigo` class is the entry point for instrumenting workloads deployed via CDK constructs with Lumigo. * You usually would need only one instance of `Lumigo` per CDK application. */ class Lumigo { constructor(props) { this.ecsSecrets = new Map(); this.props = props; } /** * @private This is an internal API; it is not meant to be invoked directly by end-user code. */ visit(construct) { if (construct instanceof aws_lambda_1.Function) { try { this.traceLambda(construct); } catch (e) { if (e instanceof UnsupportedLambdaRuntimeError) { this.info(construct, `The '${e.unsupportedRuntime}' cannot be automatically traced by Lumigo.`); } else { throw e; } } } } info(node, message) { aws_cdk_lib_1.Annotations.of(node).addInfo(message); } error(node, message) { aws_cdk_lib_1.Annotations.of(node).addError(message); } warning(node, message) { aws_cdk_lib_1.Annotations.of(node).addWarning(message); } traceEverything(root, props = DEFAULT_LUMIGO_TRACE_PROPS) { // For the people not using TypeScript, we need to perform some basic type validation assertExpectedConstructType('traceEverything', 'App or Stack', root, (c) => c instanceof aws_cdk_lib_1.App || c instanceof aws_cdk_lib_1.Stack); aws_cdk_lib_1.Aspects.of(root).add(this.asAspect(props)); } asAspect(props = DEFAULT_LUMIGO_TRACE_PROPS) { const lumigo = this; /* * Tags are implemented as aspects in CDK, and unfortunately aspects like * this cannot apply other aspects. */ const applyAutoTraceTag = false; return { visit: function (construct) { function applyAwsTagThroughTagManager(key, value) { try { /** * To overcome the limitation that (1) tags are implemented as aspects, (2) that * we are already inside an aspect and (3) an aspect cannot add aspects, we need * to access the TagManager of the function and add the tag manually. */ const scope = construct.node?.scope; if (!!scope) { /* eslint-disable */ const tags = scope['tags']; /* eslint-enable */ if (!!tags && tags instanceof aws_cdk_lib_1.TagManager) { tags.setTag(key, value, 100, true); } } } catch (e) { lumigo.warning(construct, `Cannot set the '${key}' tag with value '${value}'.`); } } if (construct instanceof aws_lambda_1.Function && props.traceLambda !== false) { try { const layerType = lumigo.getLayerType(construct); if (!layerType) { lumigo.warning(construct, 'The runtime used by this function cannot be auto-traced by Lumigo.'); return; } var layerVersion; if (layerType === LambdaLayerType.NODE) { layerVersion = props.lambdaNodejsLayerVersion; } else if (layerType === LambdaLayerType.PYTHON) { layerVersion = props.lambdaPythonLayerVersion; } lumigo.traceLambda(construct, { layerVersion, enableW3CTraceContext: isTrueOrUndefined(props.lambdaEnableW3CTraceContext), applyAutoTraceTag, lumigoTag: props.lumigoTag, }); if (props.lumigoTag) { applyAwsTagThroughTagManager(LUMIGO_TAG_TAG_NAME, props.lumigoTag); } if (props.applyAutoTraceTag) { applyAwsTagThroughTagManager(LUMIGO_AUTOTRACE_TAG_NAME, LUMIGO_AUTOTRACE_TAG_VALUE); } } catch (e) { if (e instanceof UnsupportedLambdaRuntimeError) { lumigo.info(construct, `The '${e.unsupportedRuntime}' cannot be automatically traced by Lumigo.`); } else { throw e; } } } else if (props.traceEcs !== false) { if (isSupportedEcsServiceConstruct(construct)) { lumigo.traceEcsService(construct, { applyAutoTraceTag, lumigoAutoTraceImage: props.lumigoAutoTraceImage, }); if (props.lumigoTag) { applyAwsTagThroughTagManager(LUMIGO_TAG_TAG_NAME, props.lumigoTag); } if (props.applyAutoTraceTag) { applyAwsTagThroughTagManager(LUMIGO_AUTOTRACE_TAG_NAME, LUMIGO_AUTOTRACE_TAG_VALUE); } } else if (isSupportedEcsScheduledTaskConstruct(construct)) { lumigo.traceEcsScheduledTask(construct, { applyAutoTraceTag, lumigoAutoTraceImage: props.lumigoAutoTraceImage, }); if (props.lumigoTag) { applyAwsTagThroughTagManager(LUMIGO_TAG_TAG_NAME, props.lumigoTag); } if (props.applyAutoTraceTag) { applyAwsTagThroughTagManager(LUMIGO_AUTOTRACE_TAG_NAME, LUMIGO_AUTOTRACE_TAG_VALUE); } } else if (isSupportedEcsTaskDefinitionConstruct(construct)) { lumigo.traceEcsTaskDefinition(construct, { applyAutoTraceTag, lumigoAutoTraceImage: props.lumigoAutoTraceImage, }); if (props.lumigoTag) { applyAwsTagThroughTagManager(LUMIGO_TAG_TAG_NAME, props.lumigoTag); } if (props.applyAutoTraceTag) { applyAwsTagThroughTagManager(LUMIGO_AUTOTRACE_TAG_NAME, LUMIGO_AUTOTRACE_TAG_VALUE); } } } }, }; } /** * This method returns a wrapper that can be used in conjunction with the {@link https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs.TaskDefinition.html#addwbrextensionextension|TaskDefinition.addExtension} method. * The effect is the same as using the {@link Lumigo#traceEcsTaskDefinition} method on the `TaskDefinition` on which you would invoke `TaskDefinition.addExtension`. * * @returns A wrapper that invokes {@link Lumigo#traceEcsTaskDefinition} on the task definition to be extended. */ asEcsExtension() { return { extend: this.traceEcsTaskDefinition.bind(this), }; } /** * Apply Lumigo autotracing for Java, Node.js and Python applications deployed through the provided ECS ScheduledTask construct. */ traceEcsScheduledTask(scheduledTask, props = { applyAutoTraceTag: true, }) { // For the people not using TypeScript, we need to perform some basic type validation assertExpectedConstructType('traceEcsScheduledTask', 'ScheduledEc2Task or ScheduledFargateTask', scheduledTask, (c) => isSupportedEcsScheduledTaskConstruct(c)); this.doTraceEcsTaskDefinition(scheduledTask.taskDefinition, { applyAutoTraceTag: false, lumigoAutoTraceImage: props.lumigoAutoTraceImage, }); if (!!props.applyAutoTraceTag) { this.applyAutotraceTag(scheduledTask); } if (!!props.lumigoTag) { this.applyLumigoTag(scheduledTask, props.lumigoTag); } } /** * Apply Lumigo autotracing for Java, Node.js and Python applications deployed through the provided ECS Service construct. */ traceEcsService(service, props = { applyAutoTraceTag: true, }) { // For the people not using TypeScript, we need to perform some basic type validation assertExpectedConstructType('traceEcsService', 'EcsService', service, (c) => isSupportedEcsServiceConstruct(c)); this.doTraceEcsTaskDefinition(service.taskDefinition, { applyAutoTraceTag: false, lumigoAutoTraceImage: props.lumigoAutoTraceImage, }); if (!!props.applyAutoTraceTag) { this.applyAutotraceTag(service); } if (!!props.lumigoTag) { this.applyLumigoTag(service, props.lumigoTag); } } /** * Apply Lumigo autotracing for Java, Node.js and Python applications deployed through the provided `TaskDefinition`. * If the ECS workload does not contain Java, Node.js or Python applications, no distributed-tracing data will be reported to Lumigo. */ traceEcsTaskDefinition(taskDefinition, props = DEFAULT_TRACE_ECS_TASK_DEFINITION_PROPS) { // For the people not using TypeScript, we need to perform some basic type validation assertExpectedConstructType('traceEcsTaskDefinition', 'TaskDefinition', taskDefinition, (c) => isSupportedEcsTaskDefinitionConstruct(c)); this.doTraceEcsTaskDefinition(taskDefinition, props); } lumigoTokenAsEcsSecret(scope) { if (!this.ecsSecrets.has(scope)) { const ref = this.props.lumigoToken.rawValue; if (ref.value.match(/{{resolve:\S+}}/)) { const tokens = ref.value.substring('{{resolve:'.length, ref.value.length - 2).split(':'); switch (tokens[0]) { case aws_cdk_lib_1.CfnDynamicReferenceService.SECRETS_MANAGER: { // Secret Manager: '{{resolve:secretsmanager:<secretName>:SecretString:<fieldName>::}}' const secretName = tokens[1]; const fieldName = (tokens.length > 3) ? tokens[3] : undefined; this.ecsSecrets.set(scope, aws_ecs_1.Secret.fromSecretsManager(aws_secretsmanager_1.Secret.fromSecretNameV2(scope, 'lumigoTokenSMS', secretName), fieldName)); break; } case aws_cdk_lib_1.CfnDynamicReferenceService.SSM_SECURE: { // SSM-secure: '{{resolve:ssm-secure:<parameterName>:<version>}}' const parameterName = tokens[1]; const parameterVersion = (tokens.length > 2) ? Number(tokens[2]) : undefined; this.ecsSecrets.set(scope, aws_ecs_1.Secret.fromSsmParameter(aws_ssm_1.StringParameter.fromSecureStringParameterAttributes(scope, 'lumigoTokenSSM', { parameterName, version: parameterVersion, }))); break; } } } } return this.ecsSecrets.get(scope); } doTraceEcsTaskDefinition(taskDefinition, props = DEFAULT_TRACE_ECS_TASK_DEFINITION_PROPS) { /* * This function must be idempotent, as `Lumigo.traceEverything()` will apply to * both the ECS Service and its ECS TaskDefinition. */ if (!getTaskDefinitionVolumes(taskDefinition).find(volume => volume.name === LUMIGO_INJECTOR_VOLUME_NAME)) { taskDefinition.addVolume({ name: LUMIGO_INJECTOR_VOLUME_NAME, }); } // Add injector container const TARGET_DIRECTORY_PATH = '/target'; const injectorContainer = getTaskDefinitionContainers(taskDefinition) .find(container => container.containerName === LUMIGO_INJECTOR_CONTAINER_NAME) || // We did not find the injector container yet, time to add it taskDefinition.addContainer(LUMIGO_INJECTOR_CONTAINER_NAME, { image: aws_ecs_1.ContainerImage.fromRegistry(props.lumigoAutoTraceImage || exports.DEFAULT_LUMIGO_INJECTOR_IMAGE_NAME), containerName: LUMIGO_INJECTOR_CONTAINER_NAME, environment: { TARGET_DIRECTORY: TARGET_DIRECTORY_PATH, }, essential: false, }); if (!injectorContainer.mountPoints?.find(mountPoint => mountPoint.sourceVolume === LUMIGO_INJECTOR_VOLUME_NAME)) { injectorContainer.addMountPoints({ sourceVolume: LUMIGO_INJECTOR_VOLUME_NAME, containerPath: TARGET_DIRECTORY_PATH, readOnly: false, }); } /* * See if we can construct an ECS secret from the SecretValue */ let tokenSecret; if (this.props.lumigoToken.rawValue instanceof aws_cdk_lib_1.CfnDynamicReference) { tokenSecret = this.lumigoTokenAsEcsSecret(taskDefinition); } // We wait to start any other container until the inject has done its work const otherContainers = getTaskDefinitionContainers(taskDefinition) .filter((it) => it !== injectorContainer); otherContainers.forEach(container => { if (!container.containerDependencies?.find(containerDependency => containerDependency.container === injectorContainer)) { container.addContainerDependencies({ container: injectorContainer, condition: aws_ecs_1.ContainerDependencyCondition.COMPLETE, }); } if (!container.mountPoints?.find(mountPoint => mountPoint.sourceVolume === LUMIGO_INJECTOR_VOLUME_NAME)) { container.addMountPoints({ sourceVolume: LUMIGO_INJECTOR_VOLUME_NAME, containerPath: LUMIGO_INJECTOR_VOLUME_MOUNT_POINT, readOnly: true, }); } // Trigger the injector // The environment is implemented as a dictionary, no need for idempotency checks container.addEnvironment(LUMIGO_INJECTOR_ENV_VAR_NAME, LUMIGO_INJECTOR_ENV_VAR_VALUE); if (tokenSecret) { /* * The implementation of ContainerDefinition.addSecret does not check for the secret being specified multiple times, * so we need to avoid duplication ourselves. */ const secrets = container.secrets; if (!secrets.find((entry) => entry.name === LUMIGO_TRACER_TOKEN_ENV_VAR_NAME)) { container.addSecret(LUMIGO_TRACER_TOKEN_ENV_VAR_NAME, tokenSecret); } } else { // Could not figure out which type of secret value it is, we go for the unwrap container.addEnvironment(LUMIGO_TRACER_TOKEN_ENV_VAR_NAME, this.props.lumigoToken.unsafeUnwrap()); } }); taskDefinition.node.addValidation(new EcsTaskDefinitionLumigoInjectorVolumeValidation(taskDefinition)); taskDefinition.node.addValidation(new EcsTaskDefinitionLumigoInjectorContainerValidation(taskDefinition)); otherContainers.forEach(container => { taskDefinition.node.addValidation(new EcsContainerDefinitionLumigoInjectorVolumeMountPointValidation(container)); taskDefinition.node.addValidation(new EcsContainerDefinitionLumigoInjectorContainerConditionValidation(container, injectorContainer)); taskDefinition.node.addValidation(new EcsContainerDefinitionHasLumigoInjectorEnvVarValidation(container)); if (tokenSecret) { taskDefinition.node.addValidation(new EcsContainerDefinitionHasLumigoTracerTokenSecretValidation(container)); } else { taskDefinition.node.addValidation(new EcsContainerDefinitionHasLumigoTracerTokenEnvVarValidation(container, this.props.lumigoToken.unsafeUnwrap())); } }); if (!!props.applyAutoTraceTag) { this.applyAutotraceTag(taskDefinition); } if (!!props.lumigoTag) { this.applyLumigoTag(taskDefinition, props.lumigoTag); } } /** * Apply Lumigo autotracing for the provided Lambda function if it uses a supported Node.js or Python runtime. * If the runtime used by the provided function is not supported by [Lumigo Lambda Auto-Tracing](https://docs.lumigo.io/docs/auto-instrumentation), * a warning will be added to the CloudFormation template. */ traceLambda(lambda, props = { enableW3CTraceContext: true, applyAutoTraceTag: true, }) { // For the people not using TypeScript, we need to perform some basic type validation assertExpectedConstructType('traceLambda', 'Function', lambda, (c) => c instanceof aws_lambda_1.Function); const layerType = this.getLayerType(lambda); if (!layerType) { this.warning(lambda, 'The runtime used by this function cannot be auto-traced by Lumigo.'); return; } const region = aws_cdk_lib_1.Stack.of(lambda).region; const layerArn = !!props.layerVersion ? `arn:aws:lambda:${region}:114300393969:layer:${layerType}:${props.layerVersion}` : this.getLayerLatestArn(region, layerType); lambda.addLayers(aws_lambda_1.LayerVersion.fromLayerVersionArn(lambda, 'LumigoLayer', layerArn)); lambda.addEnvironment(LUMIGO_TRACER_TOKEN_ENV_VAR_NAME, this.props.lumigoToken.unsafeUnwrap()); lambda.node.addValidation(new HasExactlyOneLumigoLayerValidation(lambda)); lambda.node.addValidation(new HasLumigoTracerEnvVarValidation(lambda)); if (layerType === LambdaLayerType.NODE) { lambda.addEnvironment(AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_NAME, AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_VALUE); lambda.node.addValidation(new HasAwsLambdaExecWrapperEnvVarValidation(lambda)); } else if (layerType == LambdaLayerType.PYTHON) { /* eslint-disable */ /* * The handler is well hidden in the CfnFunction resource :-( */ const nodeAny = lambda.node; const handler = nodeAny?._children['Resource']?.handler; if (!!nodeAny && !!nodeAny._children['Resource']) { nodeAny._children['Resource'].handler = LUMIGO_LAMBDA_PYTHON_HANDLER; } /* eslint-enable */ lambda.addEnvironment(LUMIGO_ORIGINAL_HANDLER_ENV_VAR_NAME, handler); lambda.node.addValidation(new HasAwsLambdaOriginalHandlerEnvVarValidation(lambda)); lambda.node.addValidation(new HasLumigoPythonHandlerInResourceValidation(lambda)); } const enableW3CTraceContext = isTrueOrUndefined(props.enableW3CTraceContext); lambda.addEnvironment(LUMIGO_PROPAGATE_W3C_ENV_VAR_NAME, String(enableW3CTraceContext)); lambda.node.addValidation(new HasLumigoPropagateW3CEnvVarValidation(lambda, enableW3CTraceContext)); if (!!props.applyAutoTraceTag) { this.applyAutotraceTag(lambda); } if (!!props.lumigoTag) { this.applyLumigoTag(lambda, props.lumigoTag); } this.info(lambda, `This function has been modified with Lumigo auto-tracing by the '${LUMIGO_AUTOTRACE_TAG_VALUE}' package.`); } applyAutotraceTag(construct) { aws_cdk_lib_1.Tags.of(construct).add(LUMIGO_AUTOTRACE_TAG_NAME, LUMIGO_AUTOTRACE_TAG_VALUE); } applyLumigoTag(construct, value) { aws_cdk_lib_1.Tags.of(construct).add(LUMIGO_TAG_TAG_NAME, value); } getLayerType(lambda) { switch (lambda.runtime) { case aws_lambda_1.Runtime.NODEJS_10_X: case aws_lambda_1.Runtime.NODEJS_12_X: case aws_lambda_1.Runtime.NODEJS_14_X: case aws_lambda_1.Runtime.NODEJS_16_X: return LambdaLayerType.NODE; case aws_lambda_1.Runtime.PYTHON_3_7: case aws_lambda_1.Runtime.PYTHON_3_8: case aws_lambda_1.Runtime.PYTHON_3_9: return LambdaLayerType.PYTHON; default: if (!lambda.runtime && lambda instanceof aws_lambda_nodejs_1.NodejsFunction) { /* * The NodejsType has the runtime as optional, and then the * function will use the default one. The default runtime type * is set up conservatively in AWS CDK, with older versions, * long supported by Lumigo. So we can rely on the type of * the construct to tell us the layer type. */ return LambdaLayerType.NODE; } /* * Check if it is enumeration entries that do not * exist in the minimum CDK version we support. */ if (lambda.runtime.name.startsWith('nodejs')) { return LambdaLayerType.NODE; } else if (lambda.runtime.name.startsWith('python3.')) { return LambdaLayerType.PYTHON; } } return undefined; } getLayerLatestArn(region, type) { const latestLayerArnByRegion = (type === LambdaLayerType.NODE ? lambdaLayersNodejs : lambdaLayersPython); const latestLayerArn = (new Map(Object.entries(latestLayerArnByRegion))).get(region); if (!latestLayerArn) { throw new UnsupportedLambdaLayerRegion(type, region); } return latestLayerArn; } } exports.Lumigo = Lumigo; _a = JSII_RTTI_SYMBOL_1; Lumigo[_a] = { fqn: "@lumigo/cdk-constructs-v2.Lumigo", version: "0.1.162" }; const isSupportedEcsTaskDefinitionConstruct = (construct) => { return construct instanceof aws_ecs_1.FargateTaskDefinition || construct instanceof aws_ecs_1.Ec2TaskDefinition; }; const isSupportedEcsScheduledTaskConstruct = (construct) => { return construct instanceof aws_ecs_patterns_1.ScheduledEc2Task || construct instanceof aws_ecs_patterns_1.ScheduledFargateTask; }; const isSupportedEcsServiceConstruct = (construct) => { return construct instanceof aws_ecs_1.Ec2Service || construct instanceof aws_ecs_1.FargateService || construct instanceof aws_ecs_patterns_1.ApplicationLoadBalancedEc2Service || construct instanceof aws_ecs_patterns_1.ApplicationLoadBalancedFargateService || construct instanceof aws_ecs_patterns_1.ApplicationMultipleTargetGroupsEc2Service || construct instanceof aws_ecs_patterns_1.ApplicationMultipleTargetGroupsFargateService || construct instanceof aws_ecs_patterns_1.NetworkLoadBalancedEc2Service || construct instanceof aws_ecs_patterns_1.NetworkLoadBalancedFargateService || construct instanceof aws_ecs_patterns_1.NetworkMultipleTargetGroupsEc2Service || construct instanceof aws_ecs_patterns_1.NetworkMultipleTargetGroupsFargateService || construct instanceof aws_ecs_patterns_1.QueueProcessingEc2Service || construct instanceof aws_ecs_patterns_1.QueueProcessingFargateService; }; function assertExpectedConstructType(invokedMethod, expectedType, construct, test) { if (!test(construct)) { let message = `Lumigo.${invokedMethod} needs a ${expectedType} as input`; const additionalHint = getTypeErrorHint(construct); if (additionalHint) { message = `${message}; ${additionalHint}`; } throw new Error(message); } } function getTypeErrorHint(construct) { if (construct instanceof aws_cdk_lib_1.App) { return 'are you maybe looking for Lumigo.traceEverything instead?'; } else if (construct instanceof aws_lambda_1.Function) { return 'are you maybe looking for Lumigo.traceLambda instead?'; } else if (construct instanceof aws_ecs_1.TaskDefinition) { return 'are you maybe looking for Lumigo.traceEcsTaskDefinition instead?'; } else if (isSupportedEcsScheduledTaskConstruct(construct)) { return 'are you maybe looking for Lumigo.traceEcsScheduledTask instead?'; } else if (isSupportedEcsServiceConstruct(construct)) { return 'are you maybe looking for Lumigo.traceEcsService instead?'; } return undefined; } class TaskDefinitionValidation { constructor(taskDefinition) { this.issues = []; this.addIssue = (issue) => this.issues.push(issue); this.taskDefinition = taskDefinition; } validate() { this.validateTaskDefinition(this.taskDefinition); return this.issues; } } class EcsTaskDefinitionLumigoInjectorContainerValidation extends TaskDefinitionValidation { constructor(taskDefinition) { super(taskDefinition); } validateTaskDefinition(taskDefinition) { var lumigoInjectorContainers = getTaskDefinitionContainers(taskDefinition).filter(container => container.containerName == 'lumigo-injector'); switch (lumigoInjectorContainers.length) { case 0: { this.addIssue(`No container called '${LUMIGO_INJECTOR_CONTAINER_NAME}' found; did you modify the task definition after adding Lumigo tracing to it?`); return; } case 1: { // TODO Validate container image break; } default: { this.addIssue(`${lumigoInjectorContainers.length} containers called '${LUMIGO_INJECTOR_CONTAINER_NAME}' found; did you set Lumigo tracing up multiple times for this task definition?`); return; } } } } class EcsTaskDefinitionLumigoInjectorVolumeValidation extends TaskDefinitionValidation { constructor(taskDefinition) { super(taskDefinition); } validateTaskDefinition(taskDefinition) { var lumigoInjectorVolumes = getTaskDefinitionVolumes(taskDefinition)?.filter(volume => volume.name == 'lumigo-injector'); switch (lumigoInjectorVolumes?.length || 0) { case 0: { this.addIssue(`No volume called '${LUMIGO_INJECTOR_VOLUME_NAME}' found; did you modify the task definition after adding Lumigo tracing to it?`); return; } case 1: { break; } default: { this.addIssue(`${lumigoInjectorVolumes.length} volume called '${LUMIGO_INJECTOR_VOLUME_NAME}' found; did you set Lumigo tracing up multiple times for this task definition?`); return; } } const lumigoInjectorVolume = lumigoInjectorVolumes[0]; if (!!lumigoInjectorVolume.dockerVolumeConfiguration) { this.addIssue(`The '${LUMIGO_INJECTOR_VOLUME_NAME}' volume has 'dockerVolumeConfiguration's attached to it; did you modify the task definition after adding Lumigo tracing to it?`); } if (!!lumigoInjectorVolume.efsVolumeConfiguration) { this.addIssue(`The '${LUMIGO_INJECTOR_VOLUME_NAME}' volume has 'efsVolumeConfiguration's attached to it; did you modify the task definition after adding Lumigo tracing to it?`); } } } class ContainerDefinitionValidation { constructor(containerDefinition) { this.issues = []; this.addIssue = (issue) => this.issues.push(`Container '${this.containerDefinition.containerName}': ${issue}`); this.containerDefinition = containerDefinition; } validate() { this.validateContainerDefinition(this.containerDefinition); return this.issues; } } class EcsContainerDefinitionLumigoInjectorVolumeMountPointValidation extends ContainerDefinitionValidation { constructor(containerDefinition) { super(containerDefinition); } validateContainerDefinition(containerDefinition) { const injectorVolumeMountPoint = containerDefinition.mountPoints?.find(mountPoint => mountPoint.sourceVolume === LUMIGO_INJECTOR_VOLUME_NAME); if (!injectorVolumeMountPoint) { this.addIssue(`No mount point '${LUMIGO_INJECTOR_VOLUME_NAME}' found`); } else { if (!injectorVolumeMountPoint.readOnly) { this.addIssue(`The mount point for the '${LUMIGO_INJECTOR_VOLUME_NAME}' volume is not set to read-only`); } if (injectorVolumeMountPoint.containerPath !== LUMIGO_INJECTOR_VOLUME_MOUNT_POINT) { this.addIssue(`The container path of the mount point for the '${LUMIGO_INJECTOR_VOLUME_NAME}' volume is not set to '${LUMIGO_INJECTOR_VOLUME_MOUNT_POINT}'`); } } } } class EcsContainerDefinitionLumigoInjectorContainerConditionValidation extends ContainerDefinitionValidation { constructor(containerDefinition, injectorContainer) { super(containerDefinition); this.injectorContainer = injectorContainer; } validateContainerDefinition(containerDefinition) { const lumigoInjectorContainerDependency = containerDefinition.containerDependencies .find(containerDependency => containerDependency.container === this.injectorContainer); if (lumigoInjectorContainerDependency?.condition !== aws_ecs_1.ContainerDependencyCondition.COMPLETE) { this.addIssue(`The container dependency condition of the '${containerDefinition.containerName}' on the '${this.injectorContainer.containerName}' is not set to '${aws_ecs_1.ContainerDependencyCondition.COMPLETE}'`); } } } class EcsContainerDefinitionHasLumigoInjectorEnvVarValidation extends ContainerDefinitionValidation { constructor(containerDefinition) { super(containerDefinition); } validateContainerDefinition(containerDefinition) { const environment = containerDefinition.environment; if (environment[LUMIGO_INJECTOR_ENV_VAR_NAME] !== LUMIGO_INJECTOR_ENV_VAR_VALUE) { this.addIssue(`Container '${containerDefinition.containerName}': The '${LUMIGO_INJECTOR_ENV_VAR_NAME}' does not have the expected value '${LUMIGO_INJECTOR_ENV_VAR_VALUE}'`); } } } class EcsContainerDefinitionHasLumigoTracerTokenSecretValidation extends ContainerDefinitionValidation { constructor(containerDefinition) { super(containerDefinition); } validateContainerDefinition(containerDefinition) { const secrets = containerDefinition.secrets; if (!secrets.find((entry) => entry.name === LUMIGO_TRACER_TOKEN_ENV_VAR_NAME)) { // Don't print out the token value, who knows where these logs end up this.addIssue(`The '${LUMIGO_TRACER_TOKEN_ENV_VAR_NAME}' does is not mounted as a secret built from the SecretValue passed to the Lumigo object`); } } } class EcsContainerDefinitionHasLumigoTracerTokenEnvVarValidation extends ContainerDefinitionValidation { constructor(containerDefinition, expectedToken) { super(containerDefinition); this.expectedToken = expectedToken; } validateContainerDefinition(containerDefinition) { const environment = containerDefinition.environment; if (environment[LUMIGO_TRACER_TOKEN_ENV_VAR_NAME] !== this.expectedToken) { // Don't print out the token value, who knows where these logs end up this.addIssue(`The '${LUMIGO_TRACER_TOKEN_ENV_VAR_NAME}' does not have the expected value provided in the SecretValue passed to the Lumigo object`); } } } class HasExactlyOneLumigoLayerValidation { constructor(lambda) { this.lambda = lambda; } validate() { /* eslint-disable */ const layers = this.lambda['_layers']; /* eslint-enable */ if (!layers) { return ['The function does not have the Lumigo layer installed.']; } const lumigoLayerArns = layers .filter(layer => layer.layerVersionArn.startsWith(`arn:aws:lambda:${this.lambda.env.region}:114300393969:layer:lumigo-python-tracer`) || layer.layerVersionArn.startsWith(`arn:aws:lambda:${this.lambda.env.region}:114300393969:layer:lumigo-node-tracer`)) .map(layer => layer.layerVersionArn); if (lumigoLayerArns.length > 1) { return [`Multiple Lumigo layers found: ${lumigoLayerArns.map(arn => `'${arn}'`)}`]; } return []; } } class HasLumigoTracerEnvVarValidation { constructor(lambda) { this.lambda = lambda; } validate() { /* eslint-disable */ const environment = this.lambda['environment']; /* eslint-enable */ if (!environment) { return [`No 'environment' property found on this Lambda; consider upgrading your '${name}' package.`]; } if (!environment[LUMIGO_TRACER_TOKEN_ENV_VAR_NAME]) { return [`The '${LUMIGO_TRACER_TOKEN_ENV_VAR_NAME}' environment variable is not set.`]; } const { 'value': value, } = environment[LUMIGO_TRACER_TOKEN_ENV_VAR_NAME]; if (!value) { return [`The '${LUMIGO_TRACER_TOKEN_ENV_VAR_NAME}' environment variable has a blank value.`]; } return []; } } class HasAwsLambdaExecWrapperEnvVarValidation { constructor(lambda) { this.lambda = lambda; } validate() { /* eslint-disable */ const environment = this.lambda['environment']; /* eslint-enable */ if (!environment) { return [`No 'environment' property found on this Lambda; consider upgrading your '${name}' package.`]; } if (!environment[AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_NAME]) { return [`The '${AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_NAME}' environment variable is not set.`]; } const { 'value': value, } = environment[AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_NAME]; if (value !== AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_VALUE) { return [`The '${AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_NAME}' environment variable has a different value than the expected '${AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR_VALUE}'.`]; } return []; } } class HasAwsLambdaOriginalHandlerEnvVarValidation { constructor(lambda) { this.lambda = lambda; } validate() { /* eslint-disable */ const environment = this.lambda['environment']; /* eslint-enable */ if (!environment) { return [`No 'environment' property found on this Lambda; consider upgrading your '${name}' package.`]; } if (!environment[LUMIGO_ORIGINAL_HANDLER_ENV_VAR_NAME]) { return [`The '${LUMIGO_ORIGINAL_HANDLER_ENV_VAR_NAME}' environment variable is not set.`]; } const { 'value': value, } = environment[LUMIGO_ORIGINAL_HANDLER_ENV_VAR_NAME]; if (!value) { return [`The '${LUMIGO_ORIGINAL_HANDLER_ENV_VAR_NAME}' environment variable has a blank value.`]; } return []; } } class HasLumigoPropagateW3CEnvVarValidation { constructor(lambda, expectedValue) { this.lambda = lambda; this.expectedValue = expectedValue; } validate() { /* eslint-disable */ const environment = this.lambda['environment']; /* eslint-enable */ if (!environment) { return [`No 'environment' property found on this Lambda; consider upgrading your '${name}' package.`]; } if (!environment[LUMIGO_PROPAGATE_W3C_ENV_VAR_NAME]) { return [`The '${LUMIGO_PROPAGATE_W3C_ENV_VAR_NAME}' environment variable is not set.`]; } const { 'value': value, } = environment[LUMIGO_PROPAGATE_W3C_ENV_VAR_NAME]; if (value !== String(this.expectedValue)) { return [`The '${LUMIGO_PROPAGATE_W3C_ENV_VAR_NAME}' environment variable has a different value than the expected '${this.expectedValue}'.`]; } return []; } } class HasLumigoPythonHandlerInResourceValidation { constructor(lambda) { this.lambda = lambda; } validate() { /* eslint-disable */ if (this.lambda.node._children['Resource'].handler != LUMIGO_LAMBDA_PYTHON_HANDLER) { return [`The handler is not set to Lumigo's '${LUMIGO_LAMBDA_PYTHON_HANDLER}'.`]; } /* eslint-enable */ return []; } } class UnsupportedLambdaRuntimeError extends Error { constructor(unsupportedRuntime) { super(`The '${unsupportedRuntime}' runtime is not supported.`); this.unsupportedRuntime = unsupportedRuntime; } } class UnsupportedLambdaLayerRegion extends Error { constructor(unsupportedType, unsupportedRegion) { super(`The '${unsupportedType}' layer is not supported in the '${unsupportedRegion}' region.`); this.unsupportedRegion = unsupportedRegion; this.unsupportedType = unsupportedType; } } function getTaskDefinitionContainers(taskDefinition) { return taskDefinition.containers; } function getTaskDefinitionVolumes(taskDefinition) { return taskDefinition.volumes || []; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibHVtaWdvLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2x1bWlnby50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLCtCQUFxQztBQVFyQyw2Q0FBd0o7QUFDeEosaURBYTZCO0FBQzdCLG1FQWFzQztBQUN0Qyx1REFBeUU7QUFDekUscUVBQStEO0FBQy9ELHVFQUErRTtBQUMvRSxpREFBc0Q7QUFHdEQsb0JBQW9CO0FBQ3BCLE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEdBQUcsT0FBTyxDQUFDLFdBQUksQ0FBQyxjQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsY0FBYyxDQUFDLENBQUMsQ0FBQztBQUM1RSxtQkFBbUI7QUFFbkIsa0VBQWtFO0FBQ2xFLGtFQUFrRTtBQUNsRSwrRUFBZ0Y7QUFFbkUsUUFBQSxrQ0FBa0MsR0FBRyxtQ0FBc0IsQ0FBQztBQXFKekUsMkJBQTJCO0FBQzNCLElBQUssZUFHSjtBQUhELFdBQUssZUFBZTtJQUNsQiw4Q0FBMkIsQ0FBQTtJQUMzQixrREFBK0IsQ0FBQTtBQUNqQyxDQUFDLEVBSEksZUFBZSxLQUFmLGVBQWUsUUFHbkI7QUFFRCxNQUFNLG9DQUFvQyxHQUFHLHlCQUF5QixDQUFDO0FBRXZFLE1BQU0scUNBQXFDLEdBQUcscUJBQXFCLENBQUM7QUFFcEUsTUFBTSxvQ0FBb0MsR0FBRyx5QkFBeUIsQ0FBQztBQUV2RSxNQUFNLGlDQUFpQyxHQUFHLHNCQUFzQixDQUFDO0FBRWpFLE1BQU0sZ0NBQWdDLEdBQUcscUJBQXFCLENBQUM7QUFFL0QsTUFBTSx5QkFBeUIsR0FBRyxtQkFBbUIsQ0FBQztBQUV0RCxNQUFNLDBCQUEwQixHQUFHLEdBQUcsSUFBSSxJQUFJLE9BQU8sRUFBRSxDQUFDO0FBRXhELE1BQU0sbUJBQW1CLEdBQUcsWUFBWSxDQUFDO0FBRXpDLE1BQU0sNEJBQTRCLEdBQUcsd0JBQXdCLENBQUM7QUFFOUQsTUFBTSw4QkFBOEIsR0FBRyxpQkFBaUIsQ0FBQztB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