@aws-cdk/aws-lambda
Version:
The CDK Construct Library for AWS::Lambda
854 lines • 131 kB
JavaScript
"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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