From 4db987be6f5584ca93cbaf3456855ebb8dc615ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Fri, 14 Jun 2019 15:02:21 +0200 Subject: [PATCH] refactor(lambda): Standardize Lambda API `Alias`es and `Version`s are now `IFunctions`, and other fixes. BREAKING CHANGE: - Renamed `Function.addLayer` to `addLayers` and made it variadic - Removed `IFunction.handler` property - Removed `IVersion.versionArn` property (the value is at `functionArn`) - Removed `SingletonLayerVersion` - Stopped exporting `LogRetention` --- .../aws-cloudfront/lib/web_distribution.ts | 2 +- packages/@aws-cdk/aws-lambda/lib/alias.ts | 67 ++++++++++++++----- .../@aws-cdk/aws-lambda/lib/function-base.ts | 53 ++++++++++----- packages/@aws-cdk/aws-lambda/lib/function.ts | 54 +++++---------- packages/@aws-cdk/aws-lambda/lib/index.ts | 1 + .../@aws-cdk/aws-lambda/lib/lambda-version.ts | 61 +++++++++++------ packages/@aws-cdk/aws-lambda/lib/layers.ts | 53 +-------------- packages/@aws-cdk/aws-lambda/package.json | 2 +- .../@aws-cdk/aws-lambda/test/test.alias.ts | 2 +- .../@aws-cdk/aws-lambda/test/test.function.ts | 6 +- .../@aws-cdk/aws-lambda/test/test.lambda.ts | 2 +- .../@aws-cdk/aws-lambda/test/test.layers.ts | 20 +----- .../aws-lambda/test/test.log-retention.ts | 4 +- packages/@aws-cdk/aws-logs/package.json | 2 +- .../aws-sns-subscriptions/lib/lambda.ts | 2 +- 15 files changed, 157 insertions(+), 174 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index 23feb3e48658b..25eca3e0b9489 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -739,7 +739,7 @@ export class CloudFrontWebDistribution extends cdk.Construct implements IDistrib lambdaFunctionAssociations: input.lambdaFunctionAssociations .map(fna => ({ eventType: fna.eventType, - lambdaFunctionArn: fna.lambdaFunction && fna.lambdaFunction.versionArn, + lambdaFunctionArn: fna.lambdaFunction && fna.lambdaFunction.functionArn, })) }); } diff --git a/packages/@aws-cdk/aws-lambda/lib/alias.ts b/packages/@aws-cdk/aws-lambda/lib/alias.ts index b46c31dac4277..071b69efd1bf4 100644 --- a/packages/@aws-cdk/aws-lambda/lib/alias.ts +++ b/packages/@aws-cdk/aws-lambda/lib/alias.ts @@ -1,9 +1,23 @@ import cloudwatch = require('@aws-cdk/aws-cloudwatch'); import { Construct, Stack } from '@aws-cdk/cdk'; -import { FunctionBase, IFunction } from './function-base'; +import { IFunction, QualifiedFunctionBase } from './function-base'; import { IVersion } from './lambda-version'; import { CfnAlias } from './lambda.generated'; +export interface IAlias extends IFunction { + /** + * Name of this alias. + * + * @attribute + */ + readonly aliasName: string; + + /** + * The underlying Lambda function version. + */ + readonly version: IVersion; +} + /** * Properties for a new Lambda alias */ @@ -47,10 +61,30 @@ export interface AliasProps { readonly additionalVersions?: VersionWeight[]; } +export interface AliasAttributes { + readonly aliasName: string; + readonly aliasVersion: IVersion; +} + /** * A new alias to a particular version of a Lambda function. */ -export class Alias extends FunctionBase { +export class Alias extends QualifiedFunctionBase implements IAlias { + public static fromAliasAttributes(scope: Construct, id: string, attrs: AliasAttributes): IAlias { + class Imported extends QualifiedFunctionBase implements IAlias { + public readonly aliasName = attrs.aliasName; + public readonly version = attrs.aliasVersion; + public readonly lambda = attrs.aliasVersion.lambda; + public readonly functionArn = `${attrs.aliasVersion.lambda.functionArn}:${attrs.aliasName}`; + public readonly functionName = `${attrs.aliasVersion.lambda.functionName}:${attrs.aliasName}`; + public readonly grantPrincipal = attrs.aliasVersion.grantPrincipal; + public readonly role = attrs.aliasVersion.role; + + protected readonly canCreatePermissions = false; + } + return new Imported(scope, id); + } + /** * Name of this alias. * @@ -65,6 +99,10 @@ export class Alias extends FunctionBase { */ public readonly functionName: string; + public readonly lambda: IFunction; + + public readonly version: IVersion; + /** * ARN of this alias * @@ -75,21 +113,17 @@ export class Alias extends FunctionBase { protected readonly canCreatePermissions: boolean = true; - /** - * The actual Lambda function object that this Alias is pointing to - */ - private readonly underlyingLambda: IFunction; - constructor(scope: Construct, id: string, props: AliasProps) { super(scope, id); + this.lambda = props.version.lambda; this.aliasName = props.aliasName; - this.underlyingLambda = props.version.lambda; + this.version = props.version; const alias = new CfnAlias(this, 'Resource', { name: props.aliasName, description: props.description, - functionName: this.underlyingLambda.functionName, + functionName: this.version.lambda.functionName, functionVersion: props.version.version, routingConfig: this.determineRoutingConfig(props) }); @@ -101,26 +135,23 @@ export class Alias extends FunctionBase { this.functionArn = alias.aliasArn; } - /** - * Role associated with this alias - */ - public get role() { - return this.underlyingLambda.role; + public get grantPrincipal() { + return this.version.grantPrincipal; } - public get grantPrincipal() { - return this.underlyingLambda.grantPrincipal; + public get role() { + return this.version.role; } public metric(metricName: string, props: cloudwatch.MetricOptions = {}): cloudwatch.Metric { // Metrics on Aliases need the "bare" function name, and the alias' ARN, this differes from the base behavior. return super.metric(metricName, { dimensions: { - FunctionName: this.underlyingLambda.functionName, + FunctionName: this.lambda.functionName, // construct the ARN from the underlying lambda so that alarms on an alias // don't cause a circular dependency with CodeDeploy // see: https://github.com/awslabs/aws-cdk/issues/2231 - Resource: `${this.underlyingLambda.functionArn}:${this.aliasName}` + Resource: `${this.lambda.functionArn}:${this.aliasName}` }, ...props }); diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index a2979ae2ffcee..c79ed1e4f8ba0 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -10,11 +10,6 @@ import { Permission } from './permission'; export interface IFunction extends IResource, ec2.IConnectable, iam.IGrantable { - /** - * Logical ID of this Function. - */ - readonly id: string; - /** * The name of the function. * @@ -122,7 +117,7 @@ export interface FunctionAttributes { readonly securityGroupId?: string; } -export abstract class FunctionBase extends Resource implements IFunction { +export abstract class FunctionBase extends Resource implements IFunction { /** * The principal this Lambda Function is running as */ @@ -145,11 +140,6 @@ export abstract class FunctionBase extends Resource implements IFunction { */ public abstract readonly role?: iam.IRole; - /** - * The $LATEST version of this function. - */ - public readonly latestVersion: IVersion = new LatestVersion(this); - /** * Whether the addPermission() call adds any permissions * @@ -188,10 +178,6 @@ export abstract class FunctionBase extends Resource implements IFunction { }); } - public get id() { - return this.node.id; - } - public addToRolePolicy(statement: iam.PolicyStatement) { if (!this.role) { return; @@ -213,6 +199,11 @@ export abstract class FunctionBase extends Resource implements IFunction { return this._connections; } + public get latestVersion(): IVersion { + // Dynamic to avoid invinite recursion when creating the LatestVersion instance... + return new LatestVersion(this); + } + /** * Whether or not this Lambda function was bound to a VPC * @@ -289,15 +280,45 @@ export abstract class FunctionBase extends Resource implements IFunction { } } +export abstract class QualifiedFunctionBase extends FunctionBase { + public abstract readonly lambda: IFunction; + + public get latestVersion() { + return this.lambda.latestVersion; + } +} + /** * The $LATEST version of a function, useful when attempting to create aliases. */ -class LatestVersion extends Resource implements IVersion { +class LatestVersion extends FunctionBase implements IVersion { public readonly lambda: IFunction; public readonly version = '$LATEST'; + protected readonly canCreatePermissions = true; + constructor(lambda: FunctionBase) { super(lambda, '$LATEST'); this.lambda = lambda; } + + public get functionArn() { + return `${this.lambda.functionArn}:${this.version}`; + } + + public get functionName() { + return `${this.lambda.functionName}:${this.version}`; + } + + public get grantPrincipal() { + return this.lambda.grantPrincipal; + } + + public get latestVersion() { + return this; + } + + public get role() { + return this.lambda.role; + } } diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index d77d1a8f29238..321d8d4efa82b 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -257,8 +257,8 @@ export class Function extends FunctionBase { class Import extends FunctionBase { public readonly functionName = functionName; public readonly functionArn = functionArn; - public readonly role = role; public readonly grantPrincipal: iam.IPrincipal; + public readonly role = role; protected readonly canCreatePermissions = false; @@ -370,11 +370,6 @@ export class Function extends FunctionBase { */ public readonly runtime: Runtime; - /** - * The name of the handler configured for this lambda. - */ - public readonly handler: string; - /** * The principal this Lambda Function is running as */ @@ -442,14 +437,13 @@ export class Function extends FunctionBase { this.functionName = resource.refAsString; this.functionArn = resource.functionArn; - this.handler = props.handler; this.runtime = props.runtime; // allow code to bind to stack. props.code.bind(this); - for (const layer of props.layers || []) { - this.addLayer(layer); + if (props.layers) { + this.addLayers(...props.layers); } for (const event of props.events || []) { @@ -481,22 +475,23 @@ export class Function extends FunctionBase { } /** - * Adds a Lambda Layer to this Lambda function. + * Adds one or more Lambda Layers to this Lambda function. * - * @param layer the layer to be added. + * @param layers the layers to be added. * * @throws if there are already 5 layers on this function, or the layer is incompatible with this function's runtime. */ - public addLayer(layer: ILayerVersion): this { - if (this.layers.length === 5) { - throw new Error('Unable to add layer: this lambda function already uses 5 layers.'); - } - if (layer.compatibleRuntimes && !layer.compatibleRuntimes.find(runtime => runtime.runtimeEquals(this.runtime))) { - const runtimes = layer.compatibleRuntimes.map(runtime => runtime.name).join(', '); - throw new Error(`This lambda function uses a runtime that is incompatible with this layer (${this.runtime.name} is not in [${runtimes}])`); + public addLayers(...layers: ILayerVersion[]): void { + for (const layer of layers) { + if (this.layers.length === 5) { + throw new Error('Unable to add layer: this lambda function already uses 5 layers.'); + } + if (layer.compatibleRuntimes && !layer.compatibleRuntimes.find(runtime => runtime.runtimeEquals(this.runtime))) { + const runtimes = layer.compatibleRuntimes.map(runtime => runtime.name).join(', '); + throw new Error(`This lambda function uses a runtime that is incompatible with this layer (${this.runtime.name} is not in [${runtimes}])`); + } + this.layers.push(layer); } - this.layers.push(layer); - return this; } /** @@ -523,25 +518,6 @@ export class Function extends FunctionBase { }); } - /** - * Add a new version for this Lambda, always with a different name. - * - * This is similar to the {@link addVersion} method, - * but useful when deploying this Lambda through CodePipeline with blue/green deployments. - * When using {@link addVersion}, - * your Alias will not be updated until you change the name passed to {@link addVersion} in your CDK code. - * When deploying through a Pipeline, - * that might lead to a situation where a change to your Lambda application code will never be activated, - * even though it traveled through the entire Pipeline, - * because the Alias is still pointing to an old Version. - * This method creates a new, unique Version every time the CDK code is executed, - * and so prevents that from happening. - */ - public newVersion(): Version { - const now = new Date(); - return this.addVersion(now.toISOString()); - } - private renderEnvironment() { if (!this.environment || Object.keys(this.environment).length === 0) { return undefined; diff --git a/packages/@aws-cdk/aws-lambda/lib/index.ts b/packages/@aws-cdk/aws-lambda/lib/index.ts index 8def6e736af0e..7c3f5a48e8e87 100644 --- a/packages/@aws-cdk/aws-lambda/lib/index.ts +++ b/packages/@aws-cdk/aws-lambda/lib/index.ts @@ -9,6 +9,7 @@ export * from './lambda-version'; export * from './singleton-lambda'; export * from './event-source'; export * from './event-source-mapping'; + export * from './log-retention'; // AWS::Lambda CloudFormation Resources: diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index c0ee1a3c1cce1..73cf99db7c808 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -1,20 +1,15 @@ -import { Construct, IResource, Resource } from '@aws-cdk/cdk'; -import { IFunction } from './function-base'; +import cloudwatch = require('@aws-cdk/aws-cloudwatch'); +import { Construct } from '@aws-cdk/cdk'; +import { IFunction, QualifiedFunctionBase } from './function-base'; import { CfnVersion } from './lambda.generated'; -export interface IVersion extends IResource { +export interface IVersion extends IFunction { /** * The most recently deployed version of this function. * @attribute */ readonly version: string; - /** - * The ARN of this version. - * @attribute - */ - readonly versionArn?: string; - /** * The underlying AWS Lambda function. */ @@ -53,11 +48,6 @@ export interface VersionAttributes { */ readonly version: string; - /** - * The version arn. - */ - readonly versionArn?: string; - /** * The lambda function. */ @@ -80,23 +70,34 @@ export interface VersionAttributes { * the right deployment, specify the `codeSha256` property while * creating the `Version. */ -export class Version extends Resource implements IVersion { +export class Version extends QualifiedFunctionBase implements IVersion { public static fromVersionAttributes(scope: Construct, id: string, attrs: VersionAttributes): IVersion { - class Import extends Resource implements IVersion { + class Import extends QualifiedFunctionBase implements IVersion { public readonly version = attrs.version; public readonly lambda = attrs.lambda; + public readonly functionName = `${attrs.lambda.functionName}:${attrs.version}`; + public readonly functionArn = `${attrs.lambda.functionArn}:${attrs.version}`; + public readonly grantPrincipal = attrs.lambda.grantPrincipal; + public readonly role = attrs.lambda.role; + + protected readonly canCreatePermissions = false; } return new Import(scope, id); } public readonly version: string; - public readonly versionArn?: string; public readonly lambda: IFunction; + public readonly functionArn: string; + public readonly functionName: string; + + protected readonly canCreatePermissions = true; constructor(scope: Construct, id: string, props: VersionProps) { super(scope, id); + this.lambda = props.lambda; + const version = new CfnVersion(this, 'Resource', { codeSha256: props.codeSha256, description: props.description, @@ -104,7 +105,29 @@ export class Version extends Resource implements IVersion { }); this.version = version.version; - this.versionArn = version.versionArn; - this.lambda = props.lambda; + this.functionArn = version.versionArn; + this.functionName = `${this.lambda.functionName}:${this.version}`; + } + + public get grantPrincipal() { + return this.lambda.grantPrincipal; + } + + public get role() { + return this.lambda.role; + } + + public metric(metricName: string, props: cloudwatch.MetricOptions = {}): cloudwatch.Metric { + // Metrics on Aliases need the "bare" function name, and the alias' ARN, this differes from the base behavior. + return super.metric(metricName, { + dimensions: { + FunctionName: this.lambda.functionName, + // construct the ARN from the underlying lambda so that alarms on an alias + // don't cause a circular dependency with CodeDeploy + // see: https://github.com/awslabs/aws-cdk/issues/2231 + Resource: `${this.lambda.functionArn}:${this.version}` + }, + ...props + }); } } diff --git a/packages/@aws-cdk/aws-lambda/lib/layers.ts b/packages/@aws-cdk/aws-lambda/lib/layers.ts index 185f4e753c270..d166e78bff968 100644 --- a/packages/@aws-cdk/aws-lambda/lib/layers.ts +++ b/packages/@aws-cdk/aws-lambda/lib/layers.ts @@ -1,4 +1,4 @@ -import { Construct, IResource, Lazy, Resource, Stack } from '@aws-cdk/cdk'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { Code } from './code'; import { CfnLayerVersion, CfnLayerVersionPermission } from './lambda.generated'; import { Runtime } from './runtime'; @@ -181,54 +181,3 @@ export class LayerVersion extends LayerVersionBase { this.compatibleRuntimes = props.compatibleRuntimes; } } - -/** - * Properties of a Singleton Lambda Layer Version. - */ -export interface SingletonLayerVersionProps extends LayerVersionProps { - /** - * A unique identifier to identify this lambda layer version. - * - * The identifier should be unique across all layer providers. - * We recommend generating a UUID per provider. - */ - readonly uuid: string; -} - -/** - * A Singleton Lambda Layer Version. The construct gurantees exactly one LayerVersion will be created in a given Stack - * for the provided ``uuid``. It is recommended to use ``uuidgen`` to create a new ``uuid`` each time a new singleton - * layer is created. - * - * @resource AWS::Lambda::LayerVersion - */ -export class SingletonLayerVersion extends Resource implements ILayerVersion { - private readonly layerVersion: ILayerVersion; - - constructor(scope: Construct, id: string, props: SingletonLayerVersionProps) { - super(scope, id); - - this.layerVersion = this.ensureLayerVersion(props); - } - - public get layerVersionArn(): string { - return this.layerVersion.layerVersionArn; - } - - public get compatibleRuntimes(): Runtime[] | undefined { - return this.layerVersion.compatibleRuntimes; - } - - public addPermission(id: string, grantee: LayerVersionPermission) { - this.layerVersion.addPermission(id, grantee); - } - - private ensureLayerVersion(props: SingletonLayerVersionProps): ILayerVersion { - const singletonId = `SingletonLayer-${props.uuid}`; - const existing = Stack.of(this).node.tryFindChild(singletonId); - if (existing) { - return existing as unknown as ILayerVersion; - } - return new LayerVersion(Stack.of(this), singletonId, props); - } -} diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 0b7b5b51e4213..3f055fa4bbaa6 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -116,4 +116,4 @@ ] }, "stability": "experimental" -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-lambda/test/test.alias.ts b/packages/@aws-cdk/aws-lambda/test/test.alias.ts index c641ad1e6c970..14d53123702fb 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.alias.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.alias.ts @@ -71,7 +71,7 @@ export = { runtime: lambda.Runtime.Nodejs810, }); - const version = fn.newVersion(); + const version = fn.addVersion('NewVersion'); new lambda.Alias(stack, 'Alias', { aliasName: 'prod', diff --git a/packages/@aws-cdk/aws-lambda/test/test.function.ts b/packages/@aws-cdk/aws-lambda/test/test.function.ts index 00ddeb8b08c70..f1b142c4ef910 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.function.ts @@ -22,7 +22,7 @@ export = testCase({ }); // THEN - test.throws(() => func.addLayer(layer), + test.throws(() => func.addLayers(layer), /This lambda function uses a runtime that is incompatible with this layer/); test.done(); @@ -45,7 +45,7 @@ export = testCase({ // THEN // should not throw - func.addLayer(layer); + func.addLayers(layer); test.done(); }, @@ -69,7 +69,7 @@ export = testCase({ // THEN // should not throw - func.addLayer(layer); + func.addLayers(layer); test.done(); }, diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts index 69dfdfab82375..60951cd068cc0 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts @@ -1284,7 +1284,7 @@ export = { let bindCount = 0; class EventSource implements lambda.IEventSource { - public bind(_: lambda.FunctionBase): void { + public bind(_: lambda.IFunction): void { bindCount++; } } diff --git a/packages/@aws-cdk/aws-lambda/test/test.layers.ts b/packages/@aws-cdk/aws-lambda/test/test.layers.ts index 7384de250326c..ef27acff52839 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.layers.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.layers.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert'; import s3 = require('@aws-cdk/aws-s3'); import cdk = require('@aws-cdk/cdk'); import { Test, testCase } from 'nodeunit'; @@ -71,22 +71,4 @@ export = testCase({ test.done(); }, - - 'singleton layers are created exactly once'(test: Test) { - // Given - const stack = new cdk.Stack(undefined, 'TestStack'); - const uuid = '75F9D74A-67AF-493E-888A-20976130F0B1'; - const bucket = new s3.Bucket(stack, 'Bucket'); - const code = new lambda.S3Code(bucket, 'ObjectKey'); - - // When - for (let i = 0 ; i < 5 ; i++) { - new lambda.SingletonLayerVersion(stack, `Layer-${i}`, { uuid, code }); - } - - // Then - expect(stack).to(countResources('AWS::Lambda::LayerVersion', 1)); - - test.done(); - } }); diff --git a/packages/@aws-cdk/aws-lambda/test/test.log-retention.ts b/packages/@aws-cdk/aws-lambda/test/test.log-retention.ts index be223b42148d7..7cfacdbd3a638 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.log-retention.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.log-retention.ts @@ -2,7 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert'; import logs = require('@aws-cdk/aws-logs'); import cdk = require('@aws-cdk/cdk'); import { Test } from 'nodeunit'; -import lambda = require('../lib'); +import { LogRetention } from '../lib/log-retention'; // tslint:disable:object-literal-key-quotes @@ -12,7 +12,7 @@ export = { const stack = new cdk.Stack(); // WHEN - new lambda.LogRetention(stack, 'MyLambda', { + new LogRetention(stack, 'MyLambda', { logGroupName: 'group', retentionDays: logs.RetentionDays.OneMonth }); diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index 660e812aa68bc..f1db7cef9885e 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -89,4 +89,4 @@ ] }, "stability": "experimental" -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts b/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts index fd8d67c281247..114439087a581 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts @@ -21,7 +21,7 @@ export class LambdaSubscription implements sns.ITopicSubscription { // subscribing the same queue twice on the same topic. const subscriptionName = topic.node.id + 'Subscription'; if (this.fn.node.tryFindChild(subscriptionName)) { - throw new Error(`A subscription between the topic ${topic.node.id} and the lambda ${this.fn.id} already exists`); + throw new Error(`A subscription between the topic ${topic.node.id} and the lambda ${this.fn.node.id} already exists`); } new sns.Subscription(this.fn, subscriptionName, {