UNPKG

@aws-cdk/aws-lambda

Version:

The CDK Construct Library for AWS::Lambda

854 lines 131 kB
"use strict"; var _a, _b; Object.defineProperty(exports, "__esModule", { value: true }); exports.FunctionVersionUpgrade = exports.verifyCodeConfig = exports.Function = exports.Tracing = void 0; const jsiiDeprecationWarnings = require("../.warnings.jsii.js"); const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const cloudwatch = require("@aws-cdk/aws-cloudwatch"); const aws_codeguruprofiler_1 = require("@aws-cdk/aws-codeguruprofiler"); const ec2 = require("@aws-cdk/aws-ec2"); const iam = require("@aws-cdk/aws-iam"); const logs = require("@aws-cdk/aws-logs"); const sqs = require("@aws-cdk/aws-sqs"); const core_1 = require("@aws-cdk/core"); const cx_api_1 = require("@aws-cdk/cx-api"); const architecture_1 = require("./architecture"); const function_base_1 = require("./function-base"); const function_hash_1 = require("./function-hash"); const handler_1 = require("./handler"); const lambda_version_1 = require("./lambda-version"); const lambda_generated_1 = require("./lambda.generated"); const layers_1 = require("./layers"); const runtime_1 = require("./runtime"); const util_1 = require("./util"); /** * X-Ray Tracing Modes (https://docs.aws.amazon.com/lambda/latest/dg/API_TracingConfig.html) */ var Tracing; (function (Tracing) { /** * Lambda will respect any tracing header it receives from an upstream service. * If no tracing header is received, Lambda will call X-Ray for a tracing decision. */ Tracing["ACTIVE"] = "Active"; /** * Lambda will only trace the request from an upstream service * if it contains a tracing header with "sampled=1" */ Tracing["PASS_THROUGH"] = "PassThrough"; /** * Lambda will not trace any request. */ Tracing["DISABLED"] = "Disabled"; })(Tracing = exports.Tracing || (exports.Tracing = {})); /** * Deploys a file from inside the construct library as a function. * * The supplied file is subject to the 4096 bytes limit of being embedded in a * CloudFormation template. * * The construct includes an associated role with the lambda. * * This construct does not yet reproduce all features from the underlying resource * library. */ class Function extends function_base_1.FunctionBase { constructor(scope, id, props) { super(scope, id, { physicalName: props.functionName, }); this.permissionsNode = this.node; this.canCreatePermissions = true; /** @internal */ this._layers = []; /** * Environment variables for this function */ this.environment = {}; try { jsiiDeprecationWarnings._aws_cdk_aws_lambda_FunctionProps(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, Function); } throw error; } if (props.functionName && !core_1.Token.isUnresolved(props.functionName)) { if (props.functionName.length > 64) { throw new Error(`Function name can not be longer than 64 characters but has ${props.functionName.length} characters.`); } if (!/^[a-zA-Z0-9-_]+$/.test(props.functionName)) { throw new Error(`Function name ${props.functionName} can contain only letters, numbers, hyphens, or underscores with no spaces.`); } } if (props.description && !core_1.Token.isUnresolved(props.description)) { if (props.description.length > 256) { throw new Error(`Function description can not be longer than 256 characters but has ${props.description.length} characters.`); } } const managedPolicies = new Array(); // the arn is in the form of - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole managedPolicies.push(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')); if (props.vpc) { // Policy that will have ENI creation permissions managedPolicies.push(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaVPCAccessExecutionRole')); } this.role = props.role || new iam.Role(this, 'ServiceRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), managedPolicies, }); this.grantPrincipal = this.role; // add additional managed policies when necessary if (props.filesystem) { const config = props.filesystem.config; if (config.policies) { config.policies.forEach(p => { this.role?.addToPrincipalPolicy(p); }); } } for (const statement of (props.initialPolicy || [])) { this.role.addToPrincipalPolicy(statement); } const code = props.code.bind(this); verifyCodeConfig(code, props); let profilingGroupEnvironmentVariables = {}; if (props.profilingGroup && props.profiling !== false) { this.validateProfiling(props); props.profilingGroup.grantPublish(this.role); profilingGroupEnvironmentVariables = { AWS_CODEGURU_PROFILER_GROUP_ARN: core_1.Stack.of(scope).formatArn({ service: 'codeguru-profiler', resource: 'profilingGroup', resourceName: props.profilingGroup.profilingGroupName, }), AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', }; } else if (props.profiling) { this.validateProfiling(props); const profilingGroup = new aws_codeguruprofiler_1.ProfilingGroup(this, 'ProfilingGroup', { computePlatform: aws_codeguruprofiler_1.ComputePlatform.AWS_LAMBDA, }); profilingGroup.grantPublish(this.role); profilingGroupEnvironmentVariables = { AWS_CODEGURU_PROFILER_GROUP_ARN: profilingGroup.profilingGroupArn, AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', }; } const env = { ...profilingGroupEnvironmentVariables, ...props.environment }; for (const [key, value] of Object.entries(env)) { this.addEnvironment(key, value); } // DLQ can be either sns.ITopic or sqs.IQueue const dlqTopicOrQueue = this.buildDeadLetterQueue(props); if (dlqTopicOrQueue !== undefined) { if (this.isQueue(dlqTopicOrQueue)) { this.deadLetterQueue = dlqTopicOrQueue; } else { this.deadLetterTopic = dlqTopicOrQueue; } } let fileSystemConfigs = undefined; if (props.filesystem) { fileSystemConfigs = [{ arn: props.filesystem.config.arn, localMountPath: props.filesystem.config.localMountPath, }]; } if (props.architecture && props.architectures !== undefined) { throw new Error('Either architecture or architectures must be specified but not both.'); } if (props.architectures && props.architectures.length > 1) { throw new Error('Only one architecture must be specified.'); } this._architecture = props.architecture ?? (props.architectures && props.architectures[0]); if (props.ephemeralStorageSize && !props.ephemeralStorageSize.isUnresolved() && (props.ephemeralStorageSize.toMebibytes() < 512 || props.ephemeralStorageSize.toMebibytes() > 10240)) { throw new Error(`Ephemeral storage size must be between 512 and 10240 MB, received ${props.ephemeralStorageSize}.`); } const resource = new lambda_generated_1.CfnFunction(this, 'Resource', { functionName: this.physicalName, description: props.description, code: { s3Bucket: code.s3Location && code.s3Location.bucketName, s3Key: code.s3Location && code.s3Location.objectKey, s3ObjectVersion: code.s3Location && code.s3Location.objectVersion, zipFile: code.inlineCode, imageUri: code.image?.imageUri, }, layers: core_1.Lazy.list({ produce: () => this.renderLayers() }), handler: props.handler === handler_1.Handler.FROM_IMAGE ? undefined : props.handler, timeout: props.timeout && props.timeout.toSeconds(), packageType: props.runtime === runtime_1.Runtime.FROM_IMAGE ? 'Image' : undefined, runtime: props.runtime === runtime_1.Runtime.FROM_IMAGE ? undefined : props.runtime.name, role: this.role.roleArn, // Uncached because calling '_checkEdgeCompatibility', which gets called in the resolve of another // Token, actually *modifies* the 'environment' map. environment: core_1.Lazy.uncachedAny({ produce: () => this.renderEnvironment() }), memorySize: props.memorySize, ephemeralStorage: props.ephemeralStorageSize ? { size: props.ephemeralStorageSize.toMebibytes(), } : undefined, vpcConfig: this.configureVpc(props), deadLetterConfig: this.buildDeadLetterConfig(dlqTopicOrQueue), tracingConfig: this.buildTracingConfig(props), reservedConcurrentExecutions: props.reservedConcurrentExecutions, imageConfig: undefinedIfNoKeys({ command: code.image?.cmd, entryPoint: code.image?.entrypoint, workingDirectory: code.image?.workingDirectory, }), kmsKeyArn: props.environmentEncryption?.keyArn, fileSystemConfigs, codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn, architectures: this._architecture ? [this._architecture.name] : undefined, }); resource.node.addDependency(this.role); this.functionName = this.getResourceNameAttribute(resource.ref); this.functionArn = this.getResourceArnAttribute(resource.attrArn, { service: 'lambda', resource: 'function', resourceName: this.physicalName, arnFormat: core_1.ArnFormat.COLON_RESOURCE_NAME, }); this.runtime = props.runtime; this.timeout = props.timeout; this.architecture = props.architecture ?? architecture_1.Architecture.X86_64; if (props.layers) { if (props.runtime === runtime_1.Runtime.FROM_IMAGE) { throw new Error('Layers are not supported for container image functions'); } this.addLayers(...props.layers); } for (const event of props.events || []) { this.addEventSource(event); } // Log retention if (props.logRetention) { const logRetention = new logs.LogRetention(this, 'LogRetention', { logGroupName: `/aws/lambda/${this.functionName}`, retention: props.logRetention, role: props.logRetentionRole, logRetentionRetryOptions: props.logRetentionRetryOptions, }); this._logGroup = logs.LogGroup.fromLogGroupArn(this, 'LogGroup', logRetention.logGroupArn); } props.code.bindToResource(resource); // Event Invoke Config if (props.onFailure || props.onSuccess || props.maxEventAge || props.retryAttempts !== undefined) { this.configureAsyncInvoke({ onFailure: props.onFailure, onSuccess: props.onSuccess, maxEventAge: props.maxEventAge, retryAttempts: props.retryAttempts, }); } this.currentVersionOptions = props.currentVersionOptions; if (props.filesystem) { if (!props.vpc) { throw new Error('Cannot configure \'filesystem\' without configuring a VPC.'); } const config = props.filesystem.config; if (config.dependency) { this.node.addDependency(...config.dependency); } // There could be a race if the Lambda is used in a CustomResource. It is possible for the Lambda to // fail to attach to a given FileSystem if we do not have a dependency on the SecurityGroup ingress/egress // rules that were created between this Lambda's SG & the Filesystem SG. this.connections.securityGroups.forEach(sg => { sg.node.findAll().forEach(child => { if (child instanceof core_1.CfnResource && child.cfnResourceType === 'AWS::EC2::SecurityGroupEgress') { resource.node.addDependency(child); } }); }); config.connections?.securityGroups.forEach(sg => { sg.node.findAll().forEach(child => { if (child instanceof core_1.CfnResource && child.cfnResourceType === 'AWS::EC2::SecurityGroupIngress') { resource.node.addDependency(child); } }); }); } // Configure Lambda insights this.configureLambdaInsights(props); } /** * Returns a `lambda.Version` which represents the current version of this * Lambda function. A new version will be created every time the function's * configuration changes. * * You can specify options for this version using the `currentVersionOptions` * prop when initializing the `lambda.Function`. */ get currentVersion() { if (this._currentVersion) { return this._currentVersion; } if (this._warnIfCurrentVersionCalled) { this.warnInvokeFunctionPermissions(this); } ; this._currentVersion = new lambda_version_1.Version(this, 'CurrentVersion', { lambda: this, ...this.currentVersionOptions, }); // override the version's logical ID with a lazy string which includes the // hash of the function itself, so a new version resource is created when // the function configuration changes. const cfn = this._currentVersion.node.defaultChild; const originalLogicalId = this.stack.resolve(cfn.logicalId); cfn.overrideLogicalId(core_1.Lazy.uncachedString({ produce: () => { const hash = function_hash_1.calculateFunctionHash(this); const logicalId = function_hash_1.trimFromStart(originalLogicalId, 255 - 32); return `${logicalId}${hash}`; }, })); return this._currentVersion; } get resourceArnsForGrantInvoke() { return [this.functionArn, `${this.functionArn}:*`]; } /** * Record whether specific properties in the `AWS::Lambda::Function` resource should * also be associated to the Version resource. * See 'currentVersion' section in the module README for more details. * @param propertyName The property to classify * @param locked whether the property should be associated to the version or not. */ static classifyVersionProperty(propertyName, locked) { this._VER_PROPS[propertyName] = locked; } /** * Import a lambda function into the CDK using its name */ static fromFunctionName(scope, id, functionName) { return Function.fromFunctionAttributes(scope, id, { functionArn: core_1.Stack.of(scope).formatArn({ service: 'lambda', resource: 'function', resourceName: functionName, arnFormat: core_1.ArnFormat.COLON_RESOURCE_NAME, }), }); } /** * Import a lambda function into the CDK using its ARN */ static fromFunctionArn(scope, id, functionArn) { return Function.fromFunctionAttributes(scope, id, { functionArn }); } /** * Creates a Lambda function object which represents a function not defined * within this stack. * * @param scope The parent construct * @param id The name of the lambda construct * @param attrs the attributes of the function to import */ static fromFunctionAttributes(scope, id, attrs) { try { jsiiDeprecationWarnings._aws_cdk_aws_lambda_FunctionAttributes(attrs); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.fromFunctionAttributes); } throw error; } const functionArn = attrs.functionArn; const functionName = extractNameFromArn(attrs.functionArn); const role = attrs.role; class Import extends function_base_1.FunctionBase { constructor(s, i) { super(s, i, { environmentFromArn: functionArn, }); this.functionName = functionName; this.functionArn = functionArn; this.role = role; this.permissionsNode = this.node; this.architecture = attrs.architecture ?? architecture_1.Architecture.X86_64; this.resourceArnsForGrantInvoke = [this.functionArn, `${this.functionArn}:*`]; this.canCreatePermissions = attrs.sameEnvironment ?? this._isStackAccount(); this._skipPermissions = attrs.skipPermissions ?? false; this.grantPrincipal = role || new iam.UnknownPrincipal({ resource: this }); if (attrs.securityGroup) { this._connections = new ec2.Connections({ securityGroups: [attrs.securityGroup], }); } else if (attrs.securityGroupId) { this._connections = new ec2.Connections({ securityGroups: [ec2.SecurityGroup.fromSecurityGroupId(scope, 'SecurityGroup', attrs.securityGroupId)], }); } } } return new Import(scope, id); } /** * Return the given named metric for this Lambda */ static metricAll(metricName, props) { return new cloudwatch.Metric({ namespace: 'AWS/Lambda', metricName, ...props, }); } /** * Metric for the number of Errors executing all Lambdas * * @default sum over 5 minutes */ static metricAllErrors(props) { return this.metricAll('Errors', { statistic: 'sum', ...props }); } /** * Metric for the Duration executing all Lambdas * * @default average over 5 minutes */ static metricAllDuration(props) { return this.metricAll('Duration', props); } /** * Metric for the number of invocations of all Lambdas * * @default sum over 5 minutes */ static metricAllInvocations(props) { return this.metricAll('Invocations', { statistic: 'sum', ...props }); } /** * Metric for the number of throttled invocations of all Lambdas * * @default sum over 5 minutes */ static metricAllThrottles(props) { return this.metricAll('Throttles', { statistic: 'sum', ...props }); } /** * Metric for the number of concurrent executions across all Lambdas * * @default max over 5 minutes */ static metricAllConcurrentExecutions(props) { // Mini-FAQ: why max? This metric is a gauge that is emitted every // minute, so either max or avg or a percentile make sense (but sum // doesn't). Max is more sensitive to spiky load changes which is // probably what you're interested in if you're looking at this metric // (Load spikes may lead to concurrent execution errors that would // otherwise not be visible in the avg) return this.metricAll('ConcurrentExecutions', { statistic: 'max', ...props }); } /** * Metric for the number of unreserved concurrent executions across all Lambdas * * @default max over 5 minutes */ static metricAllUnreservedConcurrentExecutions(props) { return this.metricAll('UnreservedConcurrentExecutions', { statistic: 'max', ...props }); } /** * Adds an environment variable to this Lambda function. * If this is a ref to a Lambda function, this operation results in a no-op. * @param key The environment variable key. * @param value The environment variable's value. * @param options Environment variable options. */ addEnvironment(key, value, options) { try { jsiiDeprecationWarnings._aws_cdk_aws_lambda_EnvironmentOptions(options); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addEnvironment); } throw error; } this.environment[key] = { value, ...options }; return this; } /** * Adds one or more Lambda Layers to this Lambda function. * * @param layers the layers to be added. * * @throws if there are already 5 layers on this function, or the layer is incompatible with this function's runtime. */ addLayers(...layers) { try { jsiiDeprecationWarnings._aws_cdk_aws_lambda_ILayerVersion(layers); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addLayers); } throw error; } for (const layer of layers) { if (this._layers.length === 5) { throw new Error('Unable to add layer: this lambda function already uses 5 layers.'); } if (layer.compatibleRuntimes && !layer.compatibleRuntimes.find(runtime => runtime.runtimeEquals(this.runtime))) { const runtimes = layer.compatibleRuntimes.map(runtime => runtime.name).join(', '); throw new Error(`This lambda function uses a runtime that is incompatible with this layer (${this.runtime.name} is not in [${runtimes}])`); } // Currently no validations for compatible architectures since Lambda service // allows layers configured with one architecture to be used with a Lambda function // from another architecture. this._layers.push(layer); } } /** * Add a new version for this Lambda * * If you want to deploy through CloudFormation and use aliases, you need to * add a new version (with a new name) to your Lambda every time you want to * deploy an update. An alias can then refer to the newly created Version. * * All versions should have distinct names, and you should not delete versions * as long as your Alias needs to refer to them. * * @param name A unique name for this version. * @param codeSha256 The SHA-256 hash of the most recently deployed Lambda * source code, or omit to skip validation. * @param description A description for this version. * @param provisionedExecutions A provisioned concurrency configuration for a * function's version. * @param asyncInvokeConfig configuration for this version when it is invoked * asynchronously. * @returns A new Version object. * * @deprecated This method will create an AWS::Lambda::Version resource which * snapshots the AWS Lambda function *at the time of its creation* and it * won't get updated when the function changes. Instead, use * `this.currentVersion` to obtain a reference to a version resource that gets * automatically recreated when the function configuration (or code) changes. */ addVersion(name, codeSha256, description, provisionedExecutions, asyncInvokeConfig = {}) { try { jsiiDeprecationWarnings.print("@aws-cdk/aws-lambda.Function#addVersion", "This method will create an AWS::Lambda::Version resource which\nsnapshots the AWS Lambda function *at the time of its creation* and it\nwon't get updated when the function changes. Instead, use\n`this.currentVersion` to obtain a reference to a version resource that gets\nautomatically recreated when the function configuration (or code) changes."); jsiiDeprecationWarnings._aws_cdk_aws_lambda_EventInvokeConfigOptions(asyncInvokeConfig); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addVersion); } throw error; } return new lambda_version_1.Version(this, 'Version' + name, { lambda: this, codeSha256, description, provisionedConcurrentExecutions: provisionedExecutions, ...asyncInvokeConfig, }); } /** * Defines an alias for this function. * * The alias will automatically be updated to point to the latest version of * the function as it is being updated during a deployment. * * ```ts * declare const fn: lambda.Function; * * fn.addAlias('Live'); * * // Is equivalent to * * new lambda.Alias(this, 'AliasLive', { * aliasName: 'Live', * version: fn.currentVersion, * }); * * @param aliasName The name of the alias * @param options Alias options */ addAlias(aliasName, options) { try { jsiiDeprecationWarnings._aws_cdk_aws_lambda_AliasOptions(options); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addAlias); } throw error; } return util_1.addAlias(this, this.currentVersion, aliasName, options); } /** * The LogGroup where the Lambda function's logs are made available. * * If either `logRetention` is set or this property is called, a CloudFormation custom resource is added to the stack that * pre-creates the log group as part of the stack deployment, if it already doesn't exist, and sets the correct log retention * period (never expire, by default). * * Further, if the log group already exists and the `logRetention` is not set, the custom resource will reset the log retention * to never expire even if it was configured with a different value. */ get logGroup() { if (!this._logGroup) { const logRetention = new logs.LogRetention(this, 'LogRetention', { logGroupName: `/aws/lambda/${this.functionName}`, retention: logs.RetentionDays.INFINITE, }); this._logGroup = logs.LogGroup.fromLogGroupArn(this, `${this.node.id}-LogGroup`, logRetention.logGroupArn); } return this._logGroup; } /** @internal */ _checkEdgeCompatibility() { // Check env vars const envEntries = Object.entries(this.environment); for (const [key, config] of envEntries) { if (config.removeInEdge) { delete this.environment[key]; core_1.Annotations.of(this).addInfo(`Removed ${key} environment variable for Lambda@Edge compatibility`); } } const envKeys = Object.keys(this.environment); if (envKeys.length !== 0) { throw new Error(`The function ${this.node.path} contains environment variables [${envKeys}] and is not compatible with Lambda@Edge. \ Environment variables can be marked for removal when used in Lambda@Edge by setting the \'removeInEdge\' property in the \'addEnvironment()\' API.`); } return; } /** * Configured lambda insights on the function if specified. This is acheived by adding an imported layer which is added to the * list of lambda layers on synthesis. * * https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html */ configureLambdaInsights(props) { if (props.insightsVersion === undefined) { return; } if (props.runtime !== runtime_1.Runtime.FROM_IMAGE) { // Layers cannot be added to Lambda container images. The image should have the insights agent installed. // See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-Getting-Started-docker.html this.addLayers(layers_1.LayerVersion.fromLayerVersionArn(this, 'LambdaInsightsLayer', props.insightsVersion._bind(this, this).arn)); } this.role?.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLambdaInsightsExecutionRolePolicy')); } renderLayers() { if (!this._layers || this._layers.length === 0) { return undefined; } if (core_1.FeatureFlags.of(this).isEnabled(cx_api_1.LAMBDA_RECOGNIZE_LAYER_VERSION)) { this._layers.sort(); } return this._layers.map(layer => layer.layerVersionArn); } renderEnvironment() { if (!this.environment || Object.keys(this.environment).length === 0) { return undefined; } const variables = {}; // Sort environment so the hash of the function used to create // `currentVersion` is not affected by key order (this is how lambda does // it). For backwards compatibility we do not sort environment variables in case // _currentVersion is not defined. Otherwise, this would have invalidated // the template, and for example, may cause unneeded updates for nested // stacks. const keys = this._currentVersion ? Object.keys(this.environment).sort() : Object.keys(this.environment); for (const key of keys) { variables[key] = this.environment[key].value; } return { variables }; } /** * If configured, set up the VPC-related properties * * Returns the VpcConfig that should be added to the * Lambda creation properties. */ configureVpc(props) { if ((props.securityGroup || props.allowAllOutbound !== undefined) && !props.vpc) { throw new Error('Cannot configure \'securityGroup\' or \'allowAllOutbound\' without configuring a VPC'); } if (!props.vpc) { return undefined; } if (props.securityGroup && props.allowAllOutbound !== undefined) { throw new Error('Configure \'allowAllOutbound\' directly on the supplied SecurityGroup.'); } let securityGroups; if (props.securityGroup && props.securityGroups) { throw new Error('Only one of the function props, securityGroup or securityGroups, is allowed'); } if (props.securityGroups) { securityGroups = props.securityGroups; } else { const securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, description: 'Automatic security group for Lambda Function ' + core_1.Names.uniqueId(this), allowAllOutbound: props.allowAllOutbound, }); securityGroups = [securityGroup]; } this._connections = new ec2.Connections({ securityGroups }); if (props.filesystem) { if (props.filesystem.config.connections) { props.filesystem.config.connections.allowDefaultPortFrom(this); } } const allowPublicSubnet = props.allowPublicSubnet ?? false; const { subnetIds } = props.vpc.selectSubnets(props.vpcSubnets); const publicSubnetIds = new Set(props.vpc.publicSubnets.map(s => s.subnetId)); for (const subnetId of subnetIds) { if (publicSubnetIds.has(subnetId) && !allowPublicSubnet) { throw new Error('Lambda Functions in a public subnet can NOT access the internet. ' + 'If you are aware of this limitation and would still like to place the function in a public subnet, set `allowPublicSubnet` to true'); } } // List can't be empty here, if we got this far you intended to put your Lambda // in subnets. We're going to guarantee that we get the nice error message by // making VpcNetwork do the selection again. return { subnetIds, securityGroupIds: securityGroups.map(sg => sg.securityGroupId), }; } isQueue(deadLetterQueue) { return deadLetterQueue.queueArn !== undefined; } buildDeadLetterQueue(props) { if (!props.deadLetterQueue && !props.deadLetterQueueEnabled && !props.deadLetterTopic) { return undefined; } if (props.deadLetterQueue && props.deadLetterQueueEnabled === false) { throw Error('deadLetterQueue defined but deadLetterQueueEnabled explicitly set to false'); } if (props.deadLetterTopic && (props.deadLetterQueue || props.deadLetterQueueEnabled !== undefined)) { throw new Error('deadLetterQueue and deadLetterTopic cannot be specified together at the same time'); } let deadLetterQueue; if (props.deadLetterTopic) { deadLetterQueue = props.deadLetterTopic; this.addToRolePolicy(new iam.PolicyStatement({ actions: ['sns:Publish'], resources: [deadLetterQueue.topicArn], })); } else { deadLetterQueue = props.deadLetterQueue || new sqs.Queue(this, 'DeadLetterQueue', { retentionPeriod: core_1.Duration.days(14), }); this.addToRolePolicy(new iam.PolicyStatement({ actions: ['sqs:SendMessage'], resources: [deadLetterQueue.queueArn], })); } return deadLetterQueue; } buildDeadLetterConfig(deadLetterQueue) { if (deadLetterQueue) { return { targetArn: this.isQueue(deadLetterQueue) ? deadLetterQueue.queueArn : deadLetterQueue.topicArn, }; } else { return undefined; } } buildTracingConfig(props) { if (props.tracing === undefined || props.tracing === Tracing.DISABLED) { return undefined; } this.addToRolePolicy(new iam.PolicyStatement({ actions: ['xray:PutTraceSegments', 'xray:PutTelemetryRecords'], resources: ['*'], })); return { mode: props.tracing, }; } validateProfiling(props) { if (!props.runtime.supportsCodeGuruProfiling) { throw new Error(`CodeGuru profiling is not supported by runtime ${props.runtime.name}`); } if (props.environment && (props.environment.AWS_CODEGURU_PROFILER_GROUP_ARN || props.environment.AWS_CODEGURU_PROFILER_ENABLED)) { throw new Error('AWS_CODEGURU_PROFILER_GROUP_ARN and AWS_CODEGURU_PROFILER_ENABLED must not be set when profiling options enabled'); } } } exports.Function = Function; _a = JSII_RTTI_SYMBOL_1; Function[_a] = { fqn: "@aws-cdk/aws-lambda.Function", version: "1.204.0" }; /** @internal */ Function._VER_PROPS = {}; /** * Given an opaque (token) ARN, returns a CloudFormation expression that extracts the function * name from the ARN. * * Function ARNs look like this: * * arn:aws:lambda:region:account-id:function:function-name * * ..which means that in order to extract the `function-name` component from the ARN, we can * split the ARN using ":" and select the component in index 6. * * @returns `FnSelect(6, FnSplit(':', arn))` */ function extractNameFromArn(arn) { return core_1.Fn.select(6, core_1.Fn.split(':', arn)); } function verifyCodeConfig(code, props) { // mutually exclusive const codeType = [code.inlineCode, code.s3Location, code.image]; if (codeType.filter(x => !!x).length !== 1) { throw new Error('lambda.Code must specify exactly one of: "inlineCode", "s3Location", or "image"'); } if (!!code.image === (props.handler !== handler_1.Handler.FROM_IMAGE)) { throw new Error('handler must be `Handler.FROM_IMAGE` when using image asset for Lambda function'); } if (!!code.image === (props.runtime !== runtime_1.Runtime.FROM_IMAGE)) { throw new Error('runtime must be `Runtime.FROM_IMAGE` when using image asset for Lambda function'); } // if this is inline code, check that the runtime supports if (code.inlineCode && !props.runtime.supportsInlineCode) { throw new Error(`Inline source not allowed for ${props.runtime.name}`); } } exports.verifyCodeConfig = verifyCodeConfig; function undefinedIfNoKeys(struct) { const allUndefined = Object.values(struct).every(val => val === undefined); return allUndefined ? undefined : struct; } /** * Aspect for upgrading function versions when the feature flag * provided feature flag present. This can be necessary when the feature flag * changes the function hash, as such changes must be associated with a new * version. This aspect will change the function description in these cases, * which "validates" the new function hash. */ class FunctionVersionUpgrade { constructor(featureFlag, enabled = true) { this.featureFlag = featureFlag; this.enabled = enabled; } visit(node) { if (node instanceof Function && this.enabled === core_1.FeatureFlags.of(node).isEnabled(this.featureFlag)) { const cfnFunction = node.node.defaultChild; const desc = cfnFunction.description ? `${cfnFunction.description} ` : ''; cfnFunction.addPropertyOverride('Description', `${desc}version-hash:${function_hash_1.calculateFunctionHash(node)}`); } } ; } exports.FunctionVersionUpgrade = FunctionVersionUpgrade; _b = JSII_RTTI_SYMBOL_1; FunctionVersionUpgrade[_b] = { fqn: "@aws-cdk/aws-lambda.FunctionVersionUpgrade", version: "1.204.0" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJmdW5jdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxzREFBc0Q7QUFDdEQsd0VBQWlHO0FBQ2pHLHdDQUF3QztBQUN4Qyx3Q0FBd0M7QUFFeEMsMENBQTBDO0FBRTFDLHdDQUF3QztBQUN4Qyx3Q0FBc0o7QUFDdEosNENBQWlFO0FBR2pFLGlEQUE4QztBQU05QyxtREFBOEU7QUFDOUUsbURBQXVFO0FBQ3ZFLHVDQUFvQztBQUVwQyxxREFBMkQ7QUFDM0QseURBQWlEO0FBQ2pELHFDQUF1RDtBQUN2RCx1Q0FBb0M7QUFLcEMsaUNBQWtDO0FBRWxDOztHQUVHO0FBQ0gsSUFBWSxPQWVYO0FBZkQsV0FBWSxPQUFPO0lBQ2pCOzs7T0FHRztJQUNILDRCQUFpQixDQUFBO0lBQ2pCOzs7T0FHRztJQUNILHVDQUE0QixDQUFBO0lBQzVCOztPQUVHO0lBQ0gsZ0NBQXFCLENBQUE7QUFDdkIsQ0FBQyxFQWZXLE9BQU8sR0FBUCxlQUFPLEtBQVAsZUFBTyxRQWVsQjtBQStVRDs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBYSxRQUFTLFNBQVEsNEJBQVk7SUFxUXhDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBb0I7UUFDNUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixZQUFZLEVBQUUsS0FBSyxDQUFDLFlBQVk7U0FDakMsQ0FBQyxDQUFDO1FBdEJXLG9CQUFlLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUV6Qix5QkFBb0IsR0FBRyxJQUFJLENBQUM7UUFFL0MsZ0JBQWdCO1FBQ0EsWUFBTyxHQUFvQixFQUFFLENBQUM7UUFJOUM7O1dBRUc7UUFDSyxnQkFBVyxHQUF5QyxFQUFFLENBQUM7Ozs7OzsrQ0E5UHBELFFBQVE7Ozs7UUEwUWpCLElBQUksS0FBSyxDQUFDLFlBQVksSUFBSSxDQUFDLFlBQUssQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFD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