@lumigo/cdk-constructs-v2
Version:
Home to the Lumigo constructs for the AWS Cloud Development Kit (AWS CDK)
807 lines • 136 kB
JavaScript
"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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