diff --git a/packages/aws-cdk-lib/aws-lambda/lib/code.ts b/packages/aws-cdk-lib/aws-lambda/lib/code.ts index 2790e3b357e57..3f72eab2b9c8f 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/code.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/code.ts @@ -15,16 +15,30 @@ import { UnscopedValidationError, ValidationError } from '../../core/lib/errors' export abstract class Code { /** * Lambda handler code as an S3 object. + * + * Note: If `objectVersion` is not defined, the lambda will not be updated automatically if the code in the bucket is updated. + * This is because CDK/Cloudformation does not track changes on the source S3 Bucket. It is recommended to either use S3Code.fromAsset() instead or set objectVersion. * @param bucket The S3 bucket * @param key The object key * @param objectVersion Optional S3 object version */ public static fromBucket(bucket: s3.IBucket, key: string, objectVersion?: string): S3Code { + if (objectVersion === undefined) { + cdk.Annotations.of(bucket).addWarningV2( + '@aws-cdk/aws-lambda:codeFromBucketObjectVersionNotSpecified', + 'objectVersion is not defined for S3Code.fromBucket(). The lambda will not be updated automatically if the code in the bucket is updated. ' + + 'This is because CDK/Cloudformation does not track changes on the source S3 Bucket. It is recommended to either use S3Code.fromAsset() instead or set objectVersion.', + ); + } + return new S3Code(bucket, key, objectVersion); } /** * Lambda handler code as an S3 object. + * + * Note: If `options.objectVersion` is not defined, the lambda will not be updated automatically if the code in the bucket is updated. + * This is because CDK/Cloudformation does not track changes on the source S3 Bucket. It is recommended to either use S3Code.fromAsset() instead or set objectVersion. * @param bucket The S3 bucket * @param key The object key * @param options Optional parameters for setting the code, current optional parameters to set here are @@ -32,6 +46,14 @@ export abstract class Code { * 2. `sourceKMSKey` to set KMS Key for encryption of code */ public static fromBucketV2 (bucket: s3.IBucket, key: string, options?: BucketOptions): S3CodeV2 { + if (options?.objectVersion === undefined) { + cdk.Annotations.of(bucket).addWarningV2( + '@aws-cdk/aws-lambda:codeFromBucketObjectVersionNotSpecified', + 'options.objectVersion is not defined for S3Code.fromBucketV2(). The lambda will not be updated automatically if the code in the bucket is updated. ' + + 'This is because CDK/Cloudformation does not track changes on the source S3 Bucket. It is recommended to either use S3Code.fromAsset() instead or set options.objectVersion.', + ); + } + return new S3CodeV2(bucket, key, options); } diff --git a/packages/aws-cdk-lib/aws-lambda/test/code.test.ts b/packages/aws-cdk-lib/aws-lambda/test/code.test.ts index 560673c7694fd..56ce19cd15c0a 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/code.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/code.test.ts @@ -1,7 +1,8 @@ import * as child_process from 'child_process'; import * as path from 'path'; -import { Match, Template } from '../../assertions'; +import { Annotations, Match, Template } from '../../assertions'; import * as ecr from '../../aws-ecr'; +import * as s3 from '../../aws-s3'; import * as cdk from '../../core'; import * as cxapi from '../../cx-api'; import * as lambda from '../lib'; @@ -615,6 +616,96 @@ describe('code', () => { expect(cpMock).toHaveBeenCalledWith('/my/image/path/.', undefined); }); }); + + describe('lambda.Code.fromBucket', () => { + test('fromBucket warns when no objectVersion is set', () => { + // given + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const bucket = new s3.Bucket(stack, 'Bucket'); + + // when + new lambda.Function(stack, 'Fn', { + code: lambda.Code.fromBucket(bucket, 'Object'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_LATEST, + }); + + // then + Annotations.fromStack(stack).hasWarning( + '/Stack/Bucket', + 'objectVersion is not defined for S3Code.fromBucket(). The lambda will not be updated automatically if the code in the bucket is updated. ' + + 'This is because CDK/Cloudformation does not track changes on the source S3 Bucket. It is recommended to either use S3Code.fromAsset() instead or set objectVersion. ' + + '[ack: @aws-cdk/aws-lambda:codeFromBucketObjectVersionNotSpecified]', + ); + }); + + test('fromBucket does not warn when an objectVersion is set', () => { + // given + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const bucket = new s3.Bucket(stack, 'Bucket'); + + // when + new lambda.Function(stack, 'Fn', { + code: lambda.Code.fromBucket(bucket, 'Object', 'v1'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_LATEST, + }); + + // then + Annotations.fromStack(stack).hasNoWarning( + '/Stack/Bucket', + 'objectVersion is not defined for S3Code.fromBucket(). The lambda will not be updated automatically if the code in the bucket is updated. ' + + 'This is because CDK/Cloudformation does not track changes on the source S3 Bucket. It is recommended to either use S3Code.fromAsset() instead or set objectVersion. ' + + '[ack: @aws-cdk/aws-lambda:codeFromBucketObjectVersionNotSpecified]', + ); + }); + + test('fromBucketV2 warns when no objectVersion is set', () => { + // given + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const bucket = new s3.Bucket(stack, 'Bucket'); + + // when + new lambda.Function(stack, 'Fn', { + code: lambda.Code.fromBucketV2(bucket, 'Object'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_LATEST, + }); + + // then + Annotations.fromStack(stack).hasWarning( + '/Stack/Bucket', + 'options.objectVersion is not defined for S3Code.fromBucketV2(). The lambda will not be updated automatically if the code in the bucket is updated. ' + + 'This is because CDK/Cloudformation does not track changes on the source S3 Bucket. It is recommended to either use S3Code.fromAsset() instead or set options.objectVersion. ' + + '[ack: @aws-cdk/aws-lambda:codeFromBucketObjectVersionNotSpecified]', + ); + }); + + test('fromBucketV2 does not warn when an objectVersion is set', () => { + // given + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const bucket = new s3.Bucket(stack, 'Bucket'); + + // when + new lambda.Function(stack, 'Fn', { + code: lambda.Code.fromBucketV2(bucket, 'Object', { objectVersion: 'v1' }), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_LATEST, + }); + + // then + Annotations.fromStack(stack).hasNoWarning( + '/Stack/Bucket', + 'options.objectVersion is not defined for S3Code.fromBucketV2(). The lambda will not be updated automatically if the code in the bucket is updated. ' + + 'This is because CDK/Cloudformation does not track changes on the source S3 Bucket. It is recommended to either use S3Code.fromAsset() instead or set options.objectVersion. ' + + '[ack: @aws-cdk/aws-lambda:codeFromBucketObjectVersionNotSpecified]', + ); + }); + }); }); function defineFunction(code: lambda.Code, runtime: lambda.Runtime = lambda.Runtime.NODEJS_LATEST) {