From 9d6c458284275dec41232f62e4d16401eba9afbc Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 17 Mar 2020 15:45:12 +0200 Subject: [PATCH 01/29] feat(lambda): add alias to latest version through code hash It is a common use case to define an alias for the latest version of a function. In order to do that, one needs to define a Version resource that points to the latest version and then associate an Alias with it. This was not trivial to do so far. Now it is: fn.addAlias('foo') This will define a lambda.Version with a name the derives from the hash of the lambda's source code and then define a lambda.Alias associated with this version object. Since the name of the version resource is based on the hash, when the code changes, a new version will be created automatically. To support this, `lambda.Code.bind()` now returns an optional `codeHash` attribute. It is supported for `lambda.Code.fromAsset` and `lambda.Code.fromInline`, for which we can calculate the source hash based on the content. Resolves #6750 Resolves #5334 --- packages/@aws-cdk/aws-lambda/README.md | 29 ++++ packages/@aws-cdk/aws-lambda/lib/alias.ts | 33 +++-- packages/@aws-cdk/aws-lambda/lib/code.ts | 16 ++- packages/@aws-cdk/aws-lambda/lib/function.ts | 81 +++++++++-- .../test/integ.add-alias.expected.json | 126 ++++++++++++++++++ .../aws-lambda/test/integ.add-alias.ts | 23 ++++ .../@aws-cdk/aws-lambda/test/test.code.ts | 23 ++++ .../@aws-cdk/aws-lambda/test/test.function.ts | 60 +++++++++ .../aws-lambda/test/test.lambda-version.ts | 31 +++++ 9 files changed, 399 insertions(+), 23 deletions(-) create mode 100644 packages/@aws-cdk/aws-lambda/test/integ.add-alias.expected.json create mode 100644 packages/@aws-cdk/aws-lambda/test/integ.add-alias.ts diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index c9e8433930f8a..56b0a3e4d1408 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -49,6 +49,35 @@ to our CDK project directory. This is especially important when we want to share this construct through a library. Different programming languages will have different techniques for bundling resources into libraries. +When using `fromAsset` or `fromInline`, you can obtain the hash of source +through the `function.codeHash` property. This property will return `undefined` +if the code hash cannot be calculated during synthesis (e.g. when using code +from an S3 bucket). + +### Versions and Aliases + +You can define one or more +[aliases](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) +for your AWS Lambda function. A Lambda alias is like a pointer to a specific +Lambda function version. Users can access the function version using the alias +ARN. + +To define an alias that points to the latest version of your function's code, +you can use the `function.addAlias` method like so: + +```ts +const alias = lambdaFunction.addAlias('latest'); +``` + +This will define an alias that points to a +[Version](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html) +resource that will get updated every time your lambda code changes based on your code's hash. + +> Automatically creating version objects based on the code's hash is only supported +> for `lambda.Code.fromAsset` and `lambda.Code.fromInline`. Other types of code +> providers require that you will maintain the `versionName` explicitly when you +> define the alias (and update it manually when your code changes). + ### Layers The `lambda.LayerVersion` class can be used to define Lambda layers and manage diff --git a/packages/@aws-cdk/aws-lambda/lib/alias.ts b/packages/@aws-cdk/aws-lambda/lib/alias.ts index d4dc36cb670c3..f533d19a45e17 100644 --- a/packages/@aws-cdk/aws-lambda/lib/alias.ts +++ b/packages/@aws-cdk/aws-lambda/lib/alias.ts @@ -20,9 +20,9 @@ export interface IAlias extends IFunction { } /** - * Properties for a new Lambda alias + * Options for `lambda.Alias`. */ -export interface AliasProps extends EventInvokeConfigOptions { +export interface AliasOptions extends EventInvokeConfigOptions { /** * Description for the alias * @@ -30,18 +30,6 @@ export interface AliasProps extends EventInvokeConfigOptions { */ readonly description?: string; - /** - * Function version this alias refers to - * - * Use lambda.addVersion() to obtain a new lambda version to refer to. - */ - readonly version: IVersion; - - /** - * Name of this alias - */ - readonly aliasName: string; - /** * Additional versions with individual weights this alias points to * @@ -69,6 +57,23 @@ export interface AliasProps extends EventInvokeConfigOptions { readonly provisionedConcurrentExecutions?: number; } +/** + * Properties for a new Lambda alias + */ +export interface AliasProps extends AliasOptions { + /** + * Name of this alias + */ + readonly aliasName: string; + + /** + * Function version this alias refers to + * + * Use lambda.addVersion() to obtain a new lambda version to refer to. + */ + readonly version: IVersion; +} + export interface AliasAttributes { readonly aliasName: string; readonly aliasVersion: IVersion; diff --git a/packages/@aws-cdk/aws-lambda/lib/code.ts b/packages/@aws-cdk/aws-lambda/lib/code.ts index 03c5b02c9d6b7..17bfff91897fa 100644 --- a/packages/@aws-cdk/aws-lambda/lib/code.ts +++ b/packages/@aws-cdk/aws-lambda/lib/code.ts @@ -1,6 +1,7 @@ import * as s3 from '@aws-cdk/aws-s3'; import * as s3_assets from '@aws-cdk/aws-s3-assets'; import * as cdk from '@aws-cdk/core'; +import * as crypto from 'crypto'; export abstract class Code { /** @@ -104,6 +105,11 @@ export interface CodeConfig { * Inline code (mutually exclusive with `s3Location`). */ readonly inlineCode?: string; + + /** + * The hash of the lambda code (if applicable). + */ + readonly codeHash?: string; } /** @@ -111,6 +117,7 @@ export interface CodeConfig { */ export class S3Code extends Code { public readonly isInline = false; + private bucketName: string; constructor(bucket: s3.IBucket, private key: string, private objectVersion?: string) { @@ -139,6 +146,7 @@ export class S3Code extends Code { */ export class InlineCode extends Code { public readonly isInline = true; + private readonly codeHash: string; constructor(private code: string) { super(); @@ -150,11 +158,14 @@ export class InlineCode extends Code { if (code.length > 4096) { throw new Error("Lambda source is too large, must be <= 4096 but is " + code.length); } + + this.codeHash = crypto.createHash('sha256').update(code).digest('hex'); } public bind(_scope: cdk.Construct): CodeConfig { return { - inlineCode: this.code + inlineCode: this.code, + codeHash: this.codeHash }; } } @@ -164,6 +175,7 @@ export class InlineCode extends Code { */ export class AssetCode extends Code { public readonly isInline = false; + private asset?: s3_assets.Asset; /** @@ -187,6 +199,7 @@ export class AssetCode extends Code { } return { + codeHash: this.asset.sourceHash, s3Location: { bucketName: this.asset.s3BucketName, objectKey: this.asset.s3ObjectKey @@ -246,6 +259,7 @@ export interface CfnParametersCodeProps { */ export class CfnParametersCode extends Code { public readonly isInline = false; + private _bucketNameParam?: cdk.CfnParameter; private _objectKeyParam?: cdk.CfnParameter; diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 2b76f8a21bd80..11f1eed95a1e6 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -4,6 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import * as sqs from '@aws-cdk/aws-sqs'; import { Construct, Duration, Fn, Lazy } from '@aws-cdk/core'; +import { Alias, AliasOptions } from './alias'; import { Code, CodeConfig } from './code'; import { EventInvokeConfigOptions } from './event-invoke-config'; import { IEventSource } from './event-source'; @@ -414,6 +415,14 @@ export class Function extends FunctionBase { public readonly permissionsNode = this.node; + /** + * The hash of the AWS Lambda code. + * + * This only applies to `lambda.Code.fromAsset` and `lambda.Code.fromInline`. + * For other code types this will return `undefined`. + */ + public readonly codeHash?: string; + protected readonly canCreatePermissions = true; private readonly layers: ILayerVersion[] = []; @@ -456,6 +465,7 @@ export class Function extends FunctionBase { verifyCodeConfig(code, props.runtime); this.deadLetterQueue = this.buildDeadLetterQueue(props); + this.codeHash = code.codeHash; const resource: CfnFunction = new CfnFunction(this, 'Resource', { functionName: this.physicalName, @@ -557,26 +567,43 @@ export class Function extends FunctionBase { * 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. + * 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 name A unique name for this version. The version name is not + * specified, a name will automatically be generated based on the code hash of + * the lambda. This means that a new version will automatically be created + * every time the lambda code changes. This is only supported for + * `lambda.Code.fromAsset` and `lambda.Code.fromInline`. Otherwise `name` is + * required. + * + * @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. + * @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. */ public addVersion( - name: string, + name?: string, codeSha256?: string, description?: string, provisionedExecutions?: number, asyncInvokeConfig: EventInvokeConfigOptions = {}): Version { + + if (!name) { + if (!this.codeHash) { + throw new Error(`version name must be provided because the the lambda code hash cannot be calculated. Only "lambda.Code.fromAsset" and "lambda.Code.fromInline" support code hash`); + } + + name = this.codeHash; + } + return new Version(this, 'Version' + name, { lambda: this, codeSha256, @@ -586,6 +613,23 @@ export class Function extends FunctionBase { }); } + /** + * Defines an alias for this function associated with the latest version of + * the function. + * + * @param name The name for this alias. + * @param options Options for the alias. If this function uses assets or + * inline code, do not specify `versionName`. Otherwise, `versionName` is + * required. + */ + public addAlias(name: string, options: AddAliasOptions = { }) { + return new Alias(this, `Alias${name}`, { + version: this.addVersion(options.versionName), + aliasName: name, + ...options + }); + } + /** * The LogGroup where the Lambda function's logs are made available. * @@ -750,3 +794,24 @@ export function verifyCodeConfig(code: CodeConfig, runtime: Runtime) { throw new Error(`Inline source not allowed for ${runtime.name}`); } } + +/** + * Options for `function.addAlias`. + */ +export interface AddAliasOptions extends AliasOptions { + /** + * An explicit name for this version. + * + * It is not recommeneded to specify a name for the version because you will + * need to explicitly update it every time your lambda code changes. If you + * leave this undefined, the framework will automatically create a new version + * every time your lambda code changes. + * + * @default - a name will automatically be generated based on the code hash of + * the lambda. This means that a new version will automatically be created + * every time the lambda code changes. This is only supported for + * `lambda.Code.fromAsset` and `lambda.Code.fromInline`. Otherwise `name` is + * required. + */ + readonly versionName?: string; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.add-alias.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.add-alias.expected.json new file mode 100644 index 0000000000000..cf15a62cf9d7d --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.add-alias.expected.json @@ -0,0 +1,126 @@ +{ + "Resources": { + "MyLambdaServiceRole4539ECB6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyLambdaCCE802FB": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3Bucket66527C9E" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3VersionKey4FEF0FAB" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3VersionKey4FEF0FAB" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.main", + "Role": { + "Fn::GetAtt": [ + "MyLambdaServiceRole4539ECB6", + "Arn" + ] + }, + "Runtime": "python3.6" + }, + "DependsOn": [ + "MyLambdaServiceRole4539ECB6" + ] + }, + "MyLambdaVersiona37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f02EF5512": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "MyLambdaCCE802FB" + } + } + }, + "MyLambdaAliaslatestC8AF3D45": { + "Type": "AWS::Lambda::Alias", + "Properties": { + "FunctionName": { + "Ref": "MyLambdaCCE802FB" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MyLambdaVersiona37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f02EF5512", + "Version" + ] + }, + "Name": "latest" + } + } + }, + "Parameters": { + "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3Bucket66527C9E": { + "Type": "String", + "Description": "S3 bucket for asset \"a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f\"" + }, + "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3VersionKey4FEF0FAB": { + "Type": "String", + "Description": "S3 key for asset version \"a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f\"" + }, + "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fArtifactHashCF3E1D8E": { + "Type": "String", + "Description": "Artifact hash for asset \"a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.add-alias.ts b/packages/@aws-cdk/aws-lambda/test/integ.add-alias.ts new file mode 100644 index 0000000000000..47e39df3769ec --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.add-alias.ts @@ -0,0 +1,23 @@ +import * as cdk from '@aws-cdk/core'; +import * as path from 'path'; +import * as lambda from '../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const handler = new lambda.Function(this, 'MyLambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + handler: 'index.main', + runtime: lambda.Runtime.PYTHON_3_6 + }); + + handler.addAlias('latest'); + } +} + +const app = new cdk.App(); + +new TestStack(app, 'lambda-test-asset-hash'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-lambda/test/test.code.ts b/packages/@aws-cdk/aws-lambda/test/test.code.ts index 21a861c2da5b4..34898e5021095 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.code.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.code.ts @@ -81,6 +81,29 @@ export = { } }, ResourcePart.CompleteDefinition)); test.done(); + }, + + 'codeHash is supported for assets and inline'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const asset = new lambda.Function(stack, 'AssetCode', { + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + + const inline = new lambda.Function(stack, 'InlineCode', { + code: lambda.Code.fromInline('boom boom'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + + // THEN + test.deepEqual(asset.codeHash, '9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232'); + test.deepEqual(inline.codeHash, '58ad733fe276cb7b9b171b0beafad40f43b6d1cd68a1b93327d3655f739dfa0e'); + test.done(); } }, diff --git a/packages/@aws-cdk/aws-lambda/test/test.function.ts b/packages/@aws-cdk/aws-lambda/test/test.function.ts index 6a9e2fa343090..1c947e6b9d9c2 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.function.ts @@ -1,9 +1,11 @@ +import { expect, haveResource } from '@aws-cdk/assert'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import * as _ from 'lodash'; import {Test, testCase} from 'nodeunit'; +import * as path from 'path'; import * as lambda from '../lib'; export = testCase({ @@ -177,6 +179,64 @@ export = testCase({ runtime: lambda.Runtime.PROVIDED, code: lambda.Code.fromInline('foo') }), /Inline source not allowed for/); + test.done(); + }, + + 'codeHash returns a value for supporting assets and inline code'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const asset = new lambda.Function(stack, 'Asset', { + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + const inline = new lambda.Function(stack, 'Inline', { + code: lambda.Code.fromInline('boom bam'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + const params = new lambda.Function(stack, 'CfnParams', { + code: lambda.Code.fromCfnParameters(), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + + // THEN + test.deepEqual(asset.codeHash, '9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232'); + test.deepEqual(inline.codeHash, 'e07117e0bca42f0f84f0b2cf044d45352808b2dbdde5358c0b9f770166cb1515'); + test.deepEqual(params.codeHash, undefined); + test.done(); + }, + + 'addAlias defines an alias against the latest version of your function'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('inline horray'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + + // WHEN + fn.addAlias('latest'); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::Alias', { + FunctionName: { + Ref: "MyFunction3BAA72D1" + }, + FunctionVersion: { + "Fn::GetAtt": [ + "MyFunctionVersion756d30f6e614451d9c4fed107d9c1ee3030fabf54768b61af9c54f8b2d90ad0c14F79D34", + "Version" + ] + }, + Name: "latest" + })); + test.done(); } + }); diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts index 80c02e56c9966..a93a57ac554f4 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts @@ -111,6 +111,37 @@ export = { MaximumRetryAttempts: 0 })); + test.done(); + }, + + 'version name can be omitted if code hash is supported'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('i support code hash'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + + // WHEN + const version = fn.addVersion(); + + // THEN + test.deepEqual(stack.resolve((version.node.defaultChild as lambda.CfnVersion).logicalId), 'MyFunctionVersion3881c5a687768784b8ba777dcd8ee69aadbd8bc1f5dfd01d5d085e32654afb8aD80517F5'); + test.done(); + }, + + 'version name cannot be omitted if code hash is not supported'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromCfnParameters(), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + + // THEN + test.throws(() => fn.addVersion(), /version name must be provided because the the lambda code hash cannot be calculated. Only "lambda.Code.fromAsset" and "lambda.Code.fromInline" support code hash/); test.done(); } }; From 4ba3d1f199b38c56a80c8ad1b2ebe6de5c3a35f6 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 17 Mar 2020 20:56:50 +0200 Subject: [PATCH 02/29] Update packages/@aws-cdk/aws-lambda/lib/code.ts Co-Authored-By: Niranjan Jayakar --- packages/@aws-cdk/aws-lambda/lib/code.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/code.ts b/packages/@aws-cdk/aws-lambda/lib/code.ts index 17bfff91897fa..4e12c16db2a8d 100644 --- a/packages/@aws-cdk/aws-lambda/lib/code.ts +++ b/packages/@aws-cdk/aws-lambda/lib/code.ts @@ -107,7 +107,7 @@ export interface CodeConfig { readonly inlineCode?: string; /** - * The hash of the lambda code (if applicable). + * The hash of the lambda code (if applicable). `undefined` if it cannot be computed. */ readonly codeHash?: string; } From e5b0e259bc05d7f9d1d3366dd8be5470cef1e2f8 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 23 Mar 2020 11:08:39 +0200 Subject: [PATCH 03/29] change approach to "currentVersion" --- packages/@aws-cdk/aws-lambda/README.md | 56 ++++-- packages/@aws-cdk/aws-lambda/lib/code.ts | 3 +- .../@aws-cdk/aws-lambda/lib/function-base.ts | 10 +- .../@aws-cdk/aws-lambda/lib/function-hash.ts | 30 ++++ packages/@aws-cdk/aws-lambda/lib/function.ts | 169 +++++++++--------- .../@aws-cdk/aws-lambda/lib/lambda-version.ts | 61 +++++-- packages/@aws-cdk/aws-lambda/lib/util.ts | 11 ++ .../aws-lambda/test/integ.add-alias.ts | 23 --- ...on => integ.current-version.expected.json} | 35 ++-- .../aws-lambda/test/integ.current-version.ts | 26 +++ .../@aws-cdk/aws-lambda/test/test.code.ts | 19 +- .../aws-lambda/test/test.function-hash.ts | 112 ++++++++++++ .../@aws-cdk/aws-lambda/test/test.function.ts | 120 +++++++------ .../aws-lambda/test/test.lambda-version.ts | 40 ++--- 14 files changed, 493 insertions(+), 222 deletions(-) create mode 100644 packages/@aws-cdk/aws-lambda/lib/function-hash.ts create mode 100644 packages/@aws-cdk/aws-lambda/lib/util.ts delete mode 100644 packages/@aws-cdk/aws-lambda/test/integ.add-alias.ts rename packages/@aws-cdk/aws-lambda/test/{integ.add-alias.expected.json => integ.current-version.expected.json} (61%) create mode 100644 packages/@aws-cdk/aws-lambda/test/integ.current-version.ts create mode 100644 packages/@aws-cdk/aws-lambda/test/test.function-hash.ts diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index 56b0a3e4d1408..6367ea1b1cf9f 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -56,27 +56,61 @@ from an S3 bucket). ### Versions and Aliases +You can use +[versions](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html) +to manage the deployment of your AWS Lambda functions. For example, you can +publish a new version of a function for beta testing without affecting users of +the stable production version. + +The function version includes the following information: + +- The function code and all associated dependencies. +- The Lambda runtime that executes the function. +- All of the function settings, including the environment variables. +- A unique Amazon Resource Name (ARN) to identify this version of the function. + You can define one or more [aliases](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) for your AWS Lambda function. A Lambda alias is like a pointer to a specific Lambda function version. Users can access the function version using the alias ARN. -To define an alias that points to the latest version of your function's code, -you can use the `function.addAlias` method like so: +The `fn.currentVersion` property can be used to obtain a `lambda.Version` +resource that represents the AWS Lambda function defined in your application. +Any change to your function's code or configuration will result in the creation +of a new version resource. You can specify options for this version through the +`currentVersionOptions` property. + +> The `currentVersion` property is only supported when your AWS Lambda function +> uses either `lambda.Code.fromAsset` or `lambda.Code.fromInline`. Other types +> of code providers (such as `lambda.Code.fromBucket`) require that you define a +> `lambda.Version` resource directly since the CDK is unable to determine if +> their contents had changed. + +The `version.addAlias()` method can be used to define an AWS Lambda alias that +points to a specific version. + +The following example defines an alias named `live` which will always point to a +version that represents the function as defined in your CDK app. When you change +your lambda code or configuration, a new resource will be created. Since the +version's `removalPolicy` option is set to `RETAIN`, old versions will not be +deleted (the default is `DESTROY`): ```ts -const alias = lambdaFunction.addAlias('latest'); -``` +const fn = new lambda.Function(this, 'MyFunction', { + // ... + currentVersionOptions: { + removalPolicy: RemovalPolicy.RETAIN // retain old versions + } +}); -This will define an alias that points to a -[Version](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html) -resource that will get updated every time your lambda code changes based on your code's hash. +fn.currentVersion.addAlias('live'); +``` -> Automatically creating version objects based on the code's hash is only supported -> for `lambda.Code.fromAsset` and `lambda.Code.fromInline`. Other types of code -> providers require that you will maintain the `versionName` explicitly when you -> define the alias (and update it manually when your code changes). +> NOTE: The `fn.latestVersion` property returns a `lambda.IVersion` which +> represents the `$LATEST` pseudo-version. Most AWS services require a specific +> AWS Lambda version, and won't allow you to use `$LATEST`. Therefore, you would +> normally want to use `lambda.currentVersion`. ### Layers diff --git a/packages/@aws-cdk/aws-lambda/lib/code.ts b/packages/@aws-cdk/aws-lambda/lib/code.ts index 4e12c16db2a8d..0f560914acef4 100644 --- a/packages/@aws-cdk/aws-lambda/lib/code.ts +++ b/packages/@aws-cdk/aws-lambda/lib/code.ts @@ -107,7 +107,8 @@ export interface CodeConfig { readonly inlineCode?: string; /** - * The hash of the lambda code (if applicable). `undefined` if it cannot be computed. + * The hash of the lambda code (if applicable) or `undefined` if it cannot be + * computed. */ readonly codeHash?: string; } diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index 2207db443f1b4..6fc7b9bb5e7c6 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -2,12 +2,14 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { ConstructNode, IResource, Resource } from '@aws-cdk/core'; +import { AliasOptions } from './alias'; import { EventInvokeConfig, EventInvokeConfigOptions } from './event-invoke-config'; import { IEventSource } from './event-source'; import { EventSourceMapping, EventSourceMappingOptions } from './event-source-mapping'; import { IVersion } from './lambda-version'; import { CfnPermission } from './lambda.generated'; import { Permission } from './permission'; +import { addAlias } from './util'; export interface IFunction extends IResource, ec2.IConnectable, iam.IGrantable { @@ -102,7 +104,7 @@ export interface IFunction extends IResource, ec2.IConnectable, iam.IGrantable { /** * Configures options for asynchronous invocation. */ - configureAsyncInvoke(options: EventInvokeConfigOptions): void + configureAsyncInvoke(options: EventInvokeConfigOptions): void; } /** @@ -235,7 +237,7 @@ export abstract class FunctionBase extends Resource implements IFunction { } public get latestVersion(): IVersion { - // Dynamic to avoid invinite recursion when creating the LatestVersion instance... + // Dynamic to avoid infinite recursion when creating the LatestVersion instance... return new LatestVersion(this); } @@ -393,4 +395,8 @@ class LatestVersion extends FunctionBase implements IVersion { public get role() { return this.lambda.role; } + + public addAlias(aliasName: string, options: AliasOptions = {}) { + return addAlias(this, this, aliasName, options); + } } diff --git a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts new file mode 100644 index 0000000000000..1f6ed43ce4e0c --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts @@ -0,0 +1,30 @@ +import { CfnResource, Stack } from "@aws-cdk/core"; +import * as crypto from 'crypto'; +import { Function as LambdaFunction } from "./function"; + +export function calculateFunctionHash(fn: LambdaFunction) { + const stack = Stack.of(fn); + + const functionResource = fn.node.defaultChild as CfnResource; + + if (!fn._codeHash) { + throw new Error(`assertion failed: codeHash is expected to have a value if currentVersion is defined`); + } + + // render the cloudformation resource from this function + const config = stack.resolve((functionResource as any)._toCloudFormation()); + + const hash = crypto.createHash('md5'); + hash.update(JSON.stringify({ + code: fn._codeHash, + config + })); + + return hash.digest('hex'); +} + +export function trimFromStart(s: string, maxLength: number) { + const desiredLength = Math.min(maxLength, s.length); + const newStart = s.length - desiredLength; + return s.substring(newStart); +} \ 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 11f1eed95a1e6..51a1bbeae8c8b 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -3,13 +3,13 @@ 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 sqs from '@aws-cdk/aws-sqs'; -import { Construct, Duration, Fn, Lazy } from '@aws-cdk/core'; -import { Alias, AliasOptions } from './alias'; +import { CfnResource, Construct, Duration, Fn, Lazy, Stack } from '@aws-cdk/core'; import { Code, CodeConfig } from './code'; import { EventInvokeConfigOptions } from './event-invoke-config'; import { IEventSource } from './event-source'; import { FunctionAttributes, FunctionBase, IFunction } from './function-base'; -import { Version } from './lambda-version'; +import { calculateFunctionHash, trimFromStart } from './function-hash'; +import { Version, VersionOptions } from './lambda-version'; import { CfnFunction } from './lambda.generated'; import { ILayerVersion } from './layers'; import { LogRetention } from './log-retention'; @@ -225,6 +225,12 @@ export interface FunctionOptions extends EventInvokeConfigOptions { * @default - A new role is created. */ readonly logRetentionRole?: iam.IRole; + + /** + * Options for the `lambda.Version` resource automatically created by the + * `fn.currentVersion` method. + */ + readonly currentVersionOptions?: VersionOptions; } export interface FunctionProps extends FunctionOptions { @@ -267,6 +273,55 @@ export interface FunctionProps extends FunctionOptions { * library. */ export class Function extends FunctionBase { + + /** + * Returns a `lambda.Version` which represents the current version of this + * Lambda function. A new version will be created every time the function's + * code or it's configuration changes. + * + * To enable this, set `currentVersion: true` attribute to `true` when creating + * the `lambda.Function` object. + */ + public get currentVersion(): Version { + if (this._currentVersion) { + return this._currentVersion; + } + + if (!this._codeHash) { + throw new Error( + `cannot automatically create a version resource for this function since the hash of the code cannot be calculated. ` + + `This is only supported for "lambda.Code.fromAsset" and "lambda.Code.fromInline"`); + } + + this._currentVersion = new Version(this, `CurrentVersion`, { + lambda: this, + description: `${this.node.path}.currentVersion (created by AWS CDK)`, + ...this.currentVersionOptions + }); + + return this._currentVersion; + } + + /** + * 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 { + if (!this._logGroup) { + const logretention = new 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; + } public static fromFunctionArn(scope: Construct, id: string, functionArn: string): IFunction { return Function.fromFunctionAttributes(scope, id, { functionArn }); } @@ -416,12 +471,9 @@ export class Function extends FunctionBase { public readonly permissionsNode = this.node; /** - * The hash of the AWS Lambda code. - * - * This only applies to `lambda.Code.fromAsset` and `lambda.Code.fromInline`. - * For other code types this will return `undefined`. + * @internal */ - public readonly codeHash?: string; + public _codeHash?: string; protected readonly canCreatePermissions = true; @@ -434,6 +486,9 @@ export class Function extends FunctionBase { */ private readonly environment: { [key: string]: string }; + private readonly currentVersionOptions?: VersionOptions; + private _currentVersion?: Version; + constructor(scope: Construct, id: string, props: FunctionProps) { super(scope, id, { physicalName: props.functionName, @@ -465,7 +520,7 @@ export class Function extends FunctionBase { verifyCodeConfig(code, props.runtime); this.deadLetterQueue = this.buildDeadLetterQueue(props); - this.codeHash = code.codeHash; + this._codeHash = code.codeHash; const resource: CfnFunction = new CfnFunction(this, 'Resource', { functionName: this.physicalName, @@ -530,6 +585,8 @@ export class Function extends FunctionBase { retryAttempts: props.retryAttempts, }); } + + this.currentVersionOptions = props.currentVersionOptions; } /** @@ -573,13 +630,7 @@ export class Function extends FunctionBase { * 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. The version name is not - * specified, a name will automatically be generated based on the code hash of - * the lambda. This means that a new version will automatically be created - * every time the lambda code changes. This is only supported for - * `lambda.Code.fromAsset` and `lambda.Code.fromInline`. Otherwise `name` is - * required. - * + * @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. @@ -588,22 +639,20 @@ export class Function extends FunctionBase { * @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. */ public addVersion( - name?: string, + name: string, codeSha256?: string, description?: string, provisionedExecutions?: number, asyncInvokeConfig: EventInvokeConfigOptions = {}): Version { - if (!name) { - if (!this.codeHash) { - throw new Error(`version name must be provided because the the lambda code hash cannot be calculated. Only "lambda.Code.fromAsset" and "lambda.Code.fromInline" support code hash`); - } - - name = this.codeHash; - } - return new Version(this, 'Version' + name, { lambda: this, codeSha256, @@ -613,42 +662,21 @@ export class Function extends FunctionBase { }); } - /** - * Defines an alias for this function associated with the latest version of - * the function. - * - * @param name The name for this alias. - * @param options Options for the alias. If this function uses assets or - * inline code, do not specify `versionName`. Otherwise, `versionName` is - * required. - */ - public addAlias(name: string, options: AddAliasOptions = { }) { - return new Alias(this, `Alias${name}`, { - version: this.addVersion(options.versionName), - aliasName: name, - ...options - }); - } + protected prepare() { + super.prepare(); - /** - * 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 { - if (!this._logGroup) { - const logretention = new LogRetention(this, 'LogRetention', { - logGroupName: `/aws/lambda/${this.functionName}`, - retention: logs.RetentionDays.INFINITE, - }); - this._logGroup = logs.LogGroup.fromLogGroupArn(this, `${this.node.id}-LogGroup`, logretention.logGroupArn); + // if we have a current version resource, override it's logical id + // so that it includes the hash of the function code and it's configuration. + if (this._currentVersion) { + const stack = Stack.of(this); + const cfn = this._currentVersion.node.defaultChild as CfnResource; + const originalLogicalId: string = stack.resolve(cfn.logicalId); + + const hash = calculateFunctionHash(this); + + const logicalId = trimFromStart(originalLogicalId, 255 - 32); + cfn.overrideLogicalId(`${logicalId}${hash}`); } - return this._logGroup; } private renderEnvironment() { @@ -792,26 +820,5 @@ export function verifyCodeConfig(code: CodeConfig, runtime: Runtime) { // if this is inline code, check that the runtime supports if (code.inlineCode && !runtime.supportsInlineCode) { throw new Error(`Inline source not allowed for ${runtime.name}`); - } -} + }} -/** - * Options for `function.addAlias`. - */ -export interface AddAliasOptions extends AliasOptions { - /** - * An explicit name for this version. - * - * It is not recommeneded to specify a name for the version because you will - * need to explicitly update it every time your lambda code changes. If you - * leave this undefined, the framework will automatically create a new version - * every time your lambda code changes. - * - * @default - a name will automatically be generated based on the code hash of - * the lambda. This means that a new version will automatically be created - * every time the lambda code changes. This is only supported for - * `lambda.Code.fromAsset` and `lambda.Code.fromInline`. Otherwise `name` is - * required. - */ - readonly versionName?: string; -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index bd5c132f89e44..bd3cb0b7332a0 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -1,9 +1,11 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; -import { Construct, Fn } from '@aws-cdk/core'; +import { Construct, Fn, RemovalPolicy } from '@aws-cdk/core'; +import { Alias, AliasOptions } from './alias'; import { EventInvokeConfigOptions } from './event-invoke-config'; import { Function } from './function'; import { IFunction, QualifiedFunctionBase } from './function-base'; import { CfnVersion } from './lambda.generated'; +import { addAlias } from './util'; export interface IVersion extends IFunction { /** @@ -16,12 +18,16 @@ export interface IVersion extends IFunction { * The underlying AWS Lambda function. */ readonly lambda: IFunction; + + /** + * Defines an alias for this version. + * @param aliasName The name of the alias + * @param options Alias options + */ + addAlias(aliasName: string, options?: AliasOptions): Alias; } -/** - * Properties for a new Lambda version - */ -export interface VersionProps extends EventInvokeConfigOptions { +export interface VersionOptions extends EventInvokeConfigOptions { /** * SHA256 of the version of the Lambda source code * @@ -38,17 +44,30 @@ export interface VersionProps extends EventInvokeConfigOptions { */ readonly description?: string; - /** - * Function to get the value of - */ - readonly lambda: IFunction; - /** * Specifies a provisioned concurrency configuration for a function's version. * * @default No provisioned concurrency */ readonly provisionedConcurrentExecutions?: number; + + /** + * Whether to ratin old versions of this function when a new version is + * created. + * + * @default RemovalPolicy.DESTROY + */ + readonly removalPolicy?: RemovalPolicy; +} + +/** + * Properties for a new Lambda version + */ +export interface VersionProps extends VersionOptions { + /** + * Function to get the value of + */ + readonly lambda: IFunction; } export interface VersionAttributes { @@ -102,6 +121,10 @@ export class Version extends QualifiedFunctionBase implements IVersion { protected readonly qualifier = version; protected readonly canCreatePermissions = false; + + public addAlias(name: string, opts: AliasOptions = { }): Alias { + return addAlias(this, this, name, opts); + } } return new Import(scope, id); } @@ -117,6 +140,10 @@ export class Version extends QualifiedFunctionBase implements IVersion { protected readonly qualifier = attrs.version; protected readonly canCreatePermissions = false; + + public addAlias(name: string, opts: AliasOptions = { }): Alias { + return addAlias(this, this, name, opts); + } } return new Import(scope, id); } @@ -141,6 +168,10 @@ export class Version extends QualifiedFunctionBase implements IVersion { provisionedConcurrencyConfig: this.determineProvisionedConcurrency(props) }); + version.applyRemovalPolicy(props.removalPolicy, { + default: RemovalPolicy.DESTROY + }); + this.version = version.attrVersion; this.functionArn = version.ref; this.functionName = `${this.lambda.functionName}:${this.version}`; @@ -178,6 +209,15 @@ export class Version extends QualifiedFunctionBase implements IVersion { }); } + /** + * Defines an alias for this version. + * @param aliasName The name of the alias (e.g. "live") + * @param options Alias options + */ + public addAlias(aliasName: string, options: AliasOptions = { }): Alias { + return addAlias(this, this, aliasName, options); + } + /** * Validate that the provisionedConcurrentExecutions makes sense * @@ -212,3 +252,4 @@ export class Version extends QualifiedFunctionBase implements IVersion { export function extractQualifierFromArn(arn: string) { return Fn.select(7, Fn.split(':', arn)); } + diff --git a/packages/@aws-cdk/aws-lambda/lib/util.ts b/packages/@aws-cdk/aws-lambda/lib/util.ts new file mode 100644 index 0000000000000..317699450b436 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/lib/util.ts @@ -0,0 +1,11 @@ +import { Construct } from "@aws-cdk/core"; +import { Alias, AliasOptions } from "./alias"; +import { IVersion } from "./lambda-version"; + +export function addAlias(scope: Construct, version: IVersion, aliasName: string, options: AliasOptions = {}) { + return new Alias(scope, `Alias${aliasName}`, { + aliasName, + version, + ...options + }); +} diff --git a/packages/@aws-cdk/aws-lambda/test/integ.add-alias.ts b/packages/@aws-cdk/aws-lambda/test/integ.add-alias.ts deleted file mode 100644 index 47e39df3769ec..0000000000000 --- a/packages/@aws-cdk/aws-lambda/test/integ.add-alias.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as cdk from '@aws-cdk/core'; -import * as path from 'path'; -import * as lambda from '../lib'; - -class TestStack extends cdk.Stack { - constructor(scope: cdk.App, id: string) { - super(scope, id); - - const handler = new lambda.Function(this, 'MyLambda', { - code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), - handler: 'index.main', - runtime: lambda.Runtime.PYTHON_3_6 - }); - - handler.addAlias('latest'); - } -} - -const app = new cdk.App(); - -new TestStack(app, 'lambda-test-asset-hash'); - -app.synth(); diff --git a/packages/@aws-cdk/aws-lambda/test/integ.add-alias.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json similarity index 61% rename from packages/@aws-cdk/aws-lambda/test/integ.add-alias.expected.json rename to packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json index cf15a62cf9d7d..65a4f95d0834e 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.add-alias.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3Bucket66527C9E" + "Ref": "AssetParameters45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2dS3Bucket34E3DBD0" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3VersionKey4FEF0FAB" + "Ref": "AssetParameters45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2dS3VersionKey585C4BED" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3VersionKey4FEF0FAB" + "Ref": "AssetParameters45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2dS3VersionKey585C4BED" } ] } @@ -79,21 +79,24 @@ "Arn" ] }, - "Runtime": "python3.6" + "Runtime": "python3.8" }, "DependsOn": [ "MyLambdaServiceRole4539ECB6" ] }, - "MyLambdaVersiona37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f02EF5512": { + "MyLambdaCurrentVersionE7A382CC73a23add9934a83560eb6afdb1ec3e65": { "Type": "AWS::Lambda::Version", "Properties": { "FunctionName": { "Ref": "MyLambdaCCE802FB" - } - } + }, + "Description": "lambda-test-current-version/MyLambda.currentVersion (created by AWS CDK)" + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, - "MyLambdaAliaslatestC8AF3D45": { + "MyLambdaCurrentVersionAliaslive9151E913": { "Type": "AWS::Lambda::Alias", "Properties": { "FunctionName": { @@ -101,26 +104,26 @@ }, "FunctionVersion": { "Fn::GetAtt": [ - "MyLambdaVersiona37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f02EF5512", + "MyLambdaCurrentVersionE7A382CC73a23add9934a83560eb6afdb1ec3e65", "Version" ] }, - "Name": "latest" + "Name": "live" } } }, "Parameters": { - "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3Bucket66527C9E": { + "AssetParameters45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2dS3Bucket34E3DBD0": { "Type": "String", - "Description": "S3 bucket for asset \"a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f\"" + "Description": "S3 bucket for asset \"45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2d\"" }, - "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fS3VersionKey4FEF0FAB": { + "AssetParameters45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2dS3VersionKey585C4BED": { "Type": "String", - "Description": "S3 key for asset version \"a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f\"" + "Description": "S3 key for asset version \"45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2d\"" }, - "AssetParametersa37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5fArtifactHashCF3E1D8E": { + "AssetParameters45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2dArtifactHash20CDD3D4": { "Type": "String", - "Description": "Artifact hash for asset \"a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f\"" + "Description": "Artifact hash for asset \"45f085ecc03a1a22cf003fba3fab28e660c92bcfcd4d0c01b62c7cd191070a2d\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts b/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts new file mode 100644 index 0000000000000..e017cdb35cfa5 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts @@ -0,0 +1,26 @@ +import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; +import * as path from 'path'; +import * as lambda from '../lib'; + +class TestStack extends Stack { + constructor(scope: App, id: string) { + super(scope, id); + + const handler = new lambda.Function(this, 'MyLambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'layer-code')), + handler: 'index.main', + runtime: lambda.Runtime.PYTHON_3_8, + currentVersionOptions: { + removalPolicy: RemovalPolicy.RETAIN, + } + }); + + handler.currentVersion.addAlias('live'); + } +} + +const app = new App(); + +new TestStack(app, 'lambda-test-current-version'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-lambda/test/test.code.ts b/packages/@aws-cdk/aws-lambda/test/test.code.ts index 34898e5021095..6840b67c959d6 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.code.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.code.ts @@ -1,4 +1,5 @@ import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Test } from 'nodeunit'; @@ -100,9 +101,23 @@ export = { handler: 'index.handler' }); + const bucket = new lambda.Function(stack, 'S3Code', { + code: lambda.Code.fromBucket(s3.Bucket.fromBucketName(stack, 'Bucket', 'bucket'), 'key'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + + const params = new lambda.Function(stack, 'CfnParams', { + code: lambda.Code.fromCfnParameters(), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + // THEN - test.deepEqual(asset.codeHash, '9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232'); - test.deepEqual(inline.codeHash, '58ad733fe276cb7b9b171b0beafad40f43b6d1cd68a1b93327d3655f739dfa0e'); + test.deepEqual(asset._codeHash, '9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232'); + test.deepEqual(inline._codeHash, '58ad733fe276cb7b9b171b0beafad40f43b6d1cd68a1b93327d3655f739dfa0e'); + test.deepEqual(bucket._codeHash, undefined); + test.deepEqual(params._codeHash, undefined); test.done(); } }, diff --git a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts b/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts new file mode 100644 index 0000000000000..8ed1148babd3d --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts @@ -0,0 +1,112 @@ +import { Stack } from '@aws-cdk/core'; +import { Test } from 'nodeunit'; +import * as path from 'path'; +import * as lambda from '../lib'; +import { calculateFunctionHash, trimFromStart } from '../lib/function-hash'; + +export = { + "trimFromStart": { + + 'trim not needed'(test: Test) { + test.deepEqual(trimFromStart('foo', 100), 'foo'); + test.deepEqual(trimFromStart('foo', 3), 'foo'); + test.deepEqual(trimFromStart('', 3), ''); + test.done(); + }, + + 'trim required'(test: Test) { + test.deepEqual(trimFromStart('hello', 3), 'llo'); + test.deepEqual(trimFromStart('hello', 4), 'ello'); + test.deepEqual(trimFromStart('hello', 1), 'o'); + test.done(); + } + + }, + + "calcHash": { + 'same configuration and code yields the same hash'(test: Test) { + const stack1 = new Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction1', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + handler: 'index.handler' + }); + + const stack2 = new Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction1', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + handler: 'index.handler' + }); + + test.deepEqual(calculateFunctionHash(fn1), 'a1dd0e860a511e65bf720e3bd0f6b6a9'); + test.deepEqual(calculateFunctionHash(fn2), 'a1dd0e860a511e65bf720e3bd0f6b6a9'); + test.done(); + }, + }, + + 'code impacts hash'(test: Test) { + const stack1 = new Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction1', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler' + }); + + test.notDeepEqual(calculateFunctionHash(fn1), 'a1dd0e860a511e65bf720e3bd0f6b6a9'); + test.deepEqual(calculateFunctionHash(fn1), '1ad32fcab0aa68bf36825df8e6f0a7a2'); + test.done(); + }, + + 'environment variables impact hash'(test: Test) { + const stack1 = new Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Foo: 'bar' + } + }); + + const stack2 = new Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Foo: 'beer' + } + }); + + test.deepEqual(calculateFunctionHash(fn1), 'ea4daca738e83756eec5a3a3c806d54d'); + test.deepEqual(calculateFunctionHash(fn2), '2cb1ed852c739c60254b3bbfb258e513'); + test.done(); + }, + + 'runtime impacts hash'(test: Test) { + const stack1 = new Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Foo: 'bar' + } + }); + + const stack2 = new Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Foo: 'beer' + } + }); + + test.deepEqual(calculateFunctionHash(fn1), 'ea4daca738e83756eec5a3a3c806d54d'); + test.deepEqual(calculateFunctionHash(fn2), '4bdbec98b3c838410b5637fb71101514'); + test.done(); + } +}; diff --git a/packages/@aws-cdk/aws-lambda/test/test.function.ts b/packages/@aws-cdk/aws-lambda/test/test.function.ts index 1c947e6b9d9c2..71ac3c3f01399 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.function.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveOutput } from '@aws-cdk/assert'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -7,6 +7,7 @@ import * as _ from 'lodash'; import {Test, testCase} from 'nodeunit'; import * as path from 'path'; import * as lambda from '../lib'; +import { CfnOutput } from '@aws-cdk/core'; export = testCase({ 'add incompatible layer'(test: Test) { @@ -182,61 +183,70 @@ export = testCase({ test.done(); }, - 'codeHash returns a value for supporting assets and inline code'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); + 'currentVersion': { + + 'cannot be created for unsupported lambda.Code types'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const fn = new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromCfnParameters() + }); + + // THEN + test.throws(() => fn.currentVersion, /cannot automatically create a version resource for this function/); + test.done(); + }, + + // see test.function-hash.ts for more coverage for this + 'logical id of version is based on the function hash'(test: Test) { + // GIVEN + const stack1 = new cdk.Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + environment: { + FOO: 'bar' + } + }); + const stack2 = new cdk.Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + environment: { + FOO: 'bear' + } + }); + + // WHEN + new CfnOutput(stack1, 'CurrentVersionArn', { + value: fn1.currentVersion.functionArn + }); + new CfnOutput(stack2, 'CurrentVersionArn', { + value: fn2.currentVersion.functionArn + }); + + // THEN + expect(stack1).to(haveOutput({ + outputName: 'CurrentVersionArn', + outputValue: { + Ref: "MyFunctionCurrentVersion197490AFa10cabe18b67f28a68a1ad20c7468ba6" + } + })); + expect(stack2).to(haveOutput({ + outputName: 'CurrentVersionArn', + outputValue: { + Ref: "MyFunctionCurrentVersion197490AF35a71af54fb82ee3ff968834b82d088c" + } + })); + test.done(); + } - // WHEN - const asset = new lambda.Function(stack, 'Asset', { - code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); - const inline = new lambda.Function(stack, 'Inline', { - code: lambda.Code.fromInline('boom bam'), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); - const params = new lambda.Function(stack, 'CfnParams', { - code: lambda.Code.fromCfnParameters(), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); - - // THEN - test.deepEqual(asset.codeHash, '9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232'); - test.deepEqual(inline.codeHash, 'e07117e0bca42f0f84f0b2cf044d45352808b2dbdde5358c0b9f770166cb1515'); - test.deepEqual(params.codeHash, undefined); - test.done(); }, - 'addAlias defines an alias against the latest version of your function'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'MyFunction', { - code: lambda.Code.fromInline('inline horray'), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); - - // WHEN - fn.addAlias('latest'); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Alias', { - FunctionName: { - Ref: "MyFunction3BAA72D1" - }, - FunctionVersion: { - "Fn::GetAtt": [ - "MyFunctionVersion756d30f6e614451d9c4fed107d9c1ee3030fabf54768b61af9c54f8b2d90ad0c14F79D34", - "Version" - ] - }, - Name: "latest" - })); - - test.done(); - } - }); diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts index a93a57ac554f4..3d083063ba884 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts @@ -114,34 +114,32 @@ export = { test.done(); }, - 'version name can be omitted if code hash is supported'(test: Test) { + 'addAlias can be used to add an alias that points to a version'(test: Test) { // GIVEN const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'MyFunction', { - code: lambda.Code.fromInline('i support code hash'), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + const fn = new lambda.Function(stack, 'Fn', { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromInline('foo'), }); + const version = fn.currentVersion; // WHEN - const version = fn.addVersion(); - - // THEN - test.deepEqual(stack.resolve((version.node.defaultChild as lambda.CfnVersion).logicalId), 'MyFunctionVersion3881c5a687768784b8ba777dcd8ee69aadbd8bc1f5dfd01d5d085e32654afb8aD80517F5'); - test.done(); - }, - - 'version name cannot be omitted if code hash is not supported'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'MyFunction', { - code: lambda.Code.fromCfnParameters(), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); + version.addAlias('foo'); // THEN - test.throws(() => fn.addVersion(), /version name must be provided because the the lambda code hash cannot be calculated. Only "lambda.Code.fromAsset" and "lambda.Code.fromInline" support code hash/); + expect(stack).to(haveResource('AWS::Lambda::Alias', { + "FunctionName": { + "Ref": "Fn9270CBC0" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "FnCurrentVersion17A89ABB3127ebe0d45a77e18d3b1ca1c6c8c55c", + "Version" + ] + }, + "Name": "foo" + })); test.done(); } }; From 721f2d71b29c9a891625cf8df44ab98299f66295 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 23 Mar 2020 11:26:02 +0200 Subject: [PATCH 04/29] get rid of codeHash --- packages/@aws-cdk/aws-lambda/lib/code.ts | 12 ------ .../@aws-cdk/aws-lambda/lib/function-hash.ts | 9 +---- packages/@aws-cdk/aws-lambda/lib/function.ts | 16 +------- .../@aws-cdk/aws-lambda/test/test.code.ts | 37 ------------------- .../aws-lambda/test/test.function-hash.ts | 36 ++++++++++++++---- .../@aws-cdk/aws-lambda/test/test.function.ts | 21 +---------- .../aws-lambda/test/test.lambda-version.ts | 2 +- 7 files changed, 34 insertions(+), 99 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/code.ts b/packages/@aws-cdk/aws-lambda/lib/code.ts index 0f560914acef4..3e1be704f6104 100644 --- a/packages/@aws-cdk/aws-lambda/lib/code.ts +++ b/packages/@aws-cdk/aws-lambda/lib/code.ts @@ -1,7 +1,6 @@ import * as s3 from '@aws-cdk/aws-s3'; import * as s3_assets from '@aws-cdk/aws-s3-assets'; import * as cdk from '@aws-cdk/core'; -import * as crypto from 'crypto'; export abstract class Code { /** @@ -105,12 +104,6 @@ export interface CodeConfig { * Inline code (mutually exclusive with `s3Location`). */ readonly inlineCode?: string; - - /** - * The hash of the lambda code (if applicable) or `undefined` if it cannot be - * computed. - */ - readonly codeHash?: string; } /** @@ -147,7 +140,6 @@ export class S3Code extends Code { */ export class InlineCode extends Code { public readonly isInline = true; - private readonly codeHash: string; constructor(private code: string) { super(); @@ -159,14 +151,11 @@ export class InlineCode extends Code { if (code.length > 4096) { throw new Error("Lambda source is too large, must be <= 4096 but is " + code.length); } - - this.codeHash = crypto.createHash('sha256').update(code).digest('hex'); } public bind(_scope: cdk.Construct): CodeConfig { return { inlineCode: this.code, - codeHash: this.codeHash }; } } @@ -200,7 +189,6 @@ export class AssetCode extends Code { } return { - codeHash: this.asset.sourceHash, s3Location: { bucketName: this.asset.s3BucketName, objectKey: this.asset.s3ObjectKey diff --git a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts index 1f6ed43ce4e0c..a0ca9b8becd92 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts @@ -7,18 +7,11 @@ export function calculateFunctionHash(fn: LambdaFunction) { const functionResource = fn.node.defaultChild as CfnResource; - if (!fn._codeHash) { - throw new Error(`assertion failed: codeHash is expected to have a value if currentVersion is defined`); - } - // render the cloudformation resource from this function const config = stack.resolve((functionResource as any)._toCloudFormation()); const hash = crypto.createHash('md5'); - hash.update(JSON.stringify({ - code: fn._codeHash, - config - })); + hash.update(JSON.stringify(config)); return hash.digest('hex'); } diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 51a1bbeae8c8b..6a8e828071246 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -287,12 +287,6 @@ export class Function extends FunctionBase { return this._currentVersion; } - if (!this._codeHash) { - throw new Error( - `cannot automatically create a version resource for this function since the hash of the code cannot be calculated. ` + - `This is only supported for "lambda.Code.fromAsset" and "lambda.Code.fromInline"`); - } - this._currentVersion = new Version(this, `CurrentVersion`, { lambda: this, description: `${this.node.path}.currentVersion (created by AWS CDK)`, @@ -470,11 +464,6 @@ export class Function extends FunctionBase { public readonly permissionsNode = this.node; - /** - * @internal - */ - public _codeHash?: string; - protected readonly canCreatePermissions = true; private readonly layers: ILayerVersion[] = []; @@ -520,7 +509,6 @@ export class Function extends FunctionBase { verifyCodeConfig(code, props.runtime); this.deadLetterQueue = this.buildDeadLetterQueue(props); - this._codeHash = code.codeHash; const resource: CfnFunction = new CfnFunction(this, 'Resource', { functionName: this.physicalName, @@ -820,5 +808,5 @@ export function verifyCodeConfig(code: CodeConfig, runtime: Runtime) { // if this is inline code, check that the runtime supports if (code.inlineCode && !runtime.supportsInlineCode) { throw new Error(`Inline source not allowed for ${runtime.name}`); - }} - + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/test.code.ts b/packages/@aws-cdk/aws-lambda/test/test.code.ts index 6840b67c959d6..85fa51eff90f2 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.code.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.code.ts @@ -83,43 +83,6 @@ export = { }, ResourcePart.CompleteDefinition)); test.done(); }, - - 'codeHash is supported for assets and inline'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const asset = new lambda.Function(stack, 'AssetCode', { - code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); - - const inline = new lambda.Function(stack, 'InlineCode', { - code: lambda.Code.fromInline('boom boom'), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); - - const bucket = new lambda.Function(stack, 'S3Code', { - code: lambda.Code.fromBucket(s3.Bucket.fromBucketName(stack, 'Bucket', 'bucket'), 'key'), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); - - const params = new lambda.Function(stack, 'CfnParams', { - code: lambda.Code.fromCfnParameters(), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }); - - // THEN - test.deepEqual(asset._codeHash, '9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232'); - test.deepEqual(inline._codeHash, '58ad733fe276cb7b9b171b0beafad40f43b6d1cd68a1b93327d3655f739dfa0e'); - test.deepEqual(bucket._codeHash, undefined); - test.deepEqual(params._codeHash, undefined); - test.done(); - } }, 'lambda.Code.fromCfnParameters': { diff --git a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts b/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts index 8ed1148babd3d..6aaaf5db95041 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts @@ -39,8 +39,8 @@ export = { handler: 'index.handler' }); - test.deepEqual(calculateFunctionHash(fn1), 'a1dd0e860a511e65bf720e3bd0f6b6a9'); - test.deepEqual(calculateFunctionHash(fn2), 'a1dd0e860a511e65bf720e3bd0f6b6a9'); + test.deepEqual(calculateFunctionHash(fn1), calculateFunctionHash(fn2)); + test.deepEqual(calculateFunctionHash(fn1), 'aea5463dba236007afe91d2832b3c836'); test.done(); }, }, @@ -53,8 +53,8 @@ export = { handler: 'index.handler' }); - test.notDeepEqual(calculateFunctionHash(fn1), 'a1dd0e860a511e65bf720e3bd0f6b6a9'); - test.deepEqual(calculateFunctionHash(fn1), '1ad32fcab0aa68bf36825df8e6f0a7a2'); + test.notDeepEqual(calculateFunctionHash(fn1), 'aea5463dba236007afe91d2832b3c836'); + test.deepEqual(calculateFunctionHash(fn1), '979b4a14c6f174c745cdbcd1036cf844'); test.done(); }, @@ -79,8 +79,8 @@ export = { } }); - test.deepEqual(calculateFunctionHash(fn1), 'ea4daca738e83756eec5a3a3c806d54d'); - test.deepEqual(calculateFunctionHash(fn2), '2cb1ed852c739c60254b3bbfb258e513'); + test.deepEqual(calculateFunctionHash(fn1), 'd1bc824ac5022b7d62d8b12dbae6580c'); + test.deepEqual(calculateFunctionHash(fn2), '3b683d05465012b0aa9c4ff53b32f014'); test.done(); }, @@ -105,8 +105,28 @@ export = { } }); - test.deepEqual(calculateFunctionHash(fn1), 'ea4daca738e83756eec5a3a3c806d54d'); - test.deepEqual(calculateFunctionHash(fn2), '4bdbec98b3c838410b5637fb71101514'); + test.deepEqual(calculateFunctionHash(fn1), 'd1bc824ac5022b7d62d8b12dbae6580c'); + test.deepEqual(calculateFunctionHash(fn2), '0f168f0772463e8e547bb3800937e54d'); + test.done(); + }, + + 'inline code change impacts the hash'(test: Test) { + const stack1 = new Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromInline('foo'), + handler: 'index.handler', + }); + + const stack2 = new Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('foo bar'), + handler: 'index.handler', + }); + + test.deepEqual(calculateFunctionHash(fn1), 'ebf2e871fc6a3062e8bdcc5ebe16db3f'); + test.deepEqual(calculateFunctionHash(fn2), 'ffedf6424a18a594a513129dc97bf53c'); test.done(); } }; diff --git a/packages/@aws-cdk/aws-lambda/test/test.function.ts b/packages/@aws-cdk/aws-lambda/test/test.function.ts index 71ac3c3f01399..ce7b0a2d76c08 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.function.ts @@ -185,22 +185,6 @@ export = testCase({ 'currentVersion': { - 'cannot be created for unsupported lambda.Code types'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const fn = new lambda.Function(stack, 'fn', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_12_X, - code: lambda.Code.fromCfnParameters() - }); - - // THEN - test.throws(() => fn.currentVersion, /cannot automatically create a version resource for this function/); - test.done(); - }, - // see test.function-hash.ts for more coverage for this 'logical id of version is based on the function hash'(test: Test) { // GIVEN @@ -235,18 +219,17 @@ export = testCase({ expect(stack1).to(haveOutput({ outputName: 'CurrentVersionArn', outputValue: { - Ref: "MyFunctionCurrentVersion197490AFa10cabe18b67f28a68a1ad20c7468ba6" + Ref: "MyFunctionCurrentVersion197490AF1a9a73cf5c46aec5e40fb202042eb60b" } })); expect(stack2).to(haveOutput({ outputName: 'CurrentVersionArn', outputValue: { - Ref: "MyFunctionCurrentVersion197490AF35a71af54fb82ee3ff968834b82d088c" + Ref: "MyFunctionCurrentVersion197490AF8360a045031060e3117269037b7bffd6" } })); test.done(); } - }, }); diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts index 3d083063ba884..b667e85e2b779 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts @@ -134,7 +134,7 @@ export = { }, "FunctionVersion": { "Fn::GetAtt": [ - "FnCurrentVersion17A89ABB3127ebe0d45a77e18d3b1ca1c6c8c55c", + "FnCurrentVersion17A89ABB19ed45993ff69fd011ae9fd4ab6e2005", "Version" ] }, From da122b2204ded7e7c05792f0b31abf59e7be38bc Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 23 Mar 2020 11:27:31 +0200 Subject: [PATCH 05/29] clean up --- packages/@aws-cdk/aws-lambda/lib/code.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/code.ts b/packages/@aws-cdk/aws-lambda/lib/code.ts index 3e1be704f6104..03c5b02c9d6b7 100644 --- a/packages/@aws-cdk/aws-lambda/lib/code.ts +++ b/packages/@aws-cdk/aws-lambda/lib/code.ts @@ -111,7 +111,6 @@ export interface CodeConfig { */ export class S3Code extends Code { public readonly isInline = false; - private bucketName: string; constructor(bucket: s3.IBucket, private key: string, private objectVersion?: string) { @@ -155,7 +154,7 @@ export class InlineCode extends Code { public bind(_scope: cdk.Construct): CodeConfig { return { - inlineCode: this.code, + inlineCode: this.code }; } } @@ -165,7 +164,6 @@ export class InlineCode extends Code { */ export class AssetCode extends Code { public readonly isInline = false; - private asset?: s3_assets.Asset; /** @@ -248,7 +246,6 @@ export interface CfnParametersCodeProps { */ export class CfnParametersCode extends Code { public readonly isInline = false; - private _bucketNameParam?: cdk.CfnParameter; private _objectKeyParam?: cdk.CfnParameter; From 5e89466735543d9a08415ed7b9eaf503aae5f84d Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 23 Mar 2020 17:27:34 +0200 Subject: [PATCH 06/29] doc fixes --- packages/@aws-cdk/aws-lambda/README.md | 10 +++++----- packages/@aws-cdk/aws-lambda/lib/function-base.ts | 7 +++++++ packages/@aws-cdk/aws-lambda/lib/function.ts | 6 +++--- .../@aws-cdk/aws-lambda/test/integ.current-version.ts | 1 + packages/@aws-cdk/aws-lambda/test/test.code.ts | 1 - 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index 6367ea1b1cf9f..0788509426e39 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -92,15 +92,15 @@ points to a specific version. The following example defines an alias named `live` which will always point to a version that represents the function as defined in your CDK app. When you change -your lambda code or configuration, a new resource will be created. Since the -version's `removalPolicy` option is set to `RETAIN`, old versions will not be -deleted (the default is `DESTROY`): +your lambda code or configuration, a new resource will be created. You can +specify options for the current version through the `currentVersionOptions` +property. ```ts const fn = new lambda.Function(this, 'MyFunction', { - // ... currentVersionOptions: { - removalPolicy: RemovalPolicy.RETAIN // retain old versions + removalPolicy: RemovalPolicy.RETAIN, // retain old versions + retryAttempts: 5 // async retry attempts } }); diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index 6fc7b9bb5e7c6..c8d9a49764231 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -41,6 +41,13 @@ export interface IFunction extends IResource, ec2.IConnectable, iam.IGrantable { /** * The `$LATEST` version of this function. + * + * Note that this is reference to a non-specific AWS Lambda version, which + * means the function this version refers to can return different results in + * different invocations. + * + * To obtain a reference to an explicit version which references the current + * function configuration, use `lambdaFunction.currentVersion` instead. */ readonly latestVersion: IVersion; diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 6a8e828071246..83ccdb79c3849 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -277,10 +277,10 @@ export class Function extends FunctionBase { /** * Returns a `lambda.Version` which represents the current version of this * Lambda function. A new version will be created every time the function's - * code or it's configuration changes. + * configuration changes. * - * To enable this, set `currentVersion: true` attribute to `true` when creating - * the `lambda.Function` object. + * You can specify options for this version using the `currentVersionOptions` + * prop when initializing the `lambda.Function`. */ public get currentVersion(): Version { if (this._currentVersion) { diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts b/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts index e017cdb35cfa5..743267cb7f4d9 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts @@ -12,6 +12,7 @@ class TestStack extends Stack { runtime: lambda.Runtime.PYTHON_3_8, currentVersionOptions: { removalPolicy: RemovalPolicy.RETAIN, + retryAttempts: 5 } }); diff --git a/packages/@aws-cdk/aws-lambda/test/test.code.ts b/packages/@aws-cdk/aws-lambda/test/test.code.ts index 85fa51eff90f2..9ec3b793de128 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.code.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.code.ts @@ -1,5 +1,4 @@ import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; -import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Test } from 'nodeunit'; From 411ffd8e93a3942a458bfabfd915e6fbce12ba21 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 23 Mar 2020 18:00:22 +0200 Subject: [PATCH 07/29] fix lint breaks --- packages/@aws-cdk/aws-lambda/lib/lambda-version.ts | 1 - packages/@aws-cdk/aws-lambda/test/test.function.ts | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index bd3cb0b7332a0..9a7167ef5b0ea 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -252,4 +252,3 @@ export class Version extends QualifiedFunctionBase implements IVersion { export function extractQualifierFromArn(arn: string) { return Fn.select(7, Fn.split(':', arn)); } - diff --git a/packages/@aws-cdk/aws-lambda/test/test.function.ts b/packages/@aws-cdk/aws-lambda/test/test.function.ts index ce7b0a2d76c08..fd9316c822b54 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.function.ts @@ -7,7 +7,6 @@ import * as _ from 'lodash'; import {Test, testCase} from 'nodeunit'; import * as path from 'path'; import * as lambda from '../lib'; -import { CfnOutput } from '@aws-cdk/core'; export = testCase({ 'add incompatible layer'(test: Test) { @@ -208,10 +207,10 @@ export = testCase({ }); // WHEN - new CfnOutput(stack1, 'CurrentVersionArn', { + new cdk.CfnOutput(stack1, 'CurrentVersionArn', { value: fn1.currentVersion.functionArn }); - new CfnOutput(stack2, 'CurrentVersionArn', { + new cdk.CfnOutput(stack2, 'CurrentVersionArn', { value: fn2.currentVersion.functionArn }); From e58a60a8f8cd63bd7c25a26aeab7cda221e25580 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 23 Mar 2020 18:04:31 +0200 Subject: [PATCH 08/29] fix snapshot --- packages/@aws-cdk/aws-lambda/README.md | 2 +- .../test/integ.current-version.expected.json | 19 +++++++++++++++++-- .../aws-lambda/test/integ.current-version.ts | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index 0788509426e39..1ddc674c07da5 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -100,7 +100,7 @@ property. const fn = new lambda.Function(this, 'MyFunction', { currentVersionOptions: { removalPolicy: RemovalPolicy.RETAIN, // retain old versions - retryAttempts: 5 // async retry attempts + retryAttempts: 1 // async retry attempts } }); diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json index 65a4f95d0834e..36a25c0459883 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json @@ -85,7 +85,7 @@ "MyLambdaServiceRole4539ECB6" ] }, - "MyLambdaCurrentVersionE7A382CC73a23add9934a83560eb6afdb1ec3e65": { + "MyLambdaCurrentVersionE7A382CC1a5358ec9d2d5ef45baeba2fbb9fa9bd": { "Type": "AWS::Lambda::Version", "Properties": { "FunctionName": { @@ -96,6 +96,21 @@ "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, + "MyLambdaCurrentVersionEventInvokeConfigD120DC68": { + "Type": "AWS::Lambda::EventInvokeConfig", + "Properties": { + "FunctionName": { + "Ref": "MyLambdaCCE802FB" + }, + "Qualifier": { + "Fn::GetAtt": [ + "MyLambdaCurrentVersionE7A382CC1a5358ec9d2d5ef45baeba2fbb9fa9bd", + "Version" + ] + }, + "MaximumRetryAttempts": 1 + } + }, "MyLambdaCurrentVersionAliaslive9151E913": { "Type": "AWS::Lambda::Alias", "Properties": { @@ -104,7 +119,7 @@ }, "FunctionVersion": { "Fn::GetAtt": [ - "MyLambdaCurrentVersionE7A382CC73a23add9934a83560eb6afdb1ec3e65", + "MyLambdaCurrentVersionE7A382CC1a5358ec9d2d5ef45baeba2fbb9fa9bd", "Version" ] }, diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts b/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts index 743267cb7f4d9..4a37f486e53f8 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version.ts @@ -12,7 +12,7 @@ class TestStack extends Stack { runtime: lambda.Runtime.PYTHON_3_8, currentVersionOptions: { removalPolicy: RemovalPolicy.RETAIN, - retryAttempts: 5 + retryAttempts: 1 } }); From 5a99536db58240f75f2a3b048b8fb50e0ee9192f Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 23 Mar 2020 21:36:44 +0200 Subject: [PATCH 09/29] add some docstrings --- packages/@aws-cdk/aws-lambda/lib/function.ts | 1 + packages/@aws-cdk/aws-lambda/lib/lambda-version.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 83ccdb79c3849..95a53706d9740 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -229,6 +229,7 @@ export interface FunctionOptions extends EventInvokeConfigOptions { /** * Options for the `lambda.Version` resource automatically created by the * `fn.currentVersion` method. + * @default - default options as described in `VersionOptions` */ readonly currentVersionOptions?: VersionOptions; } diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index 9a7167ef5b0ea..39d90eb881a93 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -27,6 +27,9 @@ export interface IVersion extends IFunction { addAlias(aliasName: string, options?: AliasOptions): Alias; } +/** + * Options for `lambda.Version` + */ export interface VersionOptions extends EventInvokeConfigOptions { /** * SHA256 of the version of the Lambda source code From 02f2c7e1a8ecc72f58d4d145dc6bfa50074b9108 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 11:47:34 +0200 Subject: [PATCH 10/29] sort environment variables by key for stable hashing --- packages/@aws-cdk/aws-lambda/lib/function.ts | 12 ++++++--- .../aws-lambda/test/test.function-hash.ts | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 95a53706d9740..7aa62dacfe57f 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -290,7 +290,6 @@ export class Function extends FunctionBase { this._currentVersion = new Version(this, `CurrentVersion`, { lambda: this, - description: `${this.node.path}.currentVersion (created by AWS CDK)`, ...this.currentVersionOptions }); @@ -673,9 +672,14 @@ export class Function extends FunctionBase { return undefined; } - return { - variables: this.environment - }; + // sort environment so the hash of the function used to create + // `currentVersion` is not affected by key order (this is how lambda does it). + const variables: { [key: string]: string } = { }; + for (const key of Object.keys(this.environment).sort()) { + variables[key] = this.environment[key]; + } + + return { variables }; } /** diff --git a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts b/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts index 6aaaf5db95041..d016bc9c94480 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts @@ -128,5 +128,32 @@ export = { test.deepEqual(calculateFunctionHash(fn1), 'ebf2e871fc6a3062e8bdcc5ebe16db3f'); test.deepEqual(calculateFunctionHash(fn2), 'ffedf6424a18a594a513129dc97bf53c'); test.done(); + }, + + 'different order of env vars produce the same hash'(test: Test) { + const stack1 = new Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Foo: 'bar', + Bar: 'foo', + } + }); + + const stack2 = new Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Bar: 'foo', + Foo: 'bar', + } + }); + + test.deepEqual(calculateFunctionHash(fn1), calculateFunctionHash(fn2)); + test.done(); } }; From 73e38c1d29bf330fc43b5800a7c2b94622c0100b Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 11:47:40 +0200 Subject: [PATCH 11/29] fix typo --- packages/@aws-cdk/aws-lambda/lib/lambda-version.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index 39d90eb881a93..3123d659e1936 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -55,7 +55,7 @@ export interface VersionOptions extends EventInvokeConfigOptions { readonly provisionedConcurrentExecutions?: number; /** - * Whether to ratin old versions of this function when a new version is + * Whether to retain old versions of this function when a new version is * created. * * @default RemovalPolicy.DESTROY From db61dcf91dda4fc33b076f96cfdf164ec40ee868 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 12:40:14 +0200 Subject: [PATCH 12/29] update snapthots --- .../aws-lambda/test/integ.current-version.expected.json | 3 +-- .../@aws-cdk/aws-lambda/test/integ.lambda.expected.json | 6 ++++-- .../test/integ.lambda.prov.concurrent.expected.json | 8 ++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json index 36a25c0459883..96d17d375e9c1 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version.expected.json @@ -90,8 +90,7 @@ "Properties": { "FunctionName": { "Ref": "MyLambdaCCE802FB" - }, - "Description": "lambda-test-current-version/MyLambda.currentVersion (created by AWS CDK)" + } }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda.expected.json index 885ca5f077ba7..9763db3c9d5ba 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda.expected.json @@ -78,7 +78,9 @@ "FunctionName": { "Ref": "MyLambdaCCE802FB" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Alias325C5727": { "Type": "AWS::Lambda::Alias", @@ -106,4 +108,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json index ad788ff4425b6..ca4eb1eeb04bc 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json @@ -78,7 +78,9 @@ "FunctionName": { "Ref": "MyLambdaAliasPCED0B8D751" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Alias325C5727": { "Type": "AWS::Lambda::Alias", @@ -189,7 +191,9 @@ "ProvisionedConcurrencyConfig": { "ProvisionedConcurrentExecutions": 5 } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Alias29455D932": { "Type": "AWS::Lambda::Alias", From c7252fdf84ffee598ce97990e52ba87735db4a38 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 15:05:16 +0200 Subject: [PATCH 13/29] update snapshot --- .../test/integ.nested-stack.expected.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json index b765d6db35ab6..699c958a7bd0c 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json @@ -158,7 +158,7 @@ }, "/", { - "Ref": "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3BucketE3660F43" + "Ref": "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3BucketB0304724" }, "/", { @@ -168,7 +168,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3VersionKeyFD0B0470" + "Ref": "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3VersionKey5CBE3598" } ] } @@ -181,7 +181,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3VersionKeyFD0B0470" + "Ref": "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3VersionKey5CBE3598" } ] } @@ -266,17 +266,17 @@ "Type": "String", "Description": "Artifact hash for asset \"0d0404717d8867c09534f2cf382e8e24531ff64a968afa2efd7f071ad65a22df\"" }, - "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3BucketE3660F43": { + "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3BucketB0304724": { "Type": "String", - "Description": "S3 bucket for asset \"dddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccaf\"" + "Description": "S3 bucket for asset \"7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944\"" }, - "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3VersionKeyFD0B0470": { + "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3VersionKey5CBE3598": { "Type": "String", - "Description": "S3 key for asset version \"dddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccaf\"" + "Description": "S3 key for asset version \"7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944\"" }, - "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafArtifactHashEECD8E35": { + "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944ArtifactHash17200484": { "Type": "String", - "Description": "Artifact hash for asset \"dddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccaf\"" + "Description": "Artifact hash for asset \"7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944\"" } } } \ No newline at end of file From 32453ba6f2c7e5f70d50fcdbe5c90c007d11c835 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:52:08 +0200 Subject: [PATCH 14/29] Update integ.lambda.expected.json --- .../@aws-cdk/aws-lambda/test/integ.lambda.expected.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda.expected.json index 9763db3c9d5ba..885ca5f077ba7 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda.expected.json @@ -78,9 +78,7 @@ "FunctionName": { "Ref": "MyLambdaCCE802FB" } - }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" + } }, "Alias325C5727": { "Type": "AWS::Lambda::Alias", @@ -108,4 +106,4 @@ } } } -} \ No newline at end of file +} From b9a21d735ebe360e22ce6303cbcda8d59c4f0141 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:52:34 +0200 Subject: [PATCH 15/29] Update integ.lambda.prov.concurrent.expected.json --- .../test/integ.lambda.prov.concurrent.expected.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json index ca4eb1eeb04bc..ca3d608c53ba3 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json @@ -78,9 +78,7 @@ "FunctionName": { "Ref": "MyLambdaAliasPCED0B8D751" } - }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" + } }, "Alias325C5727": { "Type": "AWS::Lambda::Alias", @@ -221,4 +219,4 @@ } } } -} \ No newline at end of file +} From 6d2c1bed5a22f38d63c7afde15e64874efd05766 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:53:01 +0200 Subject: [PATCH 16/29] Update integ.lambda.prov.concurrent.expected.json --- .../test/integ.lambda.prov.concurrent.expected.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json index ca3d608c53ba3..10d70c1d95a17 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json @@ -189,9 +189,7 @@ "ProvisionedConcurrencyConfig": { "ProvisionedConcurrentExecutions": 5 } - }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" + } }, "Alias29455D932": { "Type": "AWS::Lambda::Alias", From ee2b1703f6d253b8cb4bcda02d6ba83adef1a70b Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:53:22 +0200 Subject: [PATCH 17/29] Update integ.lambda.prov.concurrent.expected.json From deef429da34bcea2d8d3c6b1ccb5f01dca9f8476 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:53:45 +0200 Subject: [PATCH 18/29] Update integ.lambda.prov.concurrent.expected.json From cf30ec04bae650737c1d6bcb79f08d20598c08c9 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:54:37 +0200 Subject: [PATCH 19/29] Update test.code.ts --- packages/@aws-cdk/aws-lambda/test/test.code.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda/test/test.code.ts b/packages/@aws-cdk/aws-lambda/test/test.code.ts index 9ec3b793de128..21a861c2da5b4 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.code.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.code.ts @@ -81,7 +81,7 @@ export = { } }, ResourcePart.CompleteDefinition)); test.done(); - }, + } }, 'lambda.Code.fromCfnParameters': { From 49457ba70ef2d7a22b499836a6b1e3110c0d5e1c Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:55:34 +0200 Subject: [PATCH 20/29] Update integ.lambda.prov.concurrent.expected.json From 629c81c639a8f6898fdbbd755276e61de0541515 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:55:52 +0200 Subject: [PATCH 21/29] Update integ.lambda.prov.concurrent.expected.json From ac670613e0265016168f94a34f4e0f7d271fa152 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:56:21 +0200 Subject: [PATCH 22/29] Update integ.lambda.prov.concurrent.expected.json From 5c804cdeb0f3b9969d2d46cc17055c36410bf2d1 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:46:04 +0200 Subject: [PATCH 23/29] do not set deletion policy if not specified --- packages/@aws-cdk/aws-lambda/lib/lambda-version.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index 3123d659e1936..b04fbace206e9 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -171,9 +171,11 @@ export class Version extends QualifiedFunctionBase implements IVersion { provisionedConcurrencyConfig: this.determineProvisionedConcurrency(props) }); - version.applyRemovalPolicy(props.removalPolicy, { - default: RemovalPolicy.DESTROY - }); + if (props.removalPolicy) { + version.applyRemovalPolicy(props.removalPolicy, { + default: RemovalPolicy.DESTROY + }); + } this.version = version.attrVersion; this.functionArn = version.ref; From fe10bdba5a1bc58c0f170fcf3154a158ebb739c8 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 17:58:11 +0200 Subject: [PATCH 24/29] Update integ.lambda.prov.concurrent.expected.json From d240dfdd5a4a00f6b6825c5fe7264c9f5f41112c Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 19:14:47 +0200 Subject: [PATCH 25/29] update snapshot --- .../test/integ.global.expected.json | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json index 7cdc1ef802738..3f0728c05c718 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json @@ -91,7 +91,7 @@ }, "/", { - "Ref": "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3Bucket0A4A97BA" + "Ref": "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3Bucket08DBE9F4" }, "/", { @@ -101,7 +101,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3VersionKey5AAA623D" + "Ref": "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3VersionKeyAF9BEDBE" } ] } @@ -114,7 +114,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3VersionKey5AAA623D" + "Ref": "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3VersionKeyAF9BEDBE" } ] } @@ -133,58 +133,58 @@ "referencetocdkdynamodbglobal20191121TableB640876BRef": { "Ref": "TableCD117FA1" }, - "referencetocdkdynamodbglobal20191121AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3Bucket9329A233Ref": { - "Ref": "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3Bucket4FE3E660" + "referencetocdkdynamodbglobal20191121AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3Bucket32CB68FERef": { + "Ref": "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3BucketB1F319B1" }, - "referencetocdkdynamodbglobal20191121AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3VersionKeyFFAD911CRef": { - "Ref": "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3VersionKey7D7136AC" + "referencetocdkdynamodbglobal20191121AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3VersionKey09AC142ARef": { + "Ref": "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3VersionKey4B693FC5" }, - "referencetocdkdynamodbglobal20191121AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3Bucket44C23345Ref": { - "Ref": "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3Bucket347EC9ED" + "referencetocdkdynamodbglobal20191121AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3BucketAC9B784CRef": { + "Ref": "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3Bucket75CDEB48" }, - "referencetocdkdynamodbglobal20191121AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3VersionKey03E90F27Ref": { - "Ref": "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3VersionKeyDE3A9B7E" + "referencetocdkdynamodbglobal20191121AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3VersionKeyD1868D0ARef": { + "Ref": "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3VersionKey1DD5E19F" } } } } }, "Parameters": { - "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3Bucket4FE3E660": { + "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3BucketB1F319B1": { "Type": "String", - "Description": "S3 bucket for asset \"0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821a\"" + "Description": "S3 bucket for asset \"f215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943\"" }, - "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3VersionKey7D7136AC": { + "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3VersionKey4B693FC5": { "Type": "String", - "Description": "S3 key for asset version \"0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821a\"" + "Description": "S3 key for asset version \"f215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943\"" }, - "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aArtifactHash81B49BAA": { + "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943ArtifactHash98466A41": { "Type": "String", - "Description": "Artifact hash for asset \"0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821a\"" + "Description": "Artifact hash for asset \"f215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943\"" }, - "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3Bucket347EC9ED": { + "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3Bucket75CDEB48": { "Type": "String", - "Description": "S3 bucket for asset \"082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33a\"" + "Description": "S3 bucket for asset \"6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044\"" }, - "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3VersionKeyDE3A9B7E": { + "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3VersionKey1DD5E19F": { "Type": "String", - "Description": "S3 key for asset version \"082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33a\"" + "Description": "S3 key for asset version \"6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044\"" }, - "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aArtifactHash0DA92241": { + "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044ArtifactHashF11F33A4": { "Type": "String", - "Description": "Artifact hash for asset \"082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33a\"" + "Description": "Artifact hash for asset \"6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044\"" }, - "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3Bucket0A4A97BA": { + "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3Bucket08DBE9F4": { "Type": "String", - "Description": "S3 bucket for asset \"e4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8\"" + "Description": "S3 bucket for asset \"b6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06\"" }, - "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3VersionKey5AAA623D": { + "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3VersionKeyAF9BEDBE": { "Type": "String", - "Description": "S3 key for asset version \"e4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8\"" + "Description": "S3 key for asset version \"b6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06\"" }, - "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8ArtifactHash92FF28EC": { + "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06ArtifactHashD6FA4AF7": { "Type": "String", - "Description": "Artifact hash for asset \"e4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8\"" + "Description": "Artifact hash for asset \"b6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06\"" } } } \ No newline at end of file From 46366cb5300e96061589ef99949be1fb80db4f45 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 20:20:03 +0200 Subject: [PATCH 26/29] update ddb snapshot --- .../test/integ.global.expected.json | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json index 3f0728c05c718..1a0910fc9cd8a 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json @@ -91,7 +91,7 @@ }, "/", { - "Ref": "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3Bucket08DBE9F4" + "Ref": "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3Bucket72B2B1A3" }, "/", { @@ -101,7 +101,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3VersionKeyAF9BEDBE" + "Ref": "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3VersionKeyC32CA931" } ] } @@ -114,7 +114,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3VersionKeyAF9BEDBE" + "Ref": "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3VersionKeyC32CA931" } ] } @@ -133,11 +133,11 @@ "referencetocdkdynamodbglobal20191121TableB640876BRef": { "Ref": "TableCD117FA1" }, - "referencetocdkdynamodbglobal20191121AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3Bucket32CB68FERef": { - "Ref": "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3BucketB1F319B1" + "referencetocdkdynamodbglobal20191121AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3Bucket9329A233Ref": { + "Ref": "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3Bucket4FE3E660" }, - "referencetocdkdynamodbglobal20191121AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3VersionKey09AC142ARef": { - "Ref": "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3VersionKey4B693FC5" + "referencetocdkdynamodbglobal20191121AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3VersionKeyFFAD911CRef": { + "Ref": "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3VersionKey7D7136AC" }, "referencetocdkdynamodbglobal20191121AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3BucketAC9B784CRef": { "Ref": "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3Bucket75CDEB48" @@ -150,17 +150,17 @@ } }, "Parameters": { - "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3BucketB1F319B1": { + "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3Bucket4FE3E660": { "Type": "String", - "Description": "S3 bucket for asset \"f215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943\"" + "Description": "S3 bucket for asset \"0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821a\"" }, - "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943S3VersionKey4B693FC5": { + "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3VersionKey7D7136AC": { "Type": "String", - "Description": "S3 key for asset version \"f215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943\"" + "Description": "S3 key for asset version \"0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821a\"" }, - "AssetParametersf215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943ArtifactHash98466A41": { + "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aArtifactHash81B49BAA": { "Type": "String", - "Description": "Artifact hash for asset \"f215c637e4d75e4021ff09c1fed7d451769b9f0a6d1fb73ba6eebcafcd4e8943\"" + "Description": "Artifact hash for asset \"0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821a\"" }, "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3Bucket75CDEB48": { "Type": "String", @@ -174,17 +174,17 @@ "Type": "String", "Description": "Artifact hash for asset \"6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044\"" }, - "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3Bucket08DBE9F4": { + "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3Bucket72B2B1A3": { "Type": "String", - "Description": "S3 bucket for asset \"b6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06\"" + "Description": "S3 bucket for asset \"d7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212\"" }, - "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06S3VersionKeyAF9BEDBE": { + "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3VersionKeyC32CA931": { "Type": "String", - "Description": "S3 key for asset version \"b6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06\"" + "Description": "S3 key for asset version \"d7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212\"" }, - "AssetParametersb6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06ArtifactHashD6FA4AF7": { + "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212ArtifactHash50018B10": { "Type": "String", - "Description": "Artifact hash for asset \"b6ce51e13a005e0ae5131bbf5207e00b567c4bb9507cc7bbe415df6910d1ec06\"" + "Description": "Artifact hash for asset \"d7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212\"" } } } \ No newline at end of file From 88787ff9988b18657fbe06db56f0b80b99568d16 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 24 Mar 2020 20:38:54 +0200 Subject: [PATCH 27/29] revert location of logGroup --- packages/@aws-cdk/aws-lambda/lib/function.ts | 41 ++++++++++---------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 7aa62dacfe57f..a4d680efe0d64 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -296,26 +296,6 @@ export class Function extends FunctionBase { return this._currentVersion; } - /** - * 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 { - if (!this._logGroup) { - const logretention = new 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; - } public static fromFunctionArn(scope: Construct, id: string, functionArn: string): IFunction { return Function.fromFunctionAttributes(scope, id, { functionArn }); } @@ -650,6 +630,27 @@ export class Function extends FunctionBase { }); } + /** + * 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 { + if (!this._logGroup) { + const logretention = new 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; + } + protected prepare() { super.prepare(); From c04530012808eea3d7fcaf30d81fd59eca5c6e3f Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Wed, 25 Mar 2020 10:53:21 +0200 Subject: [PATCH 28/29] do not sort env vars if "currentVersion" is not used for backwards compatibility --- .../test/integ.nested-stack.expected.json | 18 ++-- .../test/integ.global.expected.json | 38 ++++----- packages/@aws-cdk/aws-lambda/lib/function.ts | 13 ++- .../aws-lambda/test/test.function-hash.ts | 85 +++++++++++++------ 4 files changed, 100 insertions(+), 54 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json index 699c958a7bd0c..b765d6db35ab6 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json @@ -158,7 +158,7 @@ }, "/", { - "Ref": "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3BucketB0304724" + "Ref": "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3BucketE3660F43" }, "/", { @@ -168,7 +168,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3VersionKey5CBE3598" + "Ref": "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3VersionKeyFD0B0470" } ] } @@ -181,7 +181,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3VersionKey5CBE3598" + "Ref": "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3VersionKeyFD0B0470" } ] } @@ -266,17 +266,17 @@ "Type": "String", "Description": "Artifact hash for asset \"0d0404717d8867c09534f2cf382e8e24531ff64a968afa2efd7f071ad65a22df\"" }, - "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3BucketB0304724": { + "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3BucketE3660F43": { "Type": "String", - "Description": "S3 bucket for asset \"7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944\"" + "Description": "S3 bucket for asset \"dddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccaf\"" }, - "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944S3VersionKey5CBE3598": { + "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafS3VersionKeyFD0B0470": { "Type": "String", - "Description": "S3 key for asset version \"7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944\"" + "Description": "S3 key for asset version \"dddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccaf\"" }, - "AssetParameters7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944ArtifactHash17200484": { + "AssetParametersdddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccafArtifactHashEECD8E35": { "Type": "String", - "Description": "Artifact hash for asset \"7f384ef59c4f7ec4f8f4f3be8a23e5c83b374957159514db6e9e059687adf944\"" + "Description": "Artifact hash for asset \"dddca70fcceefd0a4532c8eb5ad3d5da6f51d64fda9343f0b57dd664736dccaf\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json index 1a0910fc9cd8a..7cdc1ef802738 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json @@ -91,7 +91,7 @@ }, "/", { - "Ref": "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3Bucket72B2B1A3" + "Ref": "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3Bucket0A4A97BA" }, "/", { @@ -101,7 +101,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3VersionKeyC32CA931" + "Ref": "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3VersionKey5AAA623D" } ] } @@ -114,7 +114,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3VersionKeyC32CA931" + "Ref": "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3VersionKey5AAA623D" } ] } @@ -139,11 +139,11 @@ "referencetocdkdynamodbglobal20191121AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3VersionKeyFFAD911CRef": { "Ref": "AssetParameters0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821aS3VersionKey7D7136AC" }, - "referencetocdkdynamodbglobal20191121AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3BucketAC9B784CRef": { - "Ref": "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3Bucket75CDEB48" + "referencetocdkdynamodbglobal20191121AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3Bucket44C23345Ref": { + "Ref": "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3Bucket347EC9ED" }, - "referencetocdkdynamodbglobal20191121AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3VersionKeyD1868D0ARef": { - "Ref": "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3VersionKey1DD5E19F" + "referencetocdkdynamodbglobal20191121AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3VersionKey03E90F27Ref": { + "Ref": "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3VersionKeyDE3A9B7E" } } } @@ -162,29 +162,29 @@ "Type": "String", "Description": "Artifact hash for asset \"0706ab5a9bd5b9d7fcdb4b10e8d6c37573344b8c1ba8f5800a33b85ce34d821a\"" }, - "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3Bucket75CDEB48": { + "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3Bucket347EC9ED": { "Type": "String", - "Description": "S3 bucket for asset \"6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044\"" + "Description": "S3 bucket for asset \"082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33a\"" }, - "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3VersionKey1DD5E19F": { + "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aS3VersionKeyDE3A9B7E": { "Type": "String", - "Description": "S3 key for asset version \"6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044\"" + "Description": "S3 key for asset version \"082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33a\"" }, - "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044ArtifactHashF11F33A4": { + "AssetParameters082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33aArtifactHash0DA92241": { "Type": "String", - "Description": "Artifact hash for asset \"6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044\"" + "Description": "Artifact hash for asset \"082715a6f74a051218c287c9750d2fff07912878d011fad47eb21f33f335a33a\"" }, - "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3Bucket72B2B1A3": { + "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3Bucket0A4A97BA": { "Type": "String", - "Description": "S3 bucket for asset \"d7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212\"" + "Description": "S3 bucket for asset \"e4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8\"" }, - "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212S3VersionKeyC32CA931": { + "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8S3VersionKey5AAA623D": { "Type": "String", - "Description": "S3 key for asset version \"d7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212\"" + "Description": "S3 key for asset version \"e4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8\"" }, - "AssetParametersd7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212ArtifactHash50018B10": { + "AssetParameterse4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8ArtifactHash92FF28EC": { "Type": "String", - "Description": "Artifact hash for asset \"d7ea3b8ed809b20a63532a99db8a08a8441513d9e393df03428903fb5e2b5212\"" + "Description": "Artifact hash for asset \"e4cec59f8586c531fe724f1e9c288cb92523ee15632c9fc704dadcdd45671ab8\"" } } } \ 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 a4d680efe0d64..d659a4fede6f0 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -673,8 +673,19 @@ export class Function extends FunctionBase { return undefined; } + // 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. + if (!this._currentVersion) { + return { + variables: this.environment + }; + } + // sort environment so the hash of the function used to create - // `currentVersion` is not affected by key order (this is how lambda does it). + // `currentVersion` is not affected by key order (this is how lambda does + // it). const variables: { [key: string]: string } = { }; for (const key of Object.keys(this.environment).sort()) { variables[key] = this.environment[key]; diff --git a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts b/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts index d016bc9c94480..651884b83e575 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts @@ -1,4 +1,4 @@ -import { Stack } from '@aws-cdk/core'; +import { CfnOutput, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as path from 'path'; import * as lambda from '../lib'; @@ -130,30 +130,65 @@ export = { test.done(); }, - 'different order of env vars produce the same hash'(test: Test) { - const stack1 = new Stack(); - const fn1 = new lambda.Function(stack1, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_12_X, - code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), - handler: 'index.handler', - environment: { - Foo: 'bar', - Bar: 'foo', - } - }); + 'impact of env variables order on hash': { - const stack2 = new Stack(); - const fn2 = new lambda.Function(stack2, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_12_X, - code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), - handler: 'index.handler', - environment: { - Bar: 'foo', - Foo: 'bar', - } - }); + 'without "currentVersion", we preserve old behavior to avoid unnesesary invalidation of templates'(test: Test) { + const stack1 = new Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Foo: 'bar', + Bar: 'foo', + } + }); - test.deepEqual(calculateFunctionHash(fn1), calculateFunctionHash(fn2)); - test.done(); - } + const stack2 = new Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Bar: 'foo', + Foo: 'bar', + } + }); + + test.notDeepEqual(calculateFunctionHash(fn1), calculateFunctionHash(fn2)); + test.done(); + }, + + 'with "currentVersion", we sort env keys so order is consistent'(test: Test) { + const stack1 = new Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Foo: 'bar', + Bar: 'foo', + } + }); + + new CfnOutput(stack1, 'VersionArn', { value: fn1.currentVersion.functionArn }); + + const stack2 = new Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + environment: { + Bar: 'foo', + Foo: 'bar', + } + }); + + new CfnOutput(stack2, 'VersionArn', { value: fn2.currentVersion.functionArn }); + + test.deepEqual(calculateFunctionHash(fn1), calculateFunctionHash(fn2)); + test.done(); + } + + }, }; From 3a06e76dfc1c1a43474c4ec9164f113a6ef26e50 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Wed, 25 Mar 2020 10:56:55 +0200 Subject: [PATCH 29/29] revert newline --- .../aws-lambda/test/integ.lambda.prov.concurrent.expected.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json index 10d70c1d95a17..ad788ff4425b6 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda.prov.concurrent.expected.json @@ -217,4 +217,4 @@ } } } -} +} \ No newline at end of file