diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a5462acabd4e..e47c967a1926e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.125.0](https://github.com/aws/aws-cdk/compare/v1.124.0...v1.125.0) (2021-09-29) + + +### Features + +* **lambda:** support for ARM architecture ([b3ba35e](https://github.com/aws/aws-cdk/commit/b3ba35e9b8b157303a29350031885eff0c73b05b)) + ## [1.124.0](https://github.com/aws/aws-cdk/compare/v1.123.0...v1.124.0) (2021-09-21) diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index c6098ff19fe11..63b0a97e5df4a 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -326,6 +326,31 @@ new LayerVersion(this, 'MyLayer', { }); ``` +## Architecture + +Lambda functions, by default, run on compute systems that have the 64 bit x86 architecture. + +The AWS Lambda service also runs compute on the ARM architecture, which can reduce cost +for some workloads. + +A lambda function can be configured to be run on one or both of these platforms - + +```ts +new Function(this, 'MyFunction', { + ... + architectures: [ Architecture.X86_64, Architecture.ARM_64 ], +}); +``` + +Similarly, lambda layer versions can also be tagged with architectures it is compatible with. + +```ts +new LayerVersion(this, 'MyLayer', { + ... + compatibleArchitectures: [ Architecture.X86_64, Architecture.ARM_64 ], +}); +``` + ## Lambda Insights Lambda functions can be configured to use CloudWatch [Lambda Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights.html) diff --git a/packages/@aws-cdk/aws-lambda/lib/architecture.ts b/packages/@aws-cdk/aws-lambda/lib/architecture.ts new file mode 100644 index 0000000000000..40edee1896755 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/lib/architecture.ts @@ -0,0 +1,32 @@ +/** + * Architectures supported by AWS Lambda + */ +export class Architecture { + /** + * 64 bit architecture with x86 instruction set. + */ + public static readonly X86_64 = new Architecture('x86_64'); + + /** + * 64 bit architecture with the ARM instruction set. + */ + public static readonly ARM_64 = new Architecture('arm64'); + + /** + * Used to specify a custom architecture name. + * Use this if the architecture name is not yet supported by the CDK. + * @param name the architecture name as recognized by AWS Lambda. + */ + public static custom(name: string) { + return new Architecture(name); + } + + /** + * The name of the architecture as recognized by the AWS Lambda service APIs. + */ + public readonly name: string; + + private constructor(archName: string) { + this.name = archName; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 9cd67a478f003..72ae40d5babbe 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -7,6 +7,7 @@ import * as logs from '@aws-cdk/aws-logs'; import * as sqs from '@aws-cdk/aws-sqs'; import { Annotations, CfnResource, Duration, Fn, Lazy, Names, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { Architecture } from './architecture'; import { Code, CodeConfig } from './code'; import { ICodeSigningConfig } from './code-signing-config'; import { EventInvokeConfigOptions } from './event-invoke-config'; @@ -310,6 +311,12 @@ export interface FunctionOptions extends EventInvokeConfigOptions { * @default - Not Sign the Code */ readonly codeSigningConfig?: ICodeSigningConfig; + + /** + * The system architectures compatible with this lambda function. + * @default [Architecture.X86_64] + */ + readonly architectures?: Architecture[]; } export interface FunctionProps extends FunctionOptions { @@ -680,6 +687,7 @@ export class Function extends FunctionBase { kmsKeyArn: props.environmentEncryption?.keyArn, fileSystemConfigs, codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn, + architectures: props.architectures?.map(a => a.name), }); resource.node.addDependency(this.role); @@ -792,6 +800,11 @@ export class Function extends FunctionBase { 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); } } diff --git a/packages/@aws-cdk/aws-lambda/lib/index.ts b/packages/@aws-cdk/aws-lambda/lib/index.ts index 41c77bb8d038d..875e05e995631 100644 --- a/packages/@aws-cdk/aws-lambda/lib/index.ts +++ b/packages/@aws-cdk/aws-lambda/lib/index.ts @@ -19,6 +19,7 @@ export * from './scalable-attribute-api'; export * from './code-signing-config'; export * from './lambda-insights'; export * from './log-retention'; +export * from './architecture'; // AWS::Lambda CloudFormation Resources: export * from './lambda.generated'; diff --git a/packages/@aws-cdk/aws-lambda/lib/layers.ts b/packages/@aws-cdk/aws-lambda/lib/layers.ts index babf91079b8b6..7176badb0ee42 100644 --- a/packages/@aws-cdk/aws-lambda/lib/layers.ts +++ b/packages/@aws-cdk/aws-lambda/lib/layers.ts @@ -1,5 +1,6 @@ import { IResource, RemovalPolicy, Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { Architecture } from './architecture'; import { Code } from './code'; import { CfnLayerVersion, CfnLayerVersionPermission } from './lambda.generated'; import { Runtime } from './runtime'; @@ -46,6 +47,12 @@ export interface LayerVersionProps extends LayerVersionOptions { */ readonly compatibleRuntimes?: Runtime[]; + /** + * The system architectures compatible with this layer. + * @default [Architecture.X86_64] + */ + readonly compatibleArchitectures?: Architecture[]; + /** * The content of this Layer. * @@ -196,6 +203,7 @@ export class LayerVersion extends LayerVersionBase { const resource: CfnLayerVersion = new CfnLayerVersion(this, 'Resource', { compatibleRuntimes: props.compatibleRuntimes && props.compatibleRuntimes.map(r => r.name), + compatibleArchitectures: props.compatibleArchitectures?.map(a => a.name), content: { s3Bucket: code.s3Location.bucketName, s3Key: code.s3Location.objectKey, diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index b4f79aff6cc9e..a4aa4a31e10cc 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -2174,6 +2174,21 @@ describe('function', () => { })).toThrow(/Layers are not supported for container image functions/); }); + test('specified architecture is recognized', () => { + const stack = new cdk.Stack(); + new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + + architectures: [lambda.Architecture.ARM_64], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Architectures: ['arm64'], + }); + }); + }); function newTestLambda(scope: constructs.Construct) { diff --git a/packages/@aws-cdk/aws-lambda/test/layers.test.ts b/packages/@aws-cdk/aws-lambda/test/layers.test.ts index 3d8cc9d70de6f..1c416236c0980 100644 --- a/packages/@aws-cdk/aws-lambda/test/layers.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/layers.test.ts @@ -103,4 +103,18 @@ describe('layers', () => { DeletionPolicy: 'Retain', }, ResourcePart.CompleteDefinition); }); + + test('specified compatible architectures is recognized', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Bucket'); + const code = new lambda.S3Code(bucket, 'ObjectKey'); + new lambda.LayerVersion(stack, 'MyLayer', { + code, + compatibleArchitectures: [lambda.Architecture.ARM_64], + }); + + expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + CompatibleArchitectures: ['arm64'], + }); + }); }); diff --git a/packages/@aws-cdk/cfnspec/spec-source/530_Lambda_ARM_patch.json b/packages/@aws-cdk/cfnspec/spec-source/530_Lambda_ARM_patch.json new file mode 100644 index 0000000000000..13c481eff424d --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/530_Lambda_ARM_patch.json @@ -0,0 +1,41 @@ +{ + "ResourceType": { + "AWS::Lambda::Function": { + "patch": { + "description": "AWS::Lambda::Function changes for early support of Lambda ARM launch. Remove once CFN spec is updated", + "operations": [ + { + "op": "add", + "path": "/Properties/Architectures", + "value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-architectures", + "UpdateType": "Mutable", + "Required": false, + "Type": "List", + "PrimitiveItemType": "String", + "DuplicatesAllowed": true + } + } + ] + } + }, + "AWS::Lambda::LayerVersion": { + "patch": { + "description": "AWS::Lambda::LayerVersion changes for early support of Lambda ARM launch. Remove once CFN spec is updated", + "operations": [ + { + "op": "add", + "path": "/Properties/CompatibleArchitectures", + "value": { + "PrimitiveItemType": "String", + "Type": "List", + "Required": false, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-layerversion.html#cfn-lambda-layerversion-compatiblearchitectures", + "UpdateType": "Immutable" + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/version.v1.json b/version.v1.json index f92dd8626fad0..e3a6d956268a9 100644 --- a/version.v1.json +++ b/version.v1.json @@ -1,3 +1,3 @@ { - "version": "1.124.0" + "version": "1.125.0" } \ No newline at end of file