From c6914939700963cb3ba1c601614323c892c57149 Mon Sep 17 00:00:00 2001 From: Ryan Parker Date: Fri, 5 Nov 2021 16:02:43 -0700 Subject: [PATCH 1/4] feat(singleton-lambda): Added `runtime`, `logGroup`, `addLayers()`, `addEnvironment()` --- .../aws-lambda/lib/singleton-lambda.ts | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts index 431b9bf6a71d9..88a03d4ae4743 100644 --- a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts @@ -1,11 +1,14 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; +import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { Function as LambdaFunction, FunctionProps } from './function'; +import { Function as LambdaFunction, FunctionProps, EnvironmentOptions } from './function'; import { FunctionBase } from './function-base'; import { Version } from './lambda-version'; +import { ILayerVersion } from './layers'; import { Permission } from './permission'; +import { Runtime } from './runtime'; /** * Properties for a newly created singleton Lambda @@ -47,6 +50,16 @@ export class SingletonFunction extends FunctionBase { public readonly functionArn: string; public readonly role?: iam.IRole; public readonly permissionsNode: cdk.ConstructNode; + + /** + * The runtime environment for the Lambda function that you are uploading. + * For valid values, see the Runtime property in the AWS Lambda Developer + * Guide. + * + * Use `Runtime.FROM_IMAGE` when when defining a function from a Docker image. + */ + public readonly runtime: Runtime; + protected readonly canCreatePermissions: boolean; private lambdaFunction: LambdaFunction; @@ -59,6 +72,7 @@ export class SingletonFunction extends FunctionBase { this.functionArn = this.lambdaFunction.functionArn; this.functionName = this.lambdaFunction.functionName; this.role = this.lambdaFunction.role; + this.runtime = this.lambdaFunction.runtime; this.grantPrincipal = this.lambdaFunction.grantPrincipal; this.canCreatePermissions = true; // Doesn't matter, addPermission is overriden anyway @@ -78,6 +92,20 @@ export class SingletonFunction extends FunctionBase { return this.lambdaFunction.connections; } + /** + * 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. + */ + public get logGroup(): logs.ILogGroup { + return this.lambdaFunction.logGroup; + } + /** * Returns a `lambda.Version` which represents the current version of this * singleton Lambda function. A new version will be created every time the @@ -90,6 +118,28 @@ export class SingletonFunction extends FunctionBase { return this.lambdaFunction.currentVersion; } + /** + * 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. + */ + public addEnvironment(key: string, value: string, options?: EnvironmentOptions) { + return this.lambdaFunction.addEnvironment(key, value, options); + } + + /** + * 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. + */ + public addLayers(...layers: ILayerVersion[]) { + return this.lambdaFunction.addLayers(...layers); + } + public addPermission(name: string, permission: Permission) { return this.lambdaFunction.addPermission(name, permission); } From 2c28611e36d6ddf827cb86b7ec5356ae885c6004 Mon Sep 17 00:00:00 2001 From: Ryan Parker Date: Fri, 5 Nov 2021 16:30:32 -0700 Subject: [PATCH 2/4] tests: Added tests for the new methods and props --- .../aws-lambda/test/singleton-lambda.test.ts | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts index 3bf78253d5ed6..a9687880be314 100644 --- a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts @@ -2,6 +2,7 @@ import '@aws-cdk/assert-internal/jest'; import { ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; +import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as lambda from '../lib'; @@ -109,6 +110,57 @@ describe('singleton lambda', () => { }, ResourcePart.CompleteDefinition); }); + test('Environment is added to Lambda, when .addEnvironment() is provided one key pair', () => { + // GIVEN + const stack = new cdk.Stack(); + const singleton = new lambda.SingletonFunction(stack, 'Singleton', { + uuid: '84c0de93-353f-4217-9b0b-45b6c993251a', + code: new lambda.InlineCode('def hello(): pass'), + runtime: lambda.Runtime.PYTHON_2_7, + handler: 'index.hello', + timeout: cdk.Duration.minutes(5), + }); + + // WHEN + singleton.addEnvironment('KEY', 'value'); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Function', { + Environment: { + Variables: { + KEY: 'value', + }, + }, + }); + }); + + test('Layer is added to Lambda, when .addLayers() is provided a valid layer', () => { + // GIVEN + const stack = new cdk.Stack(); + const singleton = new lambda.SingletonFunction(stack, 'Singleton', { + uuid: '84c0de93-353f-4217-9b0b-45b6c993251a', + code: new lambda.InlineCode('def hello(): pass'), + runtime: lambda.Runtime.PYTHON_2_7, + handler: 'index.hello', + timeout: cdk.Duration.minutes(5), + }); + const bucket = new s3.Bucket(stack, 'Bucket'); + const layer = new lambda.LayerVersion(stack, 'myLayer', { + code: new lambda.S3Code(bucket, 'ObjectKey'), + compatibleRuntimes: [lambda.Runtime.PYTHON_2_7], + }); + + // WHEN + singleton.addLayers(layer); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Function', { + Layers: [{ + Ref: 'myLayerBA1B098A', + }], + }); + }); + test('grantInvoke works correctly', () => { // GIVEN const stack = new cdk.Stack(); @@ -154,6 +206,42 @@ describe('singleton lambda', () => { .toThrow(/contains environment variables .* and is not compatible with Lambda@Edge/); }); + test('logGroup is correctly returned', () => { + // GIVEN + const stack = new cdk.Stack(); + const singleton = new lambda.SingletonFunction(stack, 'Singleton', { + uuid: '84c0de93-353f-4217-9b0b-45b6c993251a', + code: new lambda.InlineCode('def hello(): pass'), + runtime: lambda.Runtime.PYTHON_2_7, + handler: 'index.hello', + timeout: cdk.Duration.minutes(5), + }); + + // WHEN + const logGroup = singleton.logGroup; + + // THEN + expect(logGroup.logGroupName).toBeDefined(); + expect(logGroup.logGroupArn).toBeDefined(); + }); + + test('runtime is correctly returned', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const singleton = new lambda.SingletonFunction(stack, 'Singleton', { + uuid: '84c0de93-353f-4217-9b0b-45b6c993251a', + code: new lambda.InlineCode('def hello(): pass'), + runtime: lambda.Runtime.PYTHON_2_7, + handler: 'index.hello', + timeout: cdk.Duration.minutes(5), + }); + + // THEN + expect(singleton.runtime).toStrictEqual(lambda.Runtime.PYTHON_2_7); + }); + test('current version of a singleton function', () => { // GIVEN const stack = new cdk.Stack(); From 7bc6092b0f9ababacb153bc48c351f53566f6d5c Mon Sep 17 00:00:00 2001 From: Ryan Parker Date: Fri, 5 Nov 2021 16:35:28 -0700 Subject: [PATCH 3/4] clean: cleaned up logGroup test --- .../@aws-cdk/aws-lambda/test/singleton-lambda.test.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts index a9687880be314..4200b7a18a6e5 100644 --- a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts @@ -209,6 +209,8 @@ describe('singleton lambda', () => { test('logGroup is correctly returned', () => { // GIVEN const stack = new cdk.Stack(); + + // WHEN const singleton = new lambda.SingletonFunction(stack, 'Singleton', { uuid: '84c0de93-353f-4217-9b0b-45b6c993251a', code: new lambda.InlineCode('def hello(): pass'), @@ -217,12 +219,9 @@ describe('singleton lambda', () => { timeout: cdk.Duration.minutes(5), }); - // WHEN - const logGroup = singleton.logGroup; - // THEN - expect(logGroup.logGroupName).toBeDefined(); - expect(logGroup.logGroupArn).toBeDefined(); + expect(singleton.logGroup.logGroupName).toBeDefined(); + expect(singleton.logGroup.logGroupArn).toBeDefined(); }); test('runtime is correctly returned', () => { From 2a2af4be52b886a91ce71830ffc22ffc542e206c Mon Sep 17 00:00:00 2001 From: Ryan Parker Date: Tue, 9 Nov 2021 10:05:42 -0800 Subject: [PATCH 4/4] Update packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts Co-authored-by: Niranjan Jayakar --- packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts index 88a03d4ae4743..c096730b1e8eb 100644 --- a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts @@ -52,11 +52,7 @@ export class SingletonFunction extends FunctionBase { public readonly permissionsNode: cdk.ConstructNode; /** - * The runtime environment for the Lambda function that you are uploading. - * For valid values, see the Runtime property in the AWS Lambda Developer - * Guide. - * - * Use `Runtime.FROM_IMAGE` when when defining a function from a Docker image. + * The runtime environment for the Lambda function. */ public readonly runtime: Runtime;